Shading: Add Map Range node to Cycles and EEVEE.

This patch adds a new Map Range node that linearly remaps an input
value from a range to another. This node is similar to the compositor's
Map Range node.

Reviewers: brecht, JacquesLucke

Differential Revision: https://developer.blender.org/D5471
This commit is contained in:
OmarSquircleArt 2019-08-13 16:29:32 +02:00
parent aef08fda3a
commit 71641ab56d
17 changed files with 244 additions and 0 deletions

View File

@ -315,6 +315,9 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
node = new RGBToBWNode();
}
else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
node = new MapRangeNode();
}
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);
MathNode *math = new MathNode();

View File

@ -198,6 +198,7 @@ set(SRC_SVM_HEADERS
svm/svm_invert.h
svm/svm_light_path.h
svm/svm_magic.h
svm/svm_map_range.h
svm/svm_mapping.h
svm/svm_math.h
svm/svm_math_util.h

View File

@ -46,6 +46,7 @@ set(SRC_OSL
node_light_falloff.osl
node_light_path.osl
node_magic_texture.osl
node_map_range.osl
node_mapping.osl
node_math.osl
node_mix.osl

View File

@ -0,0 +1,25 @@
/*
* Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stdosl.h"
shader node_map_range(float Value = 1.0, float FromMin = 0.0, float FromMax = 1.0,
float ToMin = 0.0, float ToMax = 1.0, output float Result = 0.0)
{
if (FromMax != FromMin) {
Result = ToMin + ((Value - FromMin) / (FromMax - FromMin)) * (ToMax - ToMin);
}
}

View File

@ -192,6 +192,7 @@ CCL_NAMESPACE_END
#include "kernel/svm/svm_vector_transform.h"
#include "kernel/svm/svm_voxel.h"
#include "kernel/svm/svm_bump.h"
#include "kernel/svm/svm_map_range.h"
#ifdef __SHADER_RAYTRACE__
# include "kernel/svm/svm_ao.h"
@ -486,6 +487,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_BLACKBODY:
svm_node_blackbody(kg, sd, stack, node.y, node.z);
break;
case NODE_MAP_RANGE:
svm_node_map_range(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
# endif /* __EXTRA_NODES__ */
# if NODES_FEATURE(NODE_FEATURE_VOLUME)
case NODE_TEX_VOXEL:

View File

@ -0,0 +1,54 @@
/*
* Copyright 2011-2013 Blender Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
CCL_NAMESPACE_BEGIN
/* Map Range Node */
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,
int *offset)
{
uint from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset;
decode_node_uchar4(parameters_stack_offsets,
&from_min_stack_offset,
&from_max_stack_offset,
&to_min_stack_offset,
&to_max_stack_offset);
uint4 defaults = 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 result;
if (from_max != from_min) {
result = to_min + ((value - from_min) / (from_max - from_min)) * (to_max - to_min);
}
else {
result = 0.0f;
}
stack_store_float(stack, result_stack_offset, result);
}
CCL_NAMESPACE_END

View File

@ -138,6 +138,7 @@ typedef enum ShaderNodeType {
NODE_VECTOR_DISPLACEMENT,
NODE_PRINCIPLED_VOLUME,
NODE_IES,
NODE_MAP_RANGE,
} ShaderNodeType;
typedef enum NodeAttributeType {

View File

@ -5259,6 +5259,75 @@ void OutputNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_output_displacement");
}
/* Map Range Node */
NODE_DEFINE(MapRangeNode)
{
NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
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_OUT_FLOAT(result, "Result");
return type;
}
MapRangeNode::MapRangeNode() : ShaderNode(node_type)
{
}
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");
ShaderInput *from_min_in = input("From Min");
ShaderInput *from_max_in = input("From Max");
ShaderInput *to_min_in = input("To Min");
ShaderInput *to_max_in = input("To Max");
ShaderOutput *result_out = output("Result");
int value_stack_offset = compiler.stack_assign(value_in);
int from_min_stack_offset = compiler.stack_assign_if_linked(from_min_in);
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 result_stack_offset = compiler.stack_assign(result_out);
compiler.add_node(
NODE_MAP_RANGE,
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.add_node(__float_as_int(from_min),
__float_as_int(from_max),
__float_as_int(to_min),
__float_as_int(to_max));
}
void MapRangeNode::compile(OSLCompiler &compiler)
{
compiler.add(this, "node_map_range");
}
/* Math */
NODE_DEFINE(MathNode)

View File

@ -1228,6 +1228,17 @@ class BlackbodyNode : public ShaderNode {
float temperature;
};
class MapRangeNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MapRangeNode)
void constant_fold(const ConstantFolder &folder);
virtual int get_group()
{
return NODE_GROUP_LEVEL_3;
}
float value, from_min, from_max, to_min, to_max;
};
class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)

