Cycles: Fix bump mapping to use object space when used with true displacement

Bump mapping was happening in world space while displacement happens in object
space, causing shading errors when displacement type was used with bump mapping.

To fix this the proper transforms are added to bump nodes. This is only done
for automatic bump mapping however, to avoid visual changes from other uses of
bump mapping. It would be nice to do this for all bump mapping to be consistent
but that will have to wait till we can break compatibility.

Reviewed By: brecht

Differential Revision: https://developer.blender.org/D2191
This commit is contained in:
Mai Lavelle 2016-09-02 00:41:04 -04:00 committed by Sergey Sharybin
parent b67db67b01
commit 2c1201502d
8 changed files with 57 additions and 21 deletions

View File

@ -21,6 +21,7 @@
surface node_bump(
int invert = 0,
int use_object_space = 0,
normal NormalIn = N,
float Strength = 0.1,
float Distance = 1.0,
@ -29,12 +30,20 @@ surface node_bump(
float SampleY = 0.0,
output normal NormalOut = N)
{
/* get surface tangents from normal */
vector dPdx = Dx(P);
vector dPdy = Dy(P);
point Ptmp = P;
normal Normal = NormalIn;
vector Rx = cross(dPdy, NormalIn);
vector Ry = cross(NormalIn, dPdx);
if (use_object_space) {
Ptmp = transform("object", Ptmp);
Normal = normalize(transform("object", Normal));
}
/* get surface tangents from normal */
vector dPdx = Dx(Ptmp);
vector dPdy = Dy(Ptmp);
vector Rx = cross(dPdy, Normal);
vector Ry = cross(Normal, dPdx);
/* compute surface gradient and determinant */
float det = dot(dPdx, Rx);
@ -49,7 +58,11 @@ surface node_bump(
dist *= -1.0;
/* compute and output perturbed normal */
NormalOut = normalize(absdet * NormalIn - dist * sign(det) * surfgrad);
NormalOut = normalize(strength * NormalOut + (1.0 - strength) * NormalIn);
NormalOut = normalize(absdet * Normal - dist * sign(det) * surfgrad);
NormalOut = normalize(strength * NormalOut + (1.0 - strength) * Normal);
if (use_object_space) {
NormalOut = normalize(transform("object", "world", NormalOut));
}
}

View File

@ -22,14 +22,23 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
{
#ifdef __RAY_DIFFERENTIALS__
/* get normal input */
uint normal_offset, distance_offset, invert;
decode_node_uchar4(node.y, &normal_offset, &distance_offset, &invert, NULL);
uint normal_offset, distance_offset, invert, use_object_space;
decode_node_uchar4(node.y, &normal_offset, &distance_offset, &invert, &use_object_space);
float3 normal_in = stack_valid(normal_offset)? stack_load_float3(stack, normal_offset): ccl_fetch(sd, N);
float3 dPdx = ccl_fetch(sd, dP).dx;
float3 dPdy = ccl_fetch(sd, dP).dy;
if(use_object_space) {
object_inverse_normal_transform(kg, sd, &normal_in);
object_inverse_dir_transform(kg, sd, &dPdx);
object_inverse_dir_transform(kg, sd, &dPdy);
}
/* get surface tangents from normal */
float3 Rx = cross(ccl_fetch(sd, dP).dy, normal_in);
float3 Ry = cross(normal_in, ccl_fetch(sd, dP).dx);
float3 Rx = cross(dPdy, normal_in);
float3 Ry = cross(normal_in, dPdx);
/* get bump values */
uint c_offset, x_offset, y_offset, strength_offset;
@ -40,7 +49,7 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
float h_y = stack_load_float(stack, y_offset);
/* compute surface gradient and determinant */
float det = dot(ccl_fetch(sd, dP).dx, Rx);
float det = dot(dPdx, Rx);
float3 surfgrad = (h_x - h_c)*Rx + (h_y - h_c)*Ry;
float absdet = fabsf(det);
@ -56,6 +65,11 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac
/* compute and output perturbed normal */
float3 normal_out = normalize(absdet*normal_in - distance*signf(det)*surfgrad);
normal_out = normalize(strength*normal_out + (1.0f - strength)*normal_in);
if(use_object_space) {
object_normal_transform(kg, sd, &normal_out);
}
stack_store_float3(stack, node.w, normal_out);
#endif
}

View File

@ -312,7 +312,8 @@ void ShaderGraph::relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to)
void ShaderGraph::finalize(Scene *scene,
bool do_bump,
bool do_osl,
bool do_simplify)
bool do_simplify,
bool bump_in_object_space)
{
/* before compiling, the shader graph may undergo a number of modifications.
* currently we set default geometry shader inputs, and create automatic bump
@ -325,7 +326,7 @@ void ShaderGraph::finalize(Scene *scene,
refine_bump_nodes();
if(do_bump)
bump_from_displacement();
bump_from_displacement(bump_in_object_space);
ShaderInput *surface_in = output()->input("Surface");
ShaderInput *volume_in = output()->input("Volume");
@ -793,7 +794,7 @@ void ShaderGraph::refine_bump_nodes()
}
}
void ShaderGraph::bump_from_displacement()
void ShaderGraph::bump_from_displacement(bool use_object_space)
{
/* generate bump mapping automatically from displacement. bump mapping is
* done using a 3-tap filter, computing the displacement at the center,
@ -842,7 +843,8 @@ void ShaderGraph::bump_from_displacement()
ShaderNode *set_normal = add(new SetNormalNode());
/* add bump node and connect copied graphs to it */
ShaderNode *bump = add(new BumpNode());
BumpNode *bump = (BumpNode*)add(new BumpNode());
bump->use_object_space = use_object_space;
ShaderOutput *out = displacement_in->link;
ShaderOutput *out_center = nodes_center[out->parent]->output(out->name());

View File

@ -258,7 +258,8 @@ public:
void finalize(Scene *scene,
bool do_bump = false,
bool do_osl = false,
bool do_simplify = false);
bool do_simplify = false,
bool bump_in_object_space = false);
int get_num_closures();
@ -272,7 +273,7 @@ protected:
void copy_nodes(ShaderNodeSet& nodes, ShaderNodeMap& nnodemap);
void break_cycles(ShaderNode *node, vector<bool>& visited, vector<bool>& on_stack);
void bump_from_displacement();
void bump_from_displacement(bool use_object_space);
void refine_bump_nodes();
void default_inputs(bool do_osl);
void transform_multi_closure(ShaderNode *node, ShaderOutput *weight_out, bool volume);

