Shader Nodes: Add Interpolation modes to Map Range node

Modes: Linear interpolation (default), stepped linear, smoothstep and smootherstep.

This also includes an additional option for the **Clamp node** to switch between **Min Max** (default) and **Range** mode.

This was needed to allow clamping when **To Max** is less than **To Min**.

Reviewed By: JacquesLucke, brecht

Differential Revision: https://developer.blender.org/D5827
This commit is contained in:
Charlie Jolly 2019-12-07 12:35:07 +00:00 committed by Charlie Jolly
parent 0406eb1103
commit 958d0d4236
20 changed files with 320 additions and 44 deletions

View File

@ -301,10 +301,14 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeMapRange b_map_range_node(b_node);
MapRangeNode *map_range_node = new MapRangeNode();
map_range_node->clamp = b_map_range_node.clamp();
map_range_node->type = (NodeMapRangeType)b_map_range_node.interpolation_type();
node = map_range_node;
}
else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
node = new ClampNode();
BL::ShaderNodeClamp b_clamp_node(b_node);
ClampNode *clamp_node = new ClampNode();
clamp_node->type = (NodeClampType)b_clamp_node.clamp_type();
node = clamp_node;
}
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);

View File

@ -16,7 +16,11 @@
#include "stdosl.h"
shader node_clamp(float Value = 1.0, float Min = 0.0, float Max = 1.0, output float Result = 0.0)
shader node_clamp(string type = "minmax",
float Value = 1.0,
float Min = 0.0,
float Max = 1.0,
output float Result = 0.0)
{
Result = clamp(Value, Min, Max);
Result = (type == "range" && (Min > Max)) ? clamp(Value, Max, Min) : clamp(Value, Min, Max);
}

View File

