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:
Brecht Van Lommel
2012-12-12 06:51:06 +00:00
parent cf723e5e7c
commit 3759c10e5c
5 changed files with 58 additions and 15 deletions

View File

@@ -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;

View File

@@ -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;
}; };

View File

@@ -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

View File

@@ -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

View File

@@ -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;
} }