Fix #33485: cycles OSL now autodetects the presence of emission and transparent
closures to enable multiple importance sampling and transparent shadows.
This commit is contained in:
@@ -183,6 +183,9 @@ public:
|
|||||||
virtual void compile(SVMCompiler& compiler) = 0;
|
virtual void compile(SVMCompiler& compiler) = 0;
|
||||||
virtual void compile(OSLCompiler& compiler) = 0;
|
virtual void compile(OSLCompiler& compiler) = 0;
|
||||||
|
|
||||||
|
virtual bool has_surface_emission() { return false; }
|
||||||
|
virtual bool has_surface_transparent() { return false; }
|
||||||
|
|
||||||
vector<ShaderInput*> inputs;
|
vector<ShaderInput*> inputs;
|
||||||
vector<ShaderOutput*> outputs;
|
vector<ShaderOutput*> outputs;
|
||||||
|
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
CCL_NAMESPACE_BEGIN
|
CCL_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class ImageManager;
|
class ImageManager;
|
||||||
class Shadr;
|
class Shader;
|
||||||
|
|
||||||
/* Texture Mapping */
|
/* Texture Mapping */
|
||||||
|
|
||||||
@@ -220,6 +220,8 @@ public:
|
|||||||
class TransparentBsdfNode : public BsdfNode {
|
class TransparentBsdfNode : public BsdfNode {
|
||||||
public:
|
public:
|
||||||
SHADER_NODE_CLASS(TransparentBsdfNode)
|
SHADER_NODE_CLASS(TransparentBsdfNode)
|
||||||
|
|
||||||
|
bool has_surface_transparent() { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VelvetBsdfNode : public BsdfNode {
|
class VelvetBsdfNode : public BsdfNode {
|
||||||
@@ -255,6 +257,8 @@ class EmissionNode : public ShaderNode {
|
|||||||
public:
|
public:
|
||||||
SHADER_NODE_CLASS(EmissionNode)
|
SHADER_NODE_CLASS(EmissionNode)
|
||||||
|
|
||||||
|
bool has_surface_emission() { return true; }
|
||||||
|
|
||||||
bool total_power;
|
bool total_power;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -76,12 +76,12 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
|
|||||||
|
|
||||||
if(progress.get_cancel()) return;
|
if(progress.get_cancel()) return;
|
||||||
|
|
||||||
if(shader->sample_as_light && shader->has_surface_emission)
|
|
||||||
scene->light_manager->need_update = true;
|
|
||||||
|
|
||||||
OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager);
|
OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager);
|
||||||
compiler.background = (shader == scene->shaders[scene->default_background]);
|
compiler.background = (shader == scene->shaders[scene->default_background]);
|
||||||
compiler.compile(og, shader);
|
compiler.compile(og, shader);
|
||||||
|
|
||||||
|
if(shader->sample_as_light && shader->has_surface_emission)
|
||||||
|
scene->light_manager->need_update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* setup shader engine */
|
/* setup shader engine */
|
||||||
@@ -202,8 +202,14 @@ static string shader_filepath_hash(const string& filepath, uint64_t modified_tim
|
|||||||
|
|
||||||
const char *OSLShaderManager::shader_test_loaded(const string& hash)
|
const char *OSLShaderManager::shader_test_loaded(const string& hash)
|
||||||
{
|
{
|
||||||
set<string>::iterator it = loaded_shaders.find(hash);
|
map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
|
||||||
return (it == loaded_shaders.end())? NULL: it->c_str();
|
return (it == loaded_shaders.end())? NULL: it->first.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string& hash)
|
||||||
|
{
|
||||||
|
map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
|
||||||
|
return (it == loaded_shaders.end())? NULL: &it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *OSLShaderManager::shader_load_filepath(string filepath)
|
const char *OSLShaderManager::shader_load_filepath(string filepath)
|
||||||
@@ -261,7 +267,8 @@ const char *OSLShaderManager::shader_load_filepath(string filepath)
|
|||||||
|
|
||||||
if(!path_read_text(filepath, bytecode)) {
|
if(!path_read_text(filepath, bytecode)) {
|
||||||
fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str());
|
fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str());
|
||||||
loaded_shaders.insert(bytecode_hash); /* to avoid repeat tries */
|
OSLShaderInfo info;
|
||||||
|
loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +313,13 @@ const char *OSLShaderManager::shader_load_bytecode(const string& hash, const str
|
|||||||
{
|
{
|
||||||
load_memory_shader(ss, hash.c_str(), bytecode.c_str());
|
load_memory_shader(ss, hash.c_str(), bytecode.c_str());
|
||||||
|
|
||||||
return loaded_shaders.insert(hash).first->c_str();
|
/* this is a bit weak, but works */
|
||||||
|
OSLShaderInfo info;
|
||||||
|
info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
|
||||||
|
info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
|
||||||
|
loaded_shaders[hash] = info;
|
||||||
|
|
||||||
|
return loaded_shaders.find(hash)->first.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Graph Compiler */
|
/* Graph Compiler */
|
||||||
@@ -477,6 +490,16 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
|
|||||||
ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str());
|
ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* test if we shader contains specific closures */
|
||||||
|
OSLShaderInfo *info = ((OSLShaderManager*)manager)->shader_loaded_info(name);
|
||||||
|
|
||||||
|
if(info) {
|
||||||
|
if(info->has_surface_emission)
|
||||||
|
current_shader->has_surface_emission = true;
|
||||||
|
if(info->has_surface_transparent)
|
||||||
|
current_shader->has_surface_transparent = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OSLCompiler::parameter(const char *name, float f)
|
void OSLCompiler::parameter(const char *name, float f)
|
||||||
@@ -632,9 +655,9 @@ void OSLCompiler::generate_nodes(const set<ShaderNode*>& nodes)
|
|||||||
node->compile(*this);
|
node->compile(*this);
|
||||||
done.insert(node);
|
done.insert(node);
|
||||||
|
|
||||||
if(node->name == ustring("emission"))
|
if(node->has_surface_emission())
|
||||||
current_shader->has_surface_emission = true;
|
current_shader->has_surface_emission = true;
|
||||||
if(node->name == ustring("transparent"))
|
if(node->has_surface_transparent())
|
||||||
current_shader->has_surface_transparent = true;
|
current_shader->has_surface_transparent = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -45,6 +45,18 @@ class ShaderOutput;
|
|||||||
|
|
||||||
#ifdef WITH_OSL
|
#ifdef WITH_OSL
|
||||||
|
|
||||||
|
/* OSL Shader Info
|
||||||
|
* to auto detect closures in the shader for MIS and transparent shadows */
|
||||||
|
|
||||||
|
struct OSLShaderInfo {
|
||||||
|
OSLShaderInfo()
|
||||||
|
: has_surface_emission(false), has_surface_transparent(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool has_surface_emission;
|
||||||
|
bool has_surface_transparent;
|
||||||
|
};
|
||||||
|
|
||||||
/* Shader Manage */
|
/* Shader Manage */
|
||||||
|
|
||||||
class OSLShaderManager : public ShaderManager {
|
class OSLShaderManager : public ShaderManager {
|
||||||
@@ -65,6 +77,7 @@ public:
|
|||||||
const char *shader_test_loaded(const string& hash);
|
const char *shader_test_loaded(const string& hash);
|
||||||
const char *shader_load_bytecode(const string& hash, const string& bytecode);
|
const char *shader_load_bytecode(const string& hash, const string& bytecode);
|
||||||
const char *shader_load_filepath(string filepath);
|
const char *shader_load_filepath(string filepath);
|
||||||
|
OSLShaderInfo *shader_loaded_info(const string& hash);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void texture_system_init();
|
void texture_system_init();
|
||||||
@@ -74,7 +87,7 @@ protected:
|
|||||||
OSL::TextureSystem *ts;
|
OSL::TextureSystem *ts;
|
||||||
OSLRenderServices *services;
|
OSLRenderServices *services;
|
||||||
OSL::ErrorHandler errhandler;
|
OSL::ErrorHandler errhandler;
|
||||||
set<string> loaded_shaders;
|
map<string, OSLShaderInfo> loaded_shaders;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -478,9 +478,9 @@ void SVMCompiler::generate_closure(ShaderNode *node, set<ShaderNode*>& done)
|
|||||||
stack_clear_users(node, done);
|
stack_clear_users(node, done);
|
||||||
stack_clear_temporary(node);
|
stack_clear_temporary(node);
|
||||||
|
|
||||||
if(node->name == ustring("emission"))
|
if(node->has_surface_emission())
|
||||||
current_shader->has_surface_emission = true;
|
current_shader->has_surface_emission = true;
|
||||||
if(node->name == ustring("transparent"))
|
if(node->has_surface_transparent())
|
||||||
current_shader->has_surface_transparent = true;
|
current_shader->has_surface_transparent = true;
|
||||||
|
|
||||||
/* end node is added outside of this */
|
/* end node is added outside of this */
|
||||||
@@ -538,9 +538,9 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set<ShaderNode*>& don
|
|||||||
|
|
||||||
mix_weight_offset = SVM_STACK_INVALID;
|
mix_weight_offset = SVM_STACK_INVALID;
|
||||||
|
|
||||||
if(node->name == ustring("emission"))
|
if(node->has_surface_emission())
|
||||||
current_shader->has_surface_emission = true;
|
current_shader->has_surface_emission = true;
|
||||||
if(node->name == ustring("transparent"))
|
if(node->has_surface_transparent())
|
||||||
current_shader->has_surface_transparent = true;
|
current_shader->has_surface_transparent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user