Fix T46915: Non-intuitive behavior of Vector Curve Mapping node

Vector mapping node was doing some weird mapping of both original and mapped
coordinates. Mapping of original coordinates was caused by the clamping nature
of the LUT generated from the node. Mapping of the mapped value again was quite
totally obscure -- one needed to constantly keep in mind that actual value will
be scaled up and moved down.

This commit makes it so values in the vector curve mapping are always absolute.
In fact, it is now behaving quite the same as RGB curve mapping node and the
code could be de-duplicated. Keeping the code duplicated for a bit so it's more
clear what exact parts of the node changed.

Reviewers: brecht

Subscribers: bassamk

Differential Revision: https://developer.blender.org/D1672
This commit is contained in:
Sergey Sharybin
2015-12-15 16:23:33 +05:00
parent 70fa2f69c9
commit c81e6ffdf9
8 changed files with 88 additions and 30 deletions

View File

@@ -100,6 +100,19 @@ def mapping_node_order_flip(node):
node.rotation = quat.to_euler('XYZ') node.rotation = quat.to_euler('XYZ')
def vector_curve_node_remap(node):
"""
Remap values of vector curve node from normalized to absolute values
"""
from mathutils import Vector
if node.bl_idname == 'ShaderNodeVectorCurve':
node.mapping.use_clip = False
for curve in node.mapping.curves:
for point in curve.points:
point.location.x = (point.location.x * 2.0) - 1.0
point.location.y = (point.location.y - 0.5) * 2.0
node.mapping.update()
@persistent @persistent
def do_versions(self): def do_versions(self):
# We don't modify startup file because it assumes to # We don't modify startup file because it assumes to
@@ -140,3 +153,6 @@ def do_versions(self):
# Euler order was ZYX in previous versions. # Euler order was ZYX in previous versions.
if bpy.data.version <= (2, 73, 4): if bpy.data.version <= (2, 73, 4):
foreach_cycles_node(mapping_node_order_flip) foreach_cycles_node(mapping_node_order_flip)
if bpy.data.version <= (2, 76, 5):
foreach_cycles_node(vector_curve_node_remap)

View File

@@ -231,8 +231,13 @@ static ShaderNode *add_node(Scene *scene,
} }
if(b_node.is_a(&RNA_ShaderNodeVectorCurve)) { if(b_node.is_a(&RNA_ShaderNodeVectorCurve)) {
BL::ShaderNodeVectorCurve b_curve_node(b_node); BL::ShaderNodeVectorCurve b_curve_node(b_node);
BL::CurveMapping mapping(b_curve_node.mapping());
VectorCurvesNode *curves = new VectorCurvesNode(); VectorCurvesNode *curves = new VectorCurvesNode();
curvemapping_color_to_array(b_curve_node.mapping(), curves->curves, RAMP_TABLE_SIZE, false); curvemapping_color_to_array(mapping,
curves->curves,
RAMP_TABLE_SIZE,
false);
curvemapping_minmax(mapping, false, &curves->min_x, &curves->max_x);
node = curves; node = curves;
} }
else if(b_node.is_a(&RNA_ShaderNodeValToRGB)) { else if(b_node.is_a(&RNA_ShaderNodeValToRGB)) {

View File

@@ -101,8 +101,7 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap,
bool rgb_curve) bool rgb_curve)
{ {
float min_x = 0.0f, max_x = 1.0f; float min_x = 0.0f, max_x = 1.0f;
/* TODO(sergey): Vector curve mapping is still clipping to 0..1. */
if(rgb_curve) {
/* TODO(sergey): There is no easy way to automatically guess what is /* TODO(sergey): There is no easy way to automatically guess what is
* the range to be used here for the case when mapping is applied on * the range to be used here for the case when mapping is applied on
* top of another mapping (i.e. R curve applied on top of common * top of another mapping (i.e. R curve applied on top of common
@@ -115,7 +114,7 @@ static inline void curvemapping_color_to_array(BL::CurveMapping cumap,
* There might be some better estimations here tho. * There might be some better estimations here tho.
*/ */
curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x); curvemapping_minmax(cumap, rgb_curve, &min_x, &max_x);
}
const float range_x = max_x - min_x; const float range_x = max_x - min_x;
cumap.update(); cumap.update();

View File

@@ -19,7 +19,22 @@
float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component) float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
{ {
float f = clamp((at + 1.0) * 0.5, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1); if (at < 0.0 || at > 1.0) {
float t0, dy;
if(at < 0.0) {
t0 = ramp[0][component];
dy = t0 - ramp[1][component];
at = -at;
}
else {
t0 = ramp[RAMP_TABLE_SIZE - 1][component];
dy = t0 - ramp[RAMP_TABLE_SIZE - 2][component];
at = at - 1.0;
}
return t0 + dy * at * (RAMP_TABLE_SIZE - 1);
}
float f = clamp(at, 0.0, 1.0) * (RAMP_TABLE_SIZE - 1);
/* clamp int as well in case of NaN */ /* clamp int as well in case of NaN */
int i = (int)f; int i = (int)f;
@@ -32,19 +47,23 @@ float ramp_lookup(color ramp[RAMP_TABLE_SIZE], float at, int component)
if (t > 0.0) if (t > 0.0)
result = (1.0 - t) * result + t * ramp[i + 1][component]; result = (1.0 - t) * result + t * ramp[i + 1][component];
return result * 2.0 - 1.0; return result;
} }
shader node_vector_curves( shader node_vector_curves(
color ramp[RAMP_TABLE_SIZE] = {0.0}, color ramp[RAMP_TABLE_SIZE] = {0.0},
float min_x = 0.0,
float max_x = 1.0,
vector VectorIn = vector(0.0, 0.0, 0.0), vector VectorIn = vector(0.0, 0.0, 0.0),
float Fac = 0.0, float Fac = 0.0,
output vector VectorOut = vector(0.0, 0.0, 0.0)) output vector VectorOut = vector(0.0, 0.0, 0.0))
{ {
VectorOut[0] = ramp_lookup(ramp, VectorIn[0], 0); color c = (VectorIn - vector(min_x, min_x, min_x)) / (max_x - min_x);
VectorOut[1] = ramp_lookup(ramp, VectorIn[1], 1);
VectorOut[2] = ramp_lookup(ramp, VectorIn[2], 2); VectorOut[0] = ramp_lookup(ramp, c[0], 0);
VectorOut[1] = ramp_lookup(ramp, c[1], 1);
VectorOut[2] = ramp_lookup(ramp, c[2], 2);
VectorOut = mix(VectorIn, VectorOut, Fac); VectorOut = mix(VectorIn, VectorOut, Fac);
} }