@ -16,14 +16,43 @@
#include "stdosl.h"
shader node_map_range(float Value = 1.0,
float safe_divide(float a, float b)
{
return (b != 0.0) ? a / b : 0.0;
}
float smootherstep(float edge0, float edge1, float x)
{
float t = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
shader node_map_range(string type = "linear",
float Value = 1.0,
float FromMin = 0.0,
float FromMax = 1.0,
float ToMin = 0.0,
float ToMax = 1.0,
float Steps = 4.0,
output float Result = 0.0)
{
if (FromMax != FromMin) {
Result = ToMin + ((Value - FromMin) / (FromMax - FromMin)) * (ToMax - ToMin);
float Factor = Value;
if (type == "stepped") {
Factor = (Value - FromMin) / (FromMax - FromMin);
Factor = (Steps > 0) ? floor(Factor * (Steps + 1.0)) / Steps : 0.0;
}
else if (type == "smoothstep") {
Factor = (FromMin > FromMax) ? 1.0 - smoothstep(FromMax, FromMin, Value) :
smoothstep(FromMin, FromMax, Value);
}
else if (type == "smootherstep") {
Factor = (FromMin > FromMax) ? 1.0 - smootherstep(FromMax, FromMin, Value) :
smootherstep(FromMin, FromMax, Value);
}
else {
Factor = (Value - FromMin) / (FromMax - FromMin);
}
Result = ToMin + Factor * (ToMax - ToMin);
}
}

View File

@ -26,8 +26,8 @@ ccl_device void svm_node_clamp(KernelGlobals *kg,
uint result_stack_offset,
int *offset)
{
uint min_stack_offset, max_stack_offset;
svm_unpack_node_uchar2(parameters_stack_offsets, &min_stack_offset, &max_stack_offset);
uint min_stack_offset, max_stack_offset, type;
svm_unpack_node_uchar3(parameters_stack_offsets, &min_stack_offset, &max_stack_offset, &type);
uint4 defaults = read_node(kg, offset);
@ -35,7 +35,12 @@ ccl_device void svm_node_clamp(KernelGlobals *kg,
float min = stack_load_float_default(stack, min_stack_offset, defaults.x);
float max = stack_load_float_default(stack, max_stack_offset, defaults.y);
stack_store_float(stack, result_stack_offset, clamp(value, min, max));
if (type == NODE_CLAMP_RANGE && (min > max)) {
stack_store_float(stack, result_stack_offset, clamp(value, max, min));
}
else {
stack_store_float(stack, result_stack_offset, clamp(value, min, max));
}
}
CCL_NAMESPACE_END

View File

@ -18,32 +18,66 @@ CCL_NAMESPACE_BEGIN
/* Map Range Node */
ccl_device_inline float smootherstep(float edge0, float edge1, float x)
{
x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0f, 1.0f);
return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f);
}
ccl_device void svm_node_map_range(KernelGlobals *kg,
ShaderData *sd,
float *stack,
uint value_stack_offset,
uint parameters_stack_offsets,
uint result_stack_offset,
uint results_stack_offsets,
int *offset)
{
uint from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset;
uint type_stack_offset, steps_stack_offset, result_stack_offset;
svm_unpack_node_uchar4(parameters_stack_offsets,
&from_min_stack_offset,
&from_max_stack_offset,
&to_min_stack_offset,
&to_max_stack_offset);
svm_unpack_node_uchar3(
results_stack_offsets, &type_stack_offset, &steps_stack_offset, &result_stack_offset);
uint4 defaults = read_node(kg, offset);
uint4 defaults2 = read_node(kg, offset);
float value = stack_load_float(stack, value_stack_offset);
float from_min = stack_load_float_default(stack, from_min_stack_offset, defaults.x);
float from_max = stack_load_float_default(stack, from_max_stack_offset, defaults.y);
float to_min = stack_load_float_default(stack, to_min_stack_offset, defaults.z);
float to_max = stack_load_float_default(stack, to_max_stack_offset, defaults.w);
float steps = stack_load_float_default(stack, steps_stack_offset, defaults2.x);
float result;
if (from_max != from_min) {
result = to_min + ((value - from_min) / (from_max - from_min)) * (to_max - to_min);
float factor = value;
switch (type_stack_offset) {
default:
case NODE_MAP_RANGE_LINEAR:
factor = (value - from_min) / (from_max - from_min);
break;
case NODE_MAP_RANGE_STEPPED: {
factor = (value - from_min) / (from_max - from_min);
factor = (steps > 0.0f) ? floorf(factor * (steps + 1.0f)) / steps : 0.0f;
break;
}
case NODE_MAP_RANGE_SMOOTHSTEP: {
factor = (from_min > from_max) ? 1.0f - smoothstep(from_max, from_min, factor) :
smoothstep(from_min, from_max, factor);
break;
}
case NODE_MAP_RANGE_SMOOTHERSTEP: {
factor = (from_min > from_max) ? 1.0f - smootherstep(from_max, from_min, factor) :
smootherstep(from_min, from_max, factor);
break;
}
}
result = to_min + factor * (to_max - to_min);
}
else {
result = 0.0f;

View File

@ -325,6 +325,18 @@ typedef enum NodeVectorMathType {
NODE_VECTOR_MATH_MAXIMUM,
} NodeVectorMathType;
typedef enum NodeClampType {
NODE_CLAMP_MINMAX,
NODE_CLAMP_RANGE,
} NodeClampType;
typedef enum NodeMapRangeType {
NODE_MAP_RANGE_LINEAR,
NODE_MAP_RANGE_STEPPED,
NODE_MAP_RANGE_SMOOTHSTEP,
NODE_MAP_RANGE_SMOOTHERSTEP,
} NodeMapRangeType;
typedef enum NodeMappingType {
NODE_MAPPING_TYPE_POINT,
NODE_MAPPING_TYPE_TEXTURE,

View File

@ -5561,11 +5561,19 @@ NODE_DEFINE(MapRangeNode)
{
NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
static NodeEnum type_enum;
type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
SOCKET_ENUM(type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
SOCKET_IN_FLOAT(value, "Value", 1.0f);
SOCKET_IN_FLOAT(from_min, "From Min", 0.0f);
SOCKET_IN_FLOAT(from_max, "From Max", 1.0f);
SOCKET_IN_FLOAT(to_min, "To Min", 0.0f);
SOCKET_IN_FLOAT(to_max, "To Max", 1.0f);
SOCKET_IN_FLOAT(steps, "Steps", 4.0f);
SOCKET_OUT_FLOAT(result, "Result");
@ -5582,6 +5590,7 @@ void MapRangeNode::expand(ShaderGraph *graph)
ShaderOutput *result_out = output("Result");
if (!result_out->links.empty()) {
ClampNode *clamp_node = new ClampNode();
clamp_node->type = NODE_CLAMP_RANGE;
graph->add(clamp_node);
graph->relink(result_out, clamp_node->output("Result"));
graph->connect(result_out, clamp_node->input("Value"));
@ -5601,20 +5610,6 @@ void MapRangeNode::expand(ShaderGraph *graph)
}
}
void MapRangeNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
float result;
if (from_max != from_min) {
result = to_min + ((value - from_min) / (from_max - from_min)) * (to_max - to_min);
}
else {
result = 0.0f;
}
folder.make_constant(result);
}
}
void MapRangeNode::compile(SVMCompiler &compiler)
{
ShaderInput *value_in = input("Value");
@ -5622,6 +5617,7 @@ void MapRangeNode::compile(SVMCompiler &compiler)
ShaderInput *from_max_in = input("From Max");
ShaderInput *to_min_in = input("To Min");
ShaderInput *to_max_in = input("To Max");
ShaderInput *steps_in = input("Steps");
ShaderOutput *result_out = output("Result");
int value_stack_offset = compiler.stack_assign(value_in);
@ -5629,6 +5625,7 @@ void MapRangeNode::compile(SVMCompiler &compiler)
int from_max_stack_offset = compiler.stack_assign_if_linked(from_max_in);
int to_min_stack_offset = compiler.stack_assign_if_linked(to_min_in);
int to_max_stack_offset = compiler.stack_assign_if_linked(to_max_in);
int steps_stack_offset = compiler.stack_assign(steps_in);
int result_stack_offset = compiler.stack_assign(result_out);
compiler.add_node(
@ -5636,16 +5633,18 @@ void MapRangeNode::compile(SVMCompiler &compiler)
value_stack_offset,
compiler.encode_uchar4(
from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
result_stack_offset);
compiler.encode_uchar4(type, steps_stack_offset, result_stack_offset));
compiler.add_node(__float_as_int(from_min),
__float_as_int(from_max),
__float_as_int(to_min),
__float_as_int(to_max));
compiler.add_node(__float_as_int(steps));
}
void MapRangeNode::compile(OSLCompiler &compiler)
{
compiler.parameter(this, "type");
compiler.add(this, "node_map_range");
}
@ -5655,6 +5654,11 @@ NODE_DEFINE(ClampNode)
{
NodeType *type = NodeType::add("clamp", create, NodeType::SHADER);
static NodeEnum type_enum;
type_enum.insert("minmax", NODE_CLAMP_MINMAX);
type_enum.insert("range", NODE_CLAMP_RANGE);
SOCKET_ENUM(type, "Type", type_enum, NODE_CLAMP_MINMAX);
SOCKET_IN_FLOAT(value, "Value", 1.0f);
SOCKET_IN_FLOAT(min, "Min", 0.0f);
SOCKET_IN_FLOAT(max, "Max", 1.0f);
@ -5671,7 +5675,12 @@ ClampNode::ClampNode() : ShaderNode(node_type)
void ClampNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
folder.make_constant(clamp(value, min, max));
if (type == NODE_CLAMP_RANGE && (min > max)) {
folder.make_constant(clamp(value, max, min));
}
else {
folder.make_constant(clamp(value, min, max));
}
}
}
@ -5689,13 +5698,14 @@ void ClampNode::compile(SVMCompiler &compiler)
compiler.add_node(NODE_CLAMP,
value_stack_offset,
compiler.encode_uchar4(min_stack_offset, max_stack_offset),
compiler.encode_uchar4(min_stack_offset, max_stack_offset, type),
result_stack_offset);
compiler.add_node(__float_as_int(min), __float_as_int(max));
}
void ClampNode::compile(OSLCompiler &compiler)
{
compiler.parameter(this, "type");
compiler.add(this, "node_clamp");
}
@ -5769,6 +5779,7 @@ void MathNode::expand(ShaderGraph *graph)
ShaderOutput *result_out = output("Value");
if (!result_out->links.empty()) {
ClampNode *clamp_node = new ClampNode();
clamp_node->type = NODE_CLAMP_MINMAX;
clamp_node->min = 0.0f;
clamp_node->max = 1.0f;
graph->add(clamp_node);

View File

@ -1290,14 +1290,14 @@ class BlackbodyNode : public ShaderNode {
class MapRangeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MapRangeNode)
void constant_fold(const ConstantFolder &folder);
virtual int get_group()
{
return NODE_GROUP_LEVEL_3;
}
void expand(ShaderGraph *graph);
float value, from_min, from_max, to_min, to_max;
float value, from_min, from_max, to_min, to_max, steps;
NodeMapRangeType type;
bool clamp;
};
@ -1310,6 +1310,7 @@ class ClampNode : public ShaderNode {
return NODE_GROUP_LEVEL_3;
}
float value, min, max;
NodeClampType type;
};
class MathNode : public ShaderNode {

@ -1 +1 @@
Subproject commit 2f425cc128b8b709cc1ebf2c96ad372778f4aeda
Subproject commit 1470f353c65034db91131d21ab9c782d029a2ee9

@ -1 +1 @@
Subproject commit b52e7760ff6ccbcca73d2bbccc77f70ca2eaf98f
Subproject commit ffbaca558a27bab4716bcd51ca7ea1df8e4f4b14

View File

@ -250,9 +250,19 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
}
}
static void node_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
uiItemR(layout, ptr, "clamp_type", 0, "", ICON_NONE);
}
static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE);
if (!ELEM(RNA_enum_get(ptr, "interpolation_type"),
NODE_MAP_RANGE_SMOOTHSTEP,
NODE_MAP_RANGE_SMOOTHERSTEP)) {
uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE);
}
}
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@ -1172,8 +1182,11 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_VALTORGB:
ntype->draw_buttons = node_buts_colorramp;
break;
case SH_NODE_CLAMP:
ntype->draw_buttons = node_shader_buts_clamp;
break;
case SH_NODE_MAP_RANGE:
ntype->draw_buttons = node_buts_map_range;
ntype->draw_buttons = node_shader_buts_map_range;
break;
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;

