From 3759c10e5c832672920daf80b0f1018604cfb4b4 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 12 Dec 2012 06:51:06 +0000 Subject: [PATCH] Fix #33485: cycles OSL now autodetects the presence of emission and transparent closures to enable multiple importance sampling and transparent shadows. --- intern/cycles/render/graph.h | 3 +++ intern/cycles/render/nodes.h | 6 +++++- intern/cycles/render/osl.cpp | 41 ++++++++++++++++++++++++++++-------- intern/cycles/render/osl.h | 15 ++++++++++++- intern/cycles/render/svm.cpp | 8 +++---- 5 files changed, 58 insertions(+), 15 deletions(-) diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index b79167839ab..61b5bd83534 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -183,6 +183,9 @@ public: virtual void compile(SVMCompiler& compiler) = 0; virtual void compile(OSLCompiler& compiler) = 0; + virtual bool has_surface_emission() { return false; } + virtual bool has_surface_transparent() { return false; } + vector inputs; vector outputs; diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 5e357cff56c..8012a99ff05 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -26,7 +26,7 @@ CCL_NAMESPACE_BEGIN class ImageManager; -class Shadr; +class Shader; /* Texture Mapping */ @@ -220,6 +220,8 @@ public: class TransparentBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(TransparentBsdfNode) + + bool has_surface_transparent() { return true; } }; class VelvetBsdfNode : public BsdfNode { @@ -255,6 +257,8 @@ class EmissionNode : public ShaderNode { public: SHADER_NODE_CLASS(EmissionNode) + bool has_surface_emission() { return true; } + bool total_power; }; diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index b3b838be25b..28de56f3a72 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -76,12 +76,12 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene 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); compiler.background = (shader == scene->shaders[scene->default_background]); compiler.compile(og, shader); + + if(shader->sample_as_light && shader->has_surface_emission) + scene->light_manager->need_update = true; } /* 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) { - set::iterator it = loaded_shaders.find(hash); - return (it == loaded_shaders.end())? NULL: it->c_str(); + map::iterator it = loaded_shaders.find(hash); + return (it == loaded_shaders.end())? NULL: it->first.c_str(); +} + +OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string& hash) +{ + map::iterator it = loaded_shaders.find(hash); + return (it == loaded_shaders.end())? NULL: &it->second; } 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)) { 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; } @@ -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()); - 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 */ @@ -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()); } } + + /* 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) @@ -632,9 +655,9 @@ void OSLCompiler::generate_nodes(const set& nodes) node->compile(*this); done.insert(node); - if(node->name == ustring("emission")) + if(node->has_surface_emission()) current_shader->has_surface_emission = true; - if(node->name == ustring("transparent")) + if(node->has_surface_transparent()) current_shader->has_surface_transparent = true; } else diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index 9b58745bd46..3c599caa893 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -45,6 +45,18 @@ class ShaderOutput; #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 */ class OSLShaderManager : public ShaderManager { @@ -65,6 +77,7 @@ public: const char *shader_test_loaded(const string& hash); const char *shader_load_bytecode(const string& hash, const string& bytecode); const char *shader_load_filepath(string filepath); + OSLShaderInfo *shader_loaded_info(const string& hash); protected: void texture_system_init(); @@ -74,7 +87,7 @@ protected: OSL::TextureSystem *ts; OSLRenderServices *services; OSL::ErrorHandler errhandler; - set loaded_shaders; + map loaded_shaders; }; #endif diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 4acd174e60f..f7cb8f62247 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -478,9 +478,9 @@ void SVMCompiler::generate_closure(ShaderNode *node, set& done) stack_clear_users(node, done); stack_clear_temporary(node); - if(node->name == ustring("emission")) + if(node->has_surface_emission()) current_shader->has_surface_emission = true; - if(node->name == ustring("transparent")) + if(node->has_surface_transparent()) current_shader->has_surface_transparent = true; /* end node is added outside of this */ @@ -538,9 +538,9 @@ void SVMCompiler::generate_multi_closure(ShaderNode *node, set& don mix_weight_offset = SVM_STACK_INVALID; - if(node->name == ustring("emission")) + if(node->has_surface_emission()) current_shader->has_surface_emission = true; - if(node->name == ustring("transparent")) + if(node->has_surface_transparent()) current_shader->has_surface_transparent = true; }