View File

@ -4762,6 +4762,7 @@ NODE_DEFINE(BumpNode)
NodeType* type = NodeType::add("bump", create, NodeType::SHADER);
SOCKET_BOOLEAN(invert, "Invert", false);
SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false);
/* this input is used by the user, but after graph transform it is no longer
* used and moved to sampler center/x/y instead */
@ -4800,7 +4801,8 @@ void BumpNode::compile(SVMCompiler& compiler)
compiler.encode_uchar4(
compiler.stack_assign_if_linked(normal_in),
compiler.stack_assign(distance_in),
invert),
invert,
use_object_space),
compiler.encode_uchar4(
compiler.stack_assign(center_in),
compiler.stack_assign(dx_in),
@ -4812,6 +4814,7 @@ void BumpNode::compile(SVMCompiler& compiler)
void BumpNode::compile(OSLCompiler& compiler)
{
compiler.parameter(this, "invert");
compiler.parameter(this, "use_object_space");
compiler.add(this, "node_bump");
}

View File

@ -874,6 +874,7 @@ public:
}
bool invert;
bool use_object_space;
float height;
float sample_center;
float sample_x;

View File

@ -1103,7 +1103,8 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
shader->graph_bump->finalize(scene,
true,
true,
shader->has_integrator_dependency);
shader->has_integrator_dependency,
shader->displacement_method == DISPLACE_BOTH);
}
current_shader = shader;

View File

@ -761,7 +761,8 @@ void SVMCompiler::compile(Scene *scene,
shader->graph_bump->finalize(scene,
true,
false,
shader->has_integrator_dependency);
shader->has_integrator_dependency,
shader->displacement_method == DISPLACE_BOTH);
}
current_shader = shader;