View File

@ -316,7 +316,7 @@ static GPUMaterialLibrary gpu_shader_material_mapping_library = {
static GPUMaterialLibrary gpu_shader_material_map_range_library = {
.code = datatoc_gpu_shader_material_map_range_glsl,
.dependencies = {NULL},
.dependencies = {&gpu_shader_material_math_util_library, NULL},
};
static GPUMaterialLibrary gpu_shader_material_math_library = {

View File

@ -2,3 +2,8 @@ void clamp_value(float value, float min, float max, out float result)
{
result = clamp(value, min, max);
}
void clamp_range(float value, float min, float max, out float result)
{
result = (max > min) ? clamp(value, min, max) : clamp(value, max, min);
}

View File

@ -1,5 +1,16 @@
void map_range(
float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
float smootherstep(float edge0, float edge1, float x)
{
x = clamp(safe_divide((x - edge0), (edge1 - edge0)), 0.0, 1.0);
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
}
void map_range_linear(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
out float result)
{
if (fromMax != fromMin) {
result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
@ -8,3 +19,57 @@ void map_range(
result = 0.0;
}
}
void map_range_stepped(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
out float result)
{
if (fromMax != fromMin) {
float factor = (value - fromMin) / (fromMax - fromMin);
factor = (steps > 0.0) ? floor(factor * (steps + 1.0)) / steps : 0.0;
result = toMin + factor * (toMax - toMin);
}
else {
result = 0.0;
}
}
void map_range_smoothstep(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
out float result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smoothstep(fromMax, fromMin, value) :
smoothstep(fromMin, fromMax, value);
result = toMin + factor * (toMax - toMin);
}
else {
result = 0.0;
}
}
void map_range_smootherstep(float value,
float fromMin,
float fromMax,
float toMin,
float toMax,
float steps,
out float result)
{
if (fromMax != fromMin) {
float factor = (fromMin > fromMax) ? 1.0 - smootherstep(fromMax, fromMin, value) :
smootherstep(fromMin, fromMax, value);
result = toMin + factor * (toMax - toMin);
}
else {
result = 0.0;
}
}

View File

@ -1260,6 +1260,20 @@ enum {
NODE_VECTOR_MATH_MAXIMUM = 19,
};
/* Clamp node types. */
enum {
NODE_CLAMP_MINMAX = 0,
NODE_CLAMP_RANGE = 1,
};
/* Map range node types. */
enum {
NODE_MAP_RANGE_LINEAR = 0,
NODE_MAP_RANGE_STEPPED = 1,
NODE_MAP_RANGE_SMOOTHSTEP = 2,
NODE_MAP_RANGE_SMOOTHERSTEP = 3,
};
/* mix rgb node flags */
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2

View File

@ -188,6 +188,8 @@ extern const EnumPropertyItem rna_enum_node_math_items[];
extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
extern const EnumPropertyItem rna_enum_node_map_range_items[];
extern const EnumPropertyItem rna_enum_node_clamp_items[];
extern const EnumPropertyItem rna_enum_ramp_blend_items[];

View File

@ -226,6 +226,36 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = {
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_map_range_items[] = {
{NODE_MAP_RANGE_LINEAR,
"LINEAR",
0,
"Linear",
"Linear interpolation between From Min and From Max values"},
{NODE_MAP_RANGE_STEPPED,
"STEPPED",
0,
"Stepped Linear",
"Stepped linear interpolation between From Min and From Max values"},
{NODE_MAP_RANGE_SMOOTHSTEP,
"SMOOTHSTEP",
0,
"Smoothstep",
"Smooth hermite edge interpolation between From Min and From Max values"},
{NODE_MAP_RANGE_SMOOTHERSTEP,
"SMOOTHERSTEP",
0,
"Smootherstep",
"Smoother hermite edge interpolation between From Min and From Max values"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_clamp_items[] = {
{NODE_CLAMP_MINMAX, "MINMAX", 0, "Min Max", "Clamp values using Min and Max values"},
{NODE_CLAMP_RANGE, "RANGE", 0, "Range", "Clamp values between Min and Max range"},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem rna_enum_node_tex_dimensions_items[] = {
{1, "1D", 0, "1D", "Use the scalar value W as input"},
{2, "2D", 0, "2D", "Use the 2D vector (x, y) as input. The z component is ignored"},
@ -3921,6 +3951,17 @@ static void def_frame(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL);
}
static void def_clamp(StructRNA *srna)
{
PropertyRNA *prop;
prop = RNA_def_property(srna, "clamp_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_clamp_items);
RNA_def_property_ui_text(prop, "Clamp Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_map_range(StructRNA *srna)
{
PropertyRNA *prop;
@ -3929,6 +3970,12 @@ static void def_map_range(StructRNA *srna)
RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
RNA_def_property_ui_text(prop, "Clamp", "Clamp the result to the target range [To Min, To Max]");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "interpolation_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, rna_enum_node_map_range_items);
RNA_def_property_ui_text(prop, "Interpolation Type", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_math(StructRNA *srna)

View File

@ -51,7 +51,7 @@ DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_
DefNode(ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "" )
DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "" )
DefNode(ShaderNode, SH_NODE_MAP_RANGE, def_map_range, "MAP_RANGE", MapRange, "Map Range", "" )
DefNode(ShaderNode, SH_NODE_CLAMP, 0, "CLAMP", Clamp, "Clamp", "" )
DefNode(ShaderNode, SH_NODE_CLAMP, def_clamp, "CLAMP", Clamp, "Clamp", "" )
DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )

View File

@ -35,13 +35,19 @@ static bNodeSocketTemplate sh_node_clamp_out[] = {
{-1, 0, ""},
};
static void node_shader_init_clamp(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = NODE_CLAMP_MINMAX; /* clamp type */
}
static int gpu_shader_clamp(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
return GPU_stack_link(mat, node, "clamp_value", in, out);
return (node->custom1 == NODE_CLAMP_MINMAX) ? GPU_stack_link(mat, node, "clamp_value", in, out) :
GPU_stack_link(mat, node, "clamp_range", in, out);
}
void register_node_type_sh_clamp(void)
@ -50,6 +56,7 @@ void register_node_type_sh_clamp(void)
sh_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
node_type_init(&ntype, node_shader_init_clamp);
node_type_gpu(&ntype, gpu_shader_clamp);
nodeRegisterType(&ntype);

View File

@ -30,6 +30,7 @@ static bNodeSocketTemplate sh_node_map_range_in[] = {
{SOCK_FLOAT, 1, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("Steps"), 4.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_map_range_out[] = {
@ -37,9 +38,16 @@ static bNodeSocketTemplate sh_node_map_range_out[] = {
{-1, 0, ""},
};
static void node_shader_update_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps");
nodeSetSocketAvailability(sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED);
}
static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1 = true;
node->custom1 = true; /* use_clamp */
node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */
}
static int gpu_shader_map_range(GPUMaterial *mat,
@ -48,11 +56,25 @@ static int gpu_shader_map_range(GPUMaterial *mat,
GPUNodeStack *in,
GPUNodeStack *out)
{
GPU_stack_link(mat, node, "map_range", in, out);
if (node->custom1) {
GPU_link(mat, "clamp_value", out[0].link, in[3].link, in[4].link, &out[0].link);
static const char *names[] = {
[NODE_MAP_RANGE_LINEAR] = "map_range_linear",
[NODE_MAP_RANGE_STEPPED] = "map_range_stepped",
[NODE_MAP_RANGE_SMOOTHSTEP] = "map_range_smoothstep",
[NODE_MAP_RANGE_SMOOTHERSTEP] = "map_range_smootherstep",
};
int ret = 0;
if (node->custom2 < ARRAY_SIZE(names) && names[node->custom2]) {
ret = GPU_stack_link(mat, node, names[node->custom2], in, out);
}
return 1;
else {
ret = GPU_stack_link(mat, node, "map_range_linear", in, out);
}
if (ret && node->custom1 &&
!ELEM(node->custom2, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) {
GPU_link(mat, "clamp_range", out[0].link, in[3].link, in[4].link, &out[0].link);
}
return ret;
}
void register_node_type_sh_map_range(void)
@ -62,6 +84,7 @@ void register_node_type_sh_map_range(void)
sh_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_map_range_in, sh_node_map_range_out);
node_type_init(&ntype, node_shader_init_map_range);
node_type_update(&ntype, node_shader_update_map_range);
node_type_gpu(&ntype, gpu_shader_map_range);
nodeRegisterType(&ntype);