diff options
author | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-10-10 19:56:43 +0400 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@pandora.be> | 2012-10-10 19:56:43 +0400 |
commit | fe09b24e86e340e733f91c8ed9fcc7b8519157f4 (patch) | |
tree | dfe21334e003d8e73ea993d5fcac54c19facd987 /intern/cycles/render | |
parent | e9a61cd29db61513dedeb4d656e7dadff7439b1a (diff) |
Cycles: per-BSDF normal input and new Bump node.
Each BSDF node now has a Normal input, which can be used to set a custom normal
for the BSDF, for example if you want to have only bump on one of the layers in
a multilayer material.
The Bump node can be used to generate a normal from a scalar value, the same as
what happens when you connect a scalar value to the displacement output.
Documentation has been updated with the latest changes:
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes
Patch by Agustin Benavidez, some implementation tweaks by me.
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/graph.cpp | 78 | ||||
-rw-r--r-- | intern/cycles/render/graph.h | 1 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 58 | ||||
-rw-r--r-- | intern/cycles/render/nodes.h | 5 |
4 files changed, 136 insertions, 6 deletions
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index c13102e9567..c1c976dc193 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -229,6 +229,8 @@ void ShaderGraph::finalize(bool do_bump, bool do_osl) if(!finalized) { clean(); default_inputs(do_osl); + refine_bump_nodes(); + if(do_bump) bump_from_displacement(); @@ -484,6 +486,61 @@ void ShaderGraph::default_inputs(bool do_osl) add(texco); } +void ShaderGraph::refine_bump_nodes() +{ + /* we transverse the node graph looking for bump nodes, when we find them, + * like in bump_from_displacement(), we copy the sub-graph defined from "bump" + * input to the inputs "center","dx" and "dy" What is in "bump" input is moved + * to "center" input. */ + + foreach(ShaderNode *node, nodes) { + if(node->name == ustring("bump") && node->input("Height")->link) { + ShaderInput *bump_input = node->input("Height"); + set<ShaderNode*> nodes_bump; + + /* make 2 extra copies of the subgraph defined in Bump input */ + map<ShaderNode*, ShaderNode*> nodes_dx; + map<ShaderNode*, ShaderNode*> nodes_dy; + + /* find dependencies for the given input */ + find_dependencies(nodes_bump, bump_input ); + + copy_nodes(nodes_bump, nodes_dx); + copy_nodes(nodes_bump, nodes_dy); + + /* mark nodes to indicate they are use for bump computation, so + that any texture coordinates are shifted by dx/dy when sampling */ + foreach(ShaderNode *node, nodes_bump) + node->bump = SHADER_BUMP_CENTER; + foreach(NodePair& pair, nodes_dx) + pair.second->bump = SHADER_BUMP_DX; + foreach(NodePair& pair, nodes_dy) + pair.second->bump = SHADER_BUMP_DY; + + ShaderOutput *out = bump_input->link; + ShaderOutput *out_dx = nodes_dx[out->parent]->output(out->name); + ShaderOutput *out_dy = nodes_dy[out->parent]->output(out->name); + + connect(out_dx, node->input("SampleX")); + connect(out_dy, node->input("SampleY")); + + /* add generated nodes */ + foreach(NodePair& pair, nodes_dx) + add(pair.second); + foreach(NodePair& pair, nodes_dy) + add(pair.second); + + /* connect what is conected is bump to samplecenter input*/ + connect(out , node->input("SampleCenter")); + + /* bump input is just for connectivity purpose for the graph input, + * we reconected this input to samplecenter, so lets disconnect it + * from bump input */ + disconnect(bump_input); + } + } +} + void ShaderGraph::bump_from_displacement() { /* generate bump mapping automatically from displacement. bump mapping is @@ -497,7 +554,7 @@ void ShaderGraph::bump_from_displacement() * different shifted coordinates. * * these 3 displacement values are then fed into the bump node, which will - * modify the normal. */ + * output the the perturbed normal. */ ShaderInput *displacement_in = output()->input("Displacement"); @@ -526,6 +583,12 @@ void ShaderGraph::bump_from_displacement() foreach(NodePair& pair, nodes_dy) pair.second->bump = SHADER_BUMP_DY; + /* add set normal node and connect the bump normal ouput to the set normal + * output, so it can finally set the shader normal, note we are only doing + * this for bump from displacement, this will be the only bump allowed to + * overwrite the shader normal */ + ShaderNode *set_normal = add(new SetNormalNode()); + /* add bump node and connect copied graphs to it */ ShaderNode *bump = add(new BumpNode()); @@ -537,6 +600,9 @@ void ShaderGraph::bump_from_displacement() connect(out_center, bump->input("SampleCenter")); connect(out_dx, bump->input("SampleX")); connect(out_dy, bump->input("SampleY")); + + /* connect the bump out to the set normal in: */ + connect(bump->output("Normal"), set_normal->input("Direction")); /* connect bump output to normal input nodes that aren't set yet. actually * this will only set the normal input to the geometry node that we created @@ -544,8 +610,14 @@ void ShaderGraph::bump_from_displacement() foreach(ShaderNode *node, nodes) foreach(ShaderInput *input, node->inputs) if(!input->link && input->default_value == ShaderInput::NORMAL) - connect(bump->output("Normal"), input); - + connect(set_normal->output("Normal"), input); + + /* for displacement bump, clear the normal input in case the above loop + * connected the setnormal out to the bump normalin */ + ShaderInput *bump_normal_in = bump->input("NormalIn"); + if(bump_normal_in) + bump_normal_in->link = NULL; + /* finally, add the copied nodes to the graph. we can't do this earlier * because we would create dependency cycles in the above loop */ foreach(NodePair& pair, nodes_center) diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index d485ed02150..acafe1d5278 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -235,6 +235,7 @@ protected: void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack); void clean(); void bump_from_displacement(); + void refine_bump_nodes(); void default_inputs(bool do_osl); }; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index da31a528310..b4ef93a4ff8 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1175,7 +1175,7 @@ BsdfNode::BsdfNode() closure = ccl::CLOSURE_BSDF_DIFFUSE_ID; add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); add_output("BSDF", SHADER_SOCKET_CLOSURE); } @@ -1183,6 +1183,7 @@ BsdfNode::BsdfNode() void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2) { ShaderInput *color_in = input("Color"); + ShaderInput *normal_in = input("Normal"); if(color_in->link) { compiler.stack_assign(color_in); @@ -1203,6 +1204,10 @@ void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput * compiler.closure_mix_weight_offset()), __float_as_int((param1)? param1->value.x: 0.0f), __float_as_int((param2)? param2->value.x: 0.0f)); + + if(normal_in->link) + compiler.stack_assign(normal_in); + compiler.add_node(NODE_CLOSURE_BSDF, normal_in->stack_offset); } void BsdfNode::compile(SVMCompiler& compiler) @@ -2215,7 +2220,7 @@ static ShaderEnum mix_type_init() enm.insert("Burn", NODE_MIX_BURN); enm.insert("Hue", NODE_MIX_HUE); enm.insert("Saturation", NODE_MIX_SAT); - enm.insert("Value", NODE_MIX_VAL ); + enm.insert("Value", NODE_MIX_VAL); enm.insert("Color", NODE_MIX_COLOR); enm.insert("Soft Light", NODE_MIX_SOFT); enm.insert("Linear Light", NODE_MIX_LINEAR); @@ -2586,6 +2591,7 @@ OutputNode::OutputNode() add_input("Surface", SHADER_SOCKET_CLOSURE); add_input("Volume", SHADER_SOCKET_CLOSURE); add_input("Displacement", SHADER_SOCKET_FLOAT); + add_input("Normal", SHADER_SOCKET_NORMAL); } void OutputNode::compile(SVMCompiler& compiler) @@ -2733,9 +2739,15 @@ void VectorMathNode::compile(OSLCompiler& compiler) BumpNode::BumpNode() : ShaderNode("bump") { + /* this input is used by the user, but after graph transform it is no longer + * used and moved to sampler center/x/y instead */ + add_input("Height", SHADER_SOCKET_NORMAL); + add_input("SampleCenter", SHADER_SOCKET_FLOAT); add_input("SampleX", SHADER_SOCKET_FLOAT); add_input("SampleY", SHADER_SOCKET_FLOAT); + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL); + add_input("Strength", SHADER_SOCKET_FLOAT, 0.1f); add_output("Normal", SHADER_SOCKET_NORMAL); } @@ -2745,12 +2757,25 @@ void BumpNode::compile(SVMCompiler& compiler) ShaderInput *center_in = input("SampleCenter"); ShaderInput *dx_in = input("SampleX"); ShaderInput *dy_in = input("SampleY"); + ShaderInput *normal_in = input("NormalIn"); + ShaderInput *intensity_in = input("Strength"); + ShaderOutput *normal_out = output("Normal"); compiler.stack_assign(center_in); compiler.stack_assign(dx_in); compiler.stack_assign(dy_in); + compiler.stack_assign(intensity_in); + compiler.stack_assign(normal_out); - compiler.add_node(NODE_SET_BUMP, center_in->stack_offset, dx_in->stack_offset, dy_in->stack_offset); + if(normal_in->link) + compiler.stack_assign(normal_in); + + /* pack all parameters in the node */ + compiler.add_node(NODE_SET_BUMP, + normal_in->stack_offset, + compiler.encode_uchar4(center_in->stack_offset, dx_in->stack_offset, + dy_in->stack_offset, intensity_in->stack_offset), + normal_out->stack_offset); } void BumpNode::compile(OSLCompiler& compiler) @@ -2819,17 +2844,44 @@ void RGBRampNode::compile(OSLCompiler& compiler) /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */ float ramp_color[RAMP_TABLE_SIZE][3]; float ramp_alpha[RAMP_TABLE_SIZE]; + for (int i = 0; i < RAMP_TABLE_SIZE; ++i) { ramp_color[i][0] = ramp[i].x; ramp_color[i][1] = ramp[i].y; ramp_color[i][2] = ramp[i].z; ramp_alpha[i] = ramp[i].w; } + compiler.parameter_color_array("ramp_color", ramp_color, RAMP_TABLE_SIZE); compiler.parameter_array("ramp_alpha", ramp_alpha, RAMP_TABLE_SIZE); compiler.add(this, "node_rgb_ramp"); } +/* Set Normal Node */ + +SetNormalNode::SetNormalNode() +: ShaderNode("set_normal") +{ + add_input("Direction", SHADER_SOCKET_VECTOR); + add_output("Normal", SHADER_SOCKET_NORMAL); +} + +void SetNormalNode::compile(SVMCompiler& compiler) +{ + ShaderInput *direction_in = input("Direction"); + ShaderOutput *normal_out = output("Normal"); + + compiler.stack_assign(direction_in); + compiler.stack_assign(normal_out); + + compiler.add_node(NODE_CLOSURE_SET_NORMAL, direction_in->stack_offset, normal_out->stack_offset); +} + +void SetNormalNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "set_normal"); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 6e5d7be0091..fbc61e12fd4 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -440,6 +440,11 @@ public: float4 ramp[RAMP_TABLE_SIZE]; }; +class SetNormalNode : public ShaderNode { +public: + SHADER_NODE_CLASS(SetNormalNode) +}; + CCL_NAMESPACE_END #endif /* __NODES_H__ */ |