diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenloader/intern/versioning_300.c | 16 | ||||
-rw-r--r-- | source/blender/editors/space_node/drawnode.cc | 1 | ||||
-rw-r--r-- | source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl | 147 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_node_types.h | 10 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_nodetree.c | 18 | ||||
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_map_range.cc | 395 |
6 files changed, 523 insertions, 64 deletions
diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index a42a2d9b95f..bc3cd7a09cb 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -2432,6 +2432,22 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Add node storage for map range node. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_MAP_RANGE) { + if (node->storage == NULL) { + NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__); + data->clamp = node->custom1; + data->data_type = CD_PROP_FLOAT; + data->interpolation_type = node->custom2; + node->storage = data; + } + } + } + } + FOREACH_NODETREE_END; } if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) { diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 430908f016f..87f7bfdafb0 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -235,6 +235,7 @@ static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), Pointe static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE); if (!ELEM(RNA_enum_get(ptr, "interpolation_type"), NODE_MAP_RANGE_SMOOTHSTEP, diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl index 7853aae31a1..1def3abec26 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_map_range.glsl @@ -4,13 +4,128 @@ float smootherstep(float edge0, float edge1, float x) return x * x * x * (x * (x * 6.0 - 15.0) + 10.0); } +vec3 smootherstep(vec3 edge0, vec3 edge1, vec3 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 vector_map_range_linear(float value, + float fromMin, + float fromMax, + float toMin, + float toMax, + float steps, + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) +{ + vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min)); + v_result = v_to_min + factor * (v_to_max - v_to_min); + if (use_clamp > 0.0) { + v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) : + clamp(v_result.x, v_to_min.x, v_to_max.x); + v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) : + clamp(v_result.y, v_to_min.y, v_to_max.y); + v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) : + clamp(v_result.z, v_to_min.z, v_to_max.z); + } +} + +void vector_map_range_stepped(float value, + float fromMin, + float fromMax, + float toMin, + float toMax, + float steps, + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) +{ + vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min)); + factor = safe_divide(floor(factor * (v_steps + 1.0)), v_steps); + v_result = v_to_min + factor * (v_to_max - v_to_min); + if (use_clamp > 0.0) { + v_result.x = (v_to_min.x > v_to_max.x) ? clamp(v_result.x, v_to_max.x, v_to_min.x) : + clamp(v_result.x, v_to_min.x, v_to_max.x); + v_result.y = (v_to_min.y > v_to_max.y) ? clamp(v_result.y, v_to_max.y, v_to_min.y) : + clamp(v_result.y, v_to_min.y, v_to_max.y); + v_result.z = (v_to_min.z > v_to_max.z) ? clamp(v_result.z, v_to_max.z, v_to_min.z) : + clamp(v_result.z, v_to_min.z, v_to_max.z); + } +} + +void vector_map_range_smoothstep(float value, + float fromMin, + float fromMax, + float toMin, + float toMax, + float steps, + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) +{ + vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min)); + factor = clamp(factor, 0.0, 1.0); + factor = (3.0 - 2.0 * factor) * (factor * factor); + v_result = v_to_min + factor * (v_to_max - v_to_min); +} + +void vector_map_range_smootherstep(float value, + float fromMin, + float fromMax, + float toMin, + float toMax, + float steps, + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) +{ + vec3 factor = safe_divide((v_value - v_from_min), (v_from_max - v_from_min)); + factor = clamp(factor, 0.0, 1.0); + factor = factor * factor * factor * (factor * (factor * 6.0 - 15.0) + 10.0); + v_result = v_to_min + factor * (v_to_max - v_to_min); +} + void map_range_linear(float value, float fromMin, float fromMax, float toMin, float toMax, float steps, - out float result) + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) { if (fromMax != fromMin) { result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin); @@ -26,7 +141,15 @@ void map_range_stepped(float value, float toMin, float toMax, float steps, - out float result) + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) { if (fromMax != fromMin) { float factor = (value - fromMin) / (fromMax - fromMin); @@ -44,7 +167,15 @@ void map_range_smoothstep(float value, float toMin, float toMax, float steps, - out float result) + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) { if (fromMax != fromMin) { float factor = (fromMin > fromMax) ? 1.0 - smoothstep(fromMax, fromMin, value) : @@ -62,7 +193,15 @@ void map_range_smootherstep(float value, float toMin, float toMax, float steps, - out float result) + vec3 v_value, + vec3 v_from_min, + vec3 v_from_max, + vec3 v_to_min, + vec3 v_to_max, + vec3 v_steps, + float use_clamp, + out float result, + out vec3 v_result) { if (fromMax != fromMin) { float factor = (fromMin > fromMax) ? 1.0 - smootherstep(fromMax, fromMin, value) : diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 09a8e6bdb06..dc5acb9d5b2 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1204,6 +1204,16 @@ typedef struct NodeDenoise { char prefilter; } NodeDenoise; +typedef struct NodeMapRange { + /* CustomDataType */ + uint8_t data_type; + + /* NodeMapRangeType. */ + uint8_t interpolation_type; + uint8_t clamp; + char _pad[5]; +} NodeMapRange; + typedef struct NodeAttributeClamp { /* CustomDataType. */ uint8_t data_type; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index b9ddb6a772a..df0271d81d5 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4954,18 +4954,32 @@ static void def_clamp(StructRNA *srna) static void def_map_range(StructRNA *srna) { + static const EnumPropertyItem rna_enum_data_type_items[] = { + {CD_PROP_FLOAT, "FLOAT", 0, "Float", "Floating-point value"}, + {CD_PROP_FLOAT3, "FLOAT_VECTOR", 0, "Vector", "3D vector with floating-point values"}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_struct_sdna_from(srna, "NodeMapRange", "storage"); + PropertyRNA *prop; prop = RNA_def_property(srna, "clamp", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1); + RNA_def_property_boolean_sdna(prop, NULL, "clamp", 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_sdna(prop, NULL, "interpolation_type"); 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"); + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "data_type"); + RNA_def_property_enum_items(prop, rna_enum_data_type_items); + RNA_def_property_ui_text(prop, "Data Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); } static void def_math(StructRNA *srna) diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index 347cba84643..865263bcb31 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -21,10 +21,14 @@ * \ingroup shdnodes */ +#include <algorithm> + #include "node_shader_util.h" #include "BLI_math_base_safe.h" +NODE_STORAGE_FUNCS(NodeMapRange) + namespace blender::nodes { static void sh_node_map_range_declare(NodeDeclarationBuilder &b) @@ -36,34 +40,80 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b) b.add_input<decl::Float>(N_("To Min")).min(-10000.0f).max(10000.0f); b.add_input<decl::Float>(N_("To Max")).min(-10000.0f).max(10000.0f).default_value(1.0f); b.add_input<decl::Float>(N_("Steps")).min(-10000.0f).max(10000.0f).default_value(4.0f); + b.add_input<decl::Vector>(N_("Vector")).min(0.0f).max(1.0f).hide_value(); + b.add_input<decl::Vector>(N_("From Min"), "From_Min_FLOAT3"); + b.add_input<decl::Vector>(N_("From Max"), "From_Max_FLOAT3").default_value(float3(1.0f)); + b.add_input<decl::Vector>(N_("To Min"), "To_Min_FLOAT3"); + b.add_input<decl::Vector>(N_("To Max"), "To_Max_FLOAT3").default_value(float3(1.0f)); + b.add_input<decl::Vector>(N_("Steps"), "Steps_FLOAT3").default_value(float3(4.0f)); b.add_output<decl::Float>(N_("Result")); + b.add_output<decl::Vector>(N_("Vector")); }; } // namespace blender::nodes static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { - bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps"); - nodeSetSocketAvailability(ntree, sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); + const NodeMapRange &storage = node_storage(*node); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const int type = (storage.data_type == CD_PROP_FLOAT) ? SOCK_FLOAT : SOCK_VECTOR; + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == type); + } + + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + nodeSetSocketAvailability(ntree, socket, socket->type == type); + } + + if (storage.interpolation_type != NODE_MAP_RANGE_STEPPED) { + if (type == SOCK_FLOAT) { + bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 5); + nodeSetSocketAvailability(ntree, sockSteps, false); + } + else { + bNodeSocket *sockSteps = (bNodeSocket *)BLI_findlink(&node->inputs, 11); + nodeSetSocketAvailability(ntree, sockSteps, false); + } + } } static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) { + NodeMapRange *data = (NodeMapRange *)MEM_callocN(sizeof(NodeMapRange), __func__); + data->clamp = 1; + data->data_type = CD_PROP_FLOAT; + data->interpolation_type = NODE_MAP_RANGE_LINEAR; node->custom1 = true; /* use_clamp */ node->custom2 = NODE_MAP_RANGE_LINEAR; /* interpolation */ + node->storage = data; } -static const char *gpu_shader_get_name(int mode) +static const char *gpu_shader_get_name(int mode, bool use_vector) { - switch (mode) { - case NODE_MAP_RANGE_LINEAR: - return "map_range_linear"; - case NODE_MAP_RANGE_STEPPED: - return "map_range_stepped"; - case NODE_MAP_RANGE_SMOOTHSTEP: - return "map_range_smoothstep"; - case NODE_MAP_RANGE_SMOOTHERSTEP: - return "map_range_smootherstep"; + if (use_vector) { + switch (mode) { + case NODE_MAP_RANGE_LINEAR: + return "vector_map_range_linear"; + case NODE_MAP_RANGE_STEPPED: + return "vector_map_range_stepped"; + case NODE_MAP_RANGE_SMOOTHSTEP: + return "vector_map_range_smoothstep"; + case NODE_MAP_RANGE_SMOOTHERSTEP: + return "vector_map_range_smootherstep"; + } + } + else { + switch (mode) { + case NODE_MAP_RANGE_LINEAR: + return "map_range_linear"; + case NODE_MAP_RANGE_STEPPED: + return "map_range_stepped"; + case NODE_MAP_RANGE_SMOOTHSTEP: + return "map_range_smoothstep"; + case NODE_MAP_RANGE_SMOOTHERSTEP: + return "map_range_smootherstep"; + } } return nullptr; @@ -75,22 +125,207 @@ static int gpu_shader_map_range(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - const char *name = gpu_shader_get_name(node->custom2); - + const NodeMapRange &storage = node_storage(*node); + bool use_vector = (storage.data_type == CD_PROP_FLOAT3); + const char *name = gpu_shader_get_name(storage.interpolation_type, use_vector); + float clamp = storage.clamp ? 1.0f : 0.0f; int ret = 0; if (name != nullptr) { - ret = GPU_stack_link(mat, node, name, in, out); + ret = GPU_stack_link(mat, node, name, in, out, GPU_constant(&clamp)); } else { - ret = GPU_stack_link(mat, node, "map_range_linear", in, out); + ret = GPU_stack_link(mat, node, "map_range_linear", in, out, GPU_constant(&clamp)); } - if (ret && node->custom1 && - !ELEM(node->custom2, NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) { + if (ret && storage.clamp && !use_vector && + !ELEM(storage.interpolation_type, 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; } +namespace blender::nodes { + +static inline float clamp_range(const float value, const float min, const float max) +{ + return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max); +} + +static float3 clamp_range(const float3 value, const float3 min, const float3 max) +{ + return float3(clamp_range(value.x, min.x, max.x), + clamp_range(value.y, min.y, max.y), + clamp_range(value.z, min.z, max.z)); +} + +static void map_range_vector_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps) +{ + signature->single_input<float3>("Vector"); + signature->single_input<float3>("From Min"); + signature->single_input<float3>("From Max"); + signature->single_input<float3>("To Min"); + signature->single_input<float3>("To Max"); + if (use_steps) { + signature->single_input<float3>("Steps"); + } + signature->single_output<float3>("Vector"); +} + +class MapRangeVectorFunction : public blender::fn::MultiFunction { + private: + bool clamp_; + + public: + MapRangeVectorFunction(bool clamp) : clamp_(clamp) + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range"}; + map_range_vector_signature(&signature, false); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + + if (clamp_) { + for (int64_t i : mask) { + results[i] = clamp_range(results[i], to_min[i], to_max[i]); + } + } + } +}; + +class MapRangeSteppedVectorFunction : public blender::fn::MultiFunction { + private: + bool clamp_; + + public: + MapRangeSteppedVectorFunction(bool clamp) : clamp_(clamp) + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range Stepped"}; + map_range_vector_signature(&signature, true); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + const blender::VArray<float3> &steps = params.readonly_single_input<float3>(5, "Steps"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(6, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + factor = float3::safe_divide(float3::floor(factor * (steps[i] + 1.0f)), steps[i]); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + + if (clamp_) { + for (int64_t i : mask) { + results[i] = clamp_range(results[i], to_min[i], to_max[i]); + } + } + } +}; + +class MapRangeSmoothstepVectorFunction : public blender::fn::MultiFunction { + public: + MapRangeSmoothstepVectorFunction() + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"}; + map_range_vector_signature(&signature, false); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + clamp_v3(factor, 0.0f, 1.0f); + factor = (float3(3.0f) - 2.0f * factor) * (factor * factor); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + } +}; + +class MapRangeSmootherstepVectorFunction : public blender::fn::MultiFunction { + public: + MapRangeSmootherstepVectorFunction() + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"}; + map_range_vector_signature(&signature, false); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); + const blender::VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); + const blender::VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); + const blender::VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); + const blender::VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); + blender::MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); + + for (int64_t i : mask) { + float3 factor = float3::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); + clamp_v3(factor, 0.0f, 1.0f); + factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f); + results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; + } + } +}; + static void map_range_signature(blender::fn::MFSignatureBuilder *signature, bool use_steps) { signature->single_input<float>("Value"); @@ -140,8 +375,7 @@ class MapRangeFunction : public blender::fn::MultiFunction { if (clamp_) { for (int64_t i : mask) { - results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) : - clamp_f(results[i], to_min[i], to_max[i]); + results[i] = clamp_range(results[i], to_min[i], to_max[i]); } } } @@ -185,8 +419,7 @@ class MapRangeSteppedFunction : public blender::fn::MultiFunction { if (clamp_) { for (int64_t i : mask) { - results[i] = (to_min[i] > to_max[i]) ? clamp_f(results[i], to_max[i], to_min[i]) : - clamp_f(results[i], to_min[i], to_max[i]); + results[i] = clamp_range(results[i], to_min[i], to_max[i]); } } } @@ -265,48 +498,92 @@ class MapRangeSmootherstepFunction : public blender::fn::MultiFunction { static void sh_node_map_range_build_multi_function( blender::nodes::NodeMultiFunctionBuilder &builder) { - bNode &bnode = builder.node(); - bool clamp = bnode.custom1 != 0; - int interpolation_type = bnode.custom2; - - switch (interpolation_type) { - case NODE_MAP_RANGE_LINEAR: { - if (clamp) { - static MapRangeFunction fn_with_clamp{true}; - builder.set_matching_fn(fn_with_clamp); - } - else { - static MapRangeFunction fn_without_clamp{false}; - builder.set_matching_fn(fn_without_clamp); + const NodeMapRange &storage = node_storage(builder.node()); + bool clamp = storage.clamp != 0; + int interpolation_type = storage.interpolation_type; + + switch (storage.data_type) { + case CD_PROP_FLOAT3: + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + if (clamp) { + static MapRangeVectorFunction fn_with_clamp{true}; + builder.set_matching_fn(fn_with_clamp); + } + else { + static MapRangeVectorFunction fn_without_clamp{false}; + builder.set_matching_fn(fn_without_clamp); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + if (clamp) { + static MapRangeSteppedVectorFunction fn_stepped_with_clamp{true}; + builder.set_matching_fn(fn_stepped_with_clamp); + } + else { + static MapRangeSteppedVectorFunction fn_stepped_without_clamp{false}; + builder.set_matching_fn(fn_stepped_without_clamp); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + static MapRangeSmoothstepVectorFunction smoothstep; + builder.set_matching_fn(smoothstep); + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + static MapRangeSmootherstepVectorFunction smootherstep; + builder.set_matching_fn(smootherstep); + break; + } + default: + break; } break; - } - case NODE_MAP_RANGE_STEPPED: { - if (clamp) { - static MapRangeSteppedFunction fn_stepped_with_clamp{true}; - builder.set_matching_fn(fn_stepped_with_clamp); - } - else { - static MapRangeSteppedFunction fn_stepped_without_clamp{false}; - builder.set_matching_fn(fn_stepped_without_clamp); + case CD_PROP_FLOAT: + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + if (clamp) { + static MapRangeFunction fn_with_clamp{true}; + builder.set_matching_fn(fn_with_clamp); + } + else { + static MapRangeFunction fn_without_clamp{false}; + builder.set_matching_fn(fn_without_clamp); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + if (clamp) { + static MapRangeSteppedFunction fn_stepped_with_clamp{true}; + builder.set_matching_fn(fn_stepped_with_clamp); + } + else { + static MapRangeSteppedFunction fn_stepped_without_clamp{false}; + builder.set_matching_fn(fn_stepped_without_clamp); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + static MapRangeSmoothstepFunction smoothstep; + builder.set_matching_fn(smoothstep); + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + static MapRangeSmootherstepFunction smootherstep; + builder.set_matching_fn(smootherstep); + break; + } + default: + break; } break; - } - case NODE_MAP_RANGE_SMOOTHSTEP: { - static MapRangeSmoothstepFunction smoothstep; - builder.set_matching_fn(smoothstep); - break; - } - case NODE_MAP_RANGE_SMOOTHERSTEP: { - static MapRangeSmootherstepFunction smootherstep; - builder.set_matching_fn(smootherstep); - break; - } - default: - break; } } +} // namespace blender::nodes + void register_node_type_sh_map_range() { static bNodeType ntype; @@ -314,9 +591,11 @@ void register_node_type_sh_map_range() sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0); ntype.declare = blender::nodes::sh_node_map_range_declare; node_type_init(&ntype, node_shader_init_map_range); + node_type_storage( + &ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage); node_type_update(&ntype, node_shader_update_map_range); node_type_gpu(&ntype, gpu_shader_map_range); - ntype.build_multi_function = sh_node_map_range_build_multi_function; + ntype.build_multi_function = blender::nodes::sh_node_map_range_build_multi_function; nodeRegisterType(&ntype); } |