Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Jolly <charlie>2021-12-14 00:20:07 +0300
committerCharlie Jolly <mistajolly@gmail.com>2021-12-14 21:27:01 +0300
commit5b61737a8f41688699fd1d711a25b7cea86d1530 (patch)
treefcea899c2663e666a6b2e9f15b31dfe2064c7a42 /source/blender/nodes
parent44232a2ce6d8762f10366f6bb660a37ce3e1acbd (diff)
Nodes: Add vector support to Map Range node
This replaces lost functionality from the old GN Attribute Map Range node. This also adds vector support to the shader version of the node. Notes: This breaks forward compatibility as this node now uses data storage. Reviewed By: HooglyBoogly, brecht Differential Revision: https://developer.blender.org/D12760
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.cc395
1 files changed, 337 insertions, 58 deletions
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);
}