View File

@@ -101,18 +101,26 @@ ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *st
ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
{ {
uint fac_offset = node.y; uint fac_offset, color_offset, out_offset;
uint color_offset = node.z; decode_node_uchar4(node.y,
uint out_offset = node.w; &fac_offset,
&color_offset,
&out_offset,
NULL);
float fac = stack_load_float(stack, fac_offset); float fac = stack_load_float(stack, fac_offset);
float3 color = stack_load_float3(stack, color_offset); float3 color = stack_load_float3(stack, color_offset);
float r = rgb_ramp_lookup(kg, *offset, (color.x + 1.0f)*0.5f, true, false).x; const float min_x = __int_as_float(node.z),
float g = rgb_ramp_lookup(kg, *offset, (color.y + 1.0f)*0.5f, true, false).y; max_x = __int_as_float(node.w);
float b = rgb_ramp_lookup(kg, *offset, (color.z + 1.0f)*0.5f, true, false).z; const float range_x = max_x - min_x;
color = (color - make_float3(min_x, min_x, min_x)) / range_x;
color = (1.0f - fac)*color + fac*make_float3(r*2.0f - 1.0f, g*2.0f - 1.0f, b*2.0f - 1.0f); float r = rgb_ramp_lookup(kg, *offset, color.x, true, true).x;
float g = rgb_ramp_lookup(kg, *offset, color.y, true, true).y;
float b = rgb_ramp_lookup(kg, *offset, color.z, true, true).z;
color = (1.0f - fac)*color + fac*make_float3(r, g, b);
stack_store_float3(stack, out_offset, color); stack_store_float3(stack, out_offset, color);
*offset += RAMP_TABLE_SIZE; *offset += RAMP_TABLE_SIZE;

View File

@@ -4443,6 +4443,9 @@ VectorCurvesNode::VectorCurvesNode()
add_input("Fac", SHADER_SOCKET_FLOAT); add_input("Fac", SHADER_SOCKET_FLOAT);
add_input("Vector", SHADER_SOCKET_VECTOR); add_input("Vector", SHADER_SOCKET_VECTOR);
add_output("Vector", SHADER_SOCKET_VECTOR); add_output("Vector", SHADER_SOCKET_VECTOR);
min_x = 0.0f;
max_x = 1.0f;
} }
void VectorCurvesNode::compile(SVMCompiler& compiler) void VectorCurvesNode::compile(SVMCompiler& compiler)
@@ -4455,7 +4458,12 @@ void VectorCurvesNode::compile(SVMCompiler& compiler)
compiler.stack_assign(vector_in); compiler.stack_assign(vector_in);
compiler.stack_assign(vector_out); compiler.stack_assign(vector_out);
compiler.add_node(NODE_VECTOR_CURVES, fac_in->stack_offset, vector_in->stack_offset, vector_out->stack_offset); compiler.add_node(NODE_VECTOR_CURVES,
compiler.encode_uchar4(fac_in->stack_offset,
vector_in->stack_offset,
vector_out->stack_offset),
__float_as_int(min_x),
__float_as_int(max_x));
compiler.add_array(curves, RAMP_TABLE_SIZE); compiler.add_array(curves, RAMP_TABLE_SIZE);
} }
@@ -4470,6 +4478,8 @@ void VectorCurvesNode::compile(OSLCompiler& compiler)
} }
compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE); compiler.parameter_color_array("ramp", ramp, RAMP_TABLE_SIZE);
compiler.parameter("min_x", min_x);
compiler.parameter("max_x", max_x);
compiler.add(this, "node_vector_curves"); compiler.add(this, "node_vector_curves");
} }

View File

@@ -946,6 +946,7 @@ public:
virtual bool equals(const ShaderNode * /*other*/) { return false; } virtual bool equals(const ShaderNode * /*other*/) { return false; }
float4 curves[RAMP_TABLE_SIZE]; float4 curves[RAMP_TABLE_SIZE];
float min_x, max_x;
}; };
class RGBRampNode : public ShaderNode { class RGBRampNode : public ShaderNode {

View File

@@ -45,7 +45,7 @@ extern "C" {
#define BLENDER_SUBVERSION 5 #define BLENDER_SUBVERSION 5
/* Several breakages with 270, e.g. constraint deg vs rad */ /* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270 #define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5 #define BLENDER_MINSUBVERSION 6
/* used by packaging tools */ /* used by packaging tools */
/* can be left blank, otherwise a,b,c... etc with no quotes */ /* can be left blank, otherwise a,b,c... etc with no quotes */