View File

@ -258,6 +258,7 @@ shader_node_categories = [
NodeItem("ShaderNodeVectorTransform"),
]),
ShaderNodeCategory("SH_NEW_CONVERTOR", "Converter", items=[
NodeItem("ShaderNodeMapRange"),
NodeItem("ShaderNodeMath"),
NodeItem("ShaderNodeValToRGB"),
NodeItem("ShaderNodeRGBToBW"),

View File

@ -976,6 +976,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_VOLUME_PRINCIPLED 200
/* 201..700 occupied by other node types, continue from 701 */
#define SH_NODE_BSDF_HAIR_PRINCIPLED 701
#define SH_NODE_MAP_RANGE 702
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1

View File

@ -3856,6 +3856,7 @@ static void registerShaderNodes(void)
register_node_type_sh_mapping();
register_node_type_sh_curve_vec();
register_node_type_sh_curve_rgb();
register_node_type_sh_map_range();
register_node_type_sh_math();
register_node_type_sh_vect_math();
register_node_type_sh_vect_transform();

View File

@ -429,6 +429,17 @@ void squeeze(float val, float width, float center, out float outval)
outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
}
void map_range(
float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
{
if (fromMax != fromMin) {
result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
}
else {
result = 0.0;
}
}
void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = v1 + v2;

View File

@ -163,6 +163,7 @@ set(SRC
shader/nodes/node_shader_layer_weight.c
shader/nodes/node_shader_light_falloff.c
shader/nodes/node_shader_light_path.c
shader/nodes/node_shader_map_range.c
shader/nodes/node_shader_mapping.c
shader/nodes/node_shader_math.c
shader/nodes/node_shader_mixRgb.c

View File

@ -48,6 +48,7 @@ void register_node_type_sh_brightcontrast(void);
void register_node_type_sh_mapping(void);
void register_node_type_sh_curve_vec(void);
void register_node_type_sh_curve_rgb(void);
void register_node_type_sh_map_range(void);
void register_node_type_sh_math(void);
void register_node_type_sh_vect_math(void);
void register_node_type_sh_squeeze(void);

View File

@ -50,6 +50,7 @@ DefNode(ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPIN
DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "" )
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, 0, "MAP_RANGE", MapRange, "Map Range", "" )
DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )

View File

@ -0,0 +1,58 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup shdnodes
*/
#include "node_shader_util.h"
/* **************** Map Range ******************** */
static bNodeSocketTemplate sh_node_map_range_in[] = {
{SOCK_FLOAT, 1, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
{SOCK_FLOAT, 1, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{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},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_map_range_out[] = {
{SOCK_FLOAT, 0, N_("Result")},
{-1, 0, ""},
};
static int gpu_shader_map_range(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
return GPU_stack_link(mat, node, "map_range", in, out);
}
void register_node_type_sh_map_range(void)
{
static bNodeType ntype;
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_gpu(&ntype, gpu_shader_map_range);
nodeRegisterType(&ntype);
}