Shading: Rewrite Mapping node with dynamic inputs.
authorOmarSquircleArt <omar.squircleart@gmail.com>
Wed, 4 Sep 2019 21:17:13 +0000 (23:17 +0200)
committerOmarSquircleArt <omar.squircleart@gmail.com>
Wed, 4 Sep 2019 21:17:13 +0000 (23:17 +0200)
This patch rewrites the Mapping node to support dynamic inputs. The
Max and Min options have been removed. They can be added as Min and
Max Vector Math nodes manually.

Texture nodes still use the old matrix-based mapping. A new SVM node
`NODE_TEXTURE_MAPPING` has been added to preserve this functionality.
Similarly, in GLSL, a `mapping_mat4` function has been added.

Reviewers: brecht, JacquesLucke

24 files changed:
intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/CMakeLists.txt
intern/cycles/kernel/shaders/node_mapping.osl
intern/cycles/kernel/svm/svm.h
intern/cycles/kernel/svm/svm_mapping.h
intern/cycles/kernel/svm/svm_mapping_util.h [new file with mode: 0644]
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/constant_fold.cpp
intern/cycles/render/constant_fold.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
intern/cycles/util/util_transform.h
source/blender/blenkernel/BKE_blender_version.h
source/blender/blenloader/intern/versioning_cycles.c
source/blender/editors/space_node/drawnode.c
source/blender/gpu/intern/gpu_material_library.h
source/blender/gpu/shaders/material/gpu_shader_material_mapping.glsl
source/blender/gpu/shaders/material/gpu_shader_material_math_util.glsl
source/blender/makesdna/DNA_node_types.h
source/blender/makesrna/RNA_enum_types.h
source/blender/makesrna/intern/rna_nodetree.c
source/blender/makesrna/intern/rna_texture.c
source/blender/nodes/shader/node_shader_util.c
source/blender/nodes/shader/nodes/node_shader_mapping.c

index e81336cd692cf15425463ce12ce02cd46e3e310f..f5a76002eb6b0137f456dd97af7bf939b8324a83 100644 (file)
@@ -208,24 +208,6 @@ static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping &b_mapping)
   mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z();
 }
 
-static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping &b_mapping)
-{
-  if (!b_mapping)
-    return;
-
-  mapping->translation = get_float3(b_mapping.translation());
-  mapping->rotation = get_float3(b_mapping.rotation());
-  mapping->scale = get_float3(b_mapping.scale());
-  mapping->type = (TextureMapping::Type)b_mapping.vector_type();
-
-  mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max();
-
-  if (b_mapping.use_min())
-    mapping->min = get_float3(b_mapping.min());
-  if (b_mapping.use_max())
-    mapping->max = get_float3(b_mapping.max());
-}
-
 static ShaderNode *add_node(Scene *scene,
                             BL::RenderEngine &b_engine,
                             BL::BlendData &b_data,
@@ -357,9 +339,7 @@ static ShaderNode *add_node(Scene *scene,
   else if (b_node.is_a(&RNA_ShaderNodeMapping)) {
     BL::ShaderNodeMapping b_mapping_node(b_node);
     MappingNode *mapping = new MappingNode();
-
-    get_tex_mapping(&mapping->tex_mapping, b_mapping_node);
-
+    mapping->type = (NodeMappingType)b_mapping_node.vector_type();
     node = mapping;
   }
   else if (b_node.is_a(&RNA_ShaderNodeFresnel)) {
index 89ecdc6b7aca6f07f3f9d96f937c2050c7815720..04df49aa058d40ddfe0b609a3b899dd7d2764580 100644 (file)
@@ -201,6 +201,7 @@ set(SRC_SVM_HEADERS
   svm/svm_magic.h
   svm/svm_map_range.h
   svm/svm_mapping.h
+  svm/svm_mapping_util.h
   svm/svm_math.h
   svm/svm_math_util.h
   svm/svm_mix.h
index f5cc2d1c5dd3d411f8b079700c07d0240e5a0527..8eed0ae9c48a89eb6218973f783934e1ed3a7a48 100644 (file)
 
 #include "stdosl.h"
 
-shader node_mapping(matrix Matrix = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
-                    point mapping_min = point(0.0, 0.0, 0.0),
-                    point mapping_max = point(0.0, 0.0, 0.0),
-                    int use_minmax = 0,
-                    point VectorIn = point(0.0, 0.0, 0.0),
-                    output point VectorOut = point(0.0, 0.0, 0.0))
+point safe_divide(point a, point b)
+{
+  return point((b[0] != 0.0) ? a[0] / b[0] : 0.0,
+               (b[1] != 0.0) ? a[1] / b[1] : 0.0,
+               (b[2] != 0.0) ? a[2] / b[2] : 0.0);
+}
+
+matrix euler_to_mat(point euler)
 {
-  point p = transform(Matrix, VectorIn);
+  float cx = cos(euler[0]);
+  float cy = cos(euler[1]);
+  float cz = cos(euler[2]);
+  float sx = sin(euler[0]);
+  float sy = sin(euler[1]);
+  float sz = sin(euler[2]);
+
+  matrix mat = matrix(1.0);
+  mat[0][0] = cy * cz;
+  mat[0][1] = cy * sz;
+  mat[0][2] = -sy;
 
-  if (use_minmax)
-    p = min(max(mapping_min, p), mapping_max);
+  mat[1][0] = sy * sx * cz - cx * sz;
+  mat[1][1] = sy * sx * sz + cx * cz;
+  mat[1][2] = cy * sx;
 
-  VectorOut = p;
+  mat[2][0] = sy * cx * cz + sx * sz;
+  mat[2][1] = sy * cx * sz - sx * cz;
+  mat[2][2] = cy * cx;
+  return mat;
+}
+
+shader node_mapping(string type = "point",
+                    point VectorIn = point(0.0, 0.0, 0.0),
+                    point Location = point(0.0, 0.0, 0.0),
+                    point Rotation = point(0.0, 0.0, 0.0),
+                    point Scale = point(1.0, 1.0, 1.0),
+                    output point VectorOut = point(0.0, 0.0, 0.0))
+{
+  if (type == "point") {
+    VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)) + Location;
+  }
+  else if (type == "texture") {
+    VectorOut = safe_divide(transform(transpose(euler_to_mat(Rotation)), (VectorIn - Location)),
+                            Scale);
+  }
+  else if (type == "vector") {
+    VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale));
+  }
+  else if (type == "normal") {
+    VectorOut = normalize(transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale)));
+  }
+  else {
+    warning("%s", "Unknown Mapping vector type!");
+  }
 }
index 95954aaf99e9ddf58903eb9f7737d6842e6c41b1..ce651a1b5ff7f742ce728ebcd11003eec21635d5 100644 (file)
@@ -162,6 +162,7 @@ CCL_NAMESPACE_END
 
 #include "kernel/svm/svm_color_util.h"
 #include "kernel/svm/svm_math_util.h"
+#include "kernel/svm/svm_mapping_util.h"
 
 #include "kernel/svm/svm_attribute.h"
 #include "kernel/svm/svm_gradient.h"
@@ -405,8 +406,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
 #endif       /* NODES_GROUP(NODE_GROUP_LEVEL_1) */
 
 #if NODES_GROUP(NODE_GROUP_LEVEL_2)
+      case NODE_TEXTURE_MAPPING:
+        svm_node_texture_mapping(kg, sd, stack, node.y, node.z, &offset);
+        break;
       case NODE_MAPPING:
-        svm_node_mapping(kg, sd, stack, node.y, node.z, &offset);
+        svm_node_mapping(kg, sd, stack, node.y, node.z, node.w, &offset);
         break;
       case NODE_MIN_MAX:
         svm_node_min_max(kg, sd, stack, node.y, node.z, &offset);
index 998a29912d46bfc4f14365ab298751011787d28d..6e19c859e194db2b9e80ba29662c167d7c950cda 100644 (file)
@@ -18,7 +18,33 @@ CCL_NAMESPACE_BEGIN
 
 /* Mapping Node */
 
-ccl_device void svm_node_mapping(
+ccl_device void svm_node_mapping(KernelGlobals *kg,
+                                 ShaderData *sd,
+                                 float *stack,
+                                 uint type,
+                                 uint inputs_stack_offsets,
+                                 uint result_stack_offset,
+                                 int *offset)
+{
+  uint vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset;
+  svm_unpack_node_uchar4(inputs_stack_offsets,
+                         &vector_stack_offset,
+                         &location_stack_offset,
+                         &rotation_stack_offset,
+                         &scale_stack_offset);
+
+  float3 vector = stack_load_float3(stack, vector_stack_offset);
+  float3 location = stack_load_float3(stack, location_stack_offset);
+  float3 rotation = stack_load_float3(stack, rotation_stack_offset);
+  float3 scale = stack_load_float3(stack, scale_stack_offset);
+
+  float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
+  stack_store_float3(stack, result_stack_offset, result);
+}
+
+/* Texture Mapping */
+
+ccl_device void svm_node_texture_mapping(
     KernelGlobals *kg, ShaderData *sd, float *stack, uint vec_offset, uint out_offset, int *offset)
 {
   float3 v = stack_load_float3(stack, vec_offset);
diff --git a/intern/cycles/kernel/svm/svm_mapping_util.h b/intern/cycles/kernel/svm/svm_mapping_util.h
new file mode 100644 (file)
index 0000000..ec2c84e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2014 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
+
+ccl_device float3
+svm_mapping(NodeMappingType type, float3 vector, float3 location, float3 rotation, float3 scale)
+{
+  Transform rotationTransform = euler_to_transform(rotation);
+  switch (type) {
+    case NODE_MAPPING_TYPE_POINT:
+      return transform_direction(&rotationTransform, (vector * scale)) + location;
+    case NODE_MAPPING_TYPE_TEXTURE:
+      return safe_divide_float3_float3(
+          transform_direction_transposed(&rotationTransform, (vector - location)), scale);
+    case NODE_MAPPING_TYPE_VECTOR:
+      return transform_direction(&rotationTransform, (vector * scale));
+    case NODE_MAPPING_TYPE_NORMAL:
+      return safe_normalize(
+          transform_direction(&rotationTransform, safe_divide_float3_float3(vector, scale)));
+    default:
+      return make_float3(0.0f, 0.0f, 0.0f);
+  }
+}
+
+CCL_NAMESPACE_END
index a3caa1ab68d2f44b5e2930f9802ed5f4b3123e2e..de7114566b3ab8e85023add80b1f928b68ae61cc 100644 (file)
@@ -140,6 +140,7 @@ typedef enum ShaderNodeType {
   NODE_IES,
   NODE_MAP_RANGE,
   NODE_CLAMP,
+  NODE_TEXTURE_MAPPING,
   NODE_TEX_WHITE_NOISE,
 } ShaderNodeType;
 
@@ -299,6 +300,13 @@ typedef enum NodeVectorMathType {
   NODE_VECTOR_MATH_MAXIMUM,
 } NodeVectorMathType;
 
+typedef enum NodeMappingType {
+  NODE_MAPPING_TYPE_POINT,
+  NODE_MAPPING_TYPE_TEXTURE,
+  NODE_MAPPING_TYPE_VECTOR,
+  NODE_MAPPING_TYPE_NORMAL
+} NodeMappingType;
+
 typedef enum NodeVectorTransformType {
   NODE_VECTOR_TRANSFORM_TYPE_VECTOR,
   NODE_VECTOR_TRANSFORM_TYPE_POINT,
index 851d4b71df80d95295d5c7a4921dfbf62d422601..f3809ee8d80eaa8f5be9cb0f60b8e1c08eff3e8a 100644 (file)
@@ -429,4 +429,21 @@ void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
   }
 }
 
+void ConstantFolder::fold_mapping(NodeMappingType type) const
+{
+  ShaderInput *vector_in = node->input("Vector");
+  ShaderInput *location_in = node->input("Location");
+  ShaderInput *rotation_in = node->input("Rotation");
+  ShaderInput *scale_in = node->input("Scale");
+
+  if (is_zero(scale_in)) {
+    make_zero();
+  }
+  else if ((is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR ||
+            type == NODE_MAPPING_TYPE_NORMAL) &&
+           is_zero(rotation_in) && is_one(scale_in)) {
+    try_bypass_or_make_constant(vector_in);
+  }
+}
+
 CCL_NAMESPACE_END
index 881636a9fe1465729c33f4923d855168f46a9b32..7f622488a889ceccc9898306d0157ca1f6c26ea1 100644 (file)
@@ -66,6 +66,7 @@ class ConstantFolder {
   void fold_mix(NodeMix type, bool clamp) const;
   void fold_math(NodeMathType type) const;
   void fold_vector_math(NodeVectorMathType type) const;
+  void fold_mapping(NodeMappingType type) const;
 };
 
 CCL_NAMESPACE_END
index 24aa95892202b9ba0ba51bc7aca9ba4cb4b74241..31dc986a4d1bc9e5acab3a8f88562abab2b535f7 100644 (file)
@@ -25,6 +25,7 @@
 #include "kernel/svm/svm_color_util.h"
 #include "kernel/svm/svm_ramp_util.h"
 #include "kernel/svm/svm_math_util.h"
+#include "kernel/svm/svm_mapping_util.h"
 #include "render/osl.h"
 #include "render/constant_fold.h"
 
@@ -149,7 +150,7 @@ bool TextureMapping::skip()
 
 void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out)
 {
-  compiler.add_node(NODE_MAPPING, offset_in, offset_out);
+  compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out);
 
   Transform tfm = compute_transform();
   compiler.add_node(tfm.x);
@@ -1727,9 +1728,18 @@ NODE_DEFINE(MappingNode)
 {
   NodeType *type = NodeType::add("mapping", create, NodeType::SHADER);
 
-  TEXTURE_MAPPING_DEFINE(MappingNode);
+  static NodeEnum type_enum;
+  type_enum.insert("point", NODE_MAPPING_TYPE_POINT);
+  type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
+  type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
+  type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
+  SOCKET_ENUM(type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
 
   SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
+  SOCKET_IN_POINT(location, "Location", make_float3(0.0f, 0.0f, 0.0f));
+  SOCKET_IN_POINT(rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f));
+  SOCKET_IN_POINT(scale, "Scale", make_float3(1.0f, 1.0f, 1.0f));
+
   SOCKET_OUT_POINT(vector, "Vector");
 
   return type;
@@ -1739,22 +1749,42 @@ MappingNode::MappingNode() : ShaderNode(node_type)
 {
 }
 
+void MappingNode::constant_fold(const ConstantFolder &folder)
+{
+  if (folder.all_inputs_constant()) {
+    float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
+    folder.make_constant(result);
+  }
+  else {
+    folder.fold_mapping((NodeMappingType)type);
+  }
+}
+
 void MappingNode::compile(SVMCompiler &compiler)
 {
   ShaderInput *vector_in = input("Vector");
+  ShaderInput *location_in = input("Location");
+  ShaderInput *rotation_in = input("Rotation");
+  ShaderInput *scale_in = input("Scale");
   ShaderOutput *vector_out = output("Vector");
 
-  tex_mapping.compile(
-      compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out));
+  int vector_stack_offset = compiler.stack_assign(vector_in);
+  int location_stack_offset = compiler.stack_assign(location_in);
+  int rotation_stack_offset = compiler.stack_assign(rotation_in);
+  int scale_stack_offset = compiler.stack_assign(scale_in);
+  int result_stack_offset = compiler.stack_assign(vector_out);
+
+  compiler.add_node(
+      NODE_MAPPING,
+      type,
+      compiler.encode_uchar4(
+          vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
+      result_stack_offset);
 }
 
 void MappingNode::compile(OSLCompiler &compiler)
 {
-  compiler.parameter("Matrix", tex_mapping.compute_transform());
-  compiler.parameter_point("mapping_min", tex_mapping.min);
-  compiler.parameter_point("mapping_max", tex_mapping.max);
-  compiler.parameter("use_minmax", tex_mapping.use_minmax);
-
+  compiler.parameter(this, "type");
   compiler.add(this, "node_mapping");
 }
 
index 271d60d16b7484675b1c876c42ffede4080d6e0b..769687f1f190d2f4ad7c5c89c63d9249ab9121f2 100644 (file)
@@ -391,9 +391,10 @@ class MappingNode : public ShaderNode {
   {
     return NODE_GROUP_LEVEL_2;
   }
+  void constant_fold(const ConstantFolder &folder);
 
-  float3 vector;
-  TextureMapping tex_mapping;
+  float3 vector, location, rotation, scale;
+  NodeMappingType type;
 };
 
 class RGBToBWNode : public ShaderNode {
index cfe71d696ed1ea7b9611ac405a0600c0a816996f..407654245cbd4a0ed4ed0f5340e6635077215dd9 100644 (file)
@@ -148,6 +148,32 @@ ccl_device_inline Transform make_transform(float a,
   return t;
 }
 
+ccl_device_inline Transform euler_to_transform(const float3 euler)
+{
+  float cx = cosf(euler.x);
+  float cy = cosf(euler.y);
+  float cz = cosf(euler.z);
+  float sx = sinf(euler.x);
+  float sy = sinf(euler.y);
+  float sz = sinf(euler.z);
+
+  Transform t;
+  t.x.x = cy * cz;
+  t.y.x = cy * sz;
+  t.z.x = -sy;
+
+  t.x.y = sy * sx * cz - cx * sz;
+  t.y.y = sy * sx * sz + cx * cz;
+  t.z.y = cy * sx;
+
+  t.x.z = sy * cx * cz + sx * sz;
+  t.y.z = sy * cx * sz - sx * cz;
+  t.z.z = cy * cx;
+
+  t.x.w = t.y.w = t.z.w = 0.0f;
+  return t;
+}
+
 /* Constructs a coordinate frame from a normalized normal. */
 ccl_device_inline Transform make_transform_frame(float3 N)
 {
index 30df5abebc0b44fd9776504627c54f414bd63b15..e68989dd9ef62a03330ede73d523559ac746e00b 100644 (file)
@@ -27,7 +27,7 @@
  * \note Use #STRINGIFY() rather than defining with quotes.
  */
 #define BLENDER_VERSION 281
-#define BLENDER_SUBVERSION 7
+#define BLENDER_SUBVERSION 8
 /** Several breakages with 280, e.g. collections vs layers. */
 #define BLENDER_MINVERSION 280
 #define BLENDER_MINSUBVERSION 0
index f12a544a9ccba95e87379bb66af916652f9ef817..52be5b2ce74ce673fe4a609952ce8ef99e2b3cfc 100644 (file)
 #include "DNA_node_types.h"
 #include "DNA_particle_types.h"
 #include "DNA_camera_types.h"
+#include "DNA_anim_types.h"
 
 #include "BKE_colortools.h"
+#include "BKE_animsys.h"
 #include "BKE_idprop.h"
 #include "BKE_main.h"
 #include "BKE_node.h"
 
+#include "MEM_guardedalloc.h"
+
 #include "IMB_colormanagement.h"
 
 #include "BLO_readfile.h"
@@ -769,6 +773,141 @@ static void update_noise_node_dimensions(bNodeTree *ntree)
   }
 }
 
+/* The Mapping node has been rewritten to support dynamic inputs. Previously,
+ * the transformation information was stored in a TexMapping struct in the
+ * node->storage member of bNode. Currently, the transformation information
+ * is stored in input sockets. To correct this, we transfer the information
+ * from the TexMapping struct to the input sockets.
+ *
+ * Additionally, the Minimum and Maximum properties are no longer available
+ * in the node. To correct this, a Vector Minimum and/or a Vector Maximum
+ * nodes are added if needed.
+ *
+ * Finally, the TexMapping struct is freed and node->storage is set to NULL.
+ *
+ * Since the RNA paths of the properties changed, we also have to update the
+ * rna_path of the FCurves if they exist. To do that, we loop over FCurves
+ * and check if they control a property of the node, if they do, we update
+ * the path to be that of the corrsponding socket in the node or the added
+ * minimum/maximum node.
+ *
+ */
+static void update_mapping_node_inputs_and_properties(bNodeTree *ntree)
+{
+  bool need_update = false;
+
+  for (bNode *node = ntree->nodes.first; node; node = node->next) {
+    if (node->type == SH_NODE_MAPPING) {
+      TexMapping *mapping = (TexMapping *)node->storage;
+      node->custom1 = mapping->type;
+      node->width = 140.0f;
+
+      bNodeSocket *sockLocation = nodeFindSocket(node, SOCK_IN, "Location");
+      copy_v3_v3(cycles_node_socket_vector_value(sockLocation), mapping->loc);
+      bNodeSocket *sockRotation = nodeFindSocket(node, SOCK_IN, "Rotation");
+      copy_v3_v3(cycles_node_socket_vector_value(sockRotation), mapping->rot);
+      bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+      copy_v3_v3(cycles_node_socket_vector_value(sockScale), mapping->size);
+
+      bNode *maximumNode = NULL;
+      if (mapping->flag & TEXMAP_CLIP_MAX) {
+        maximumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+        maximumNode->custom1 = NODE_VECTOR_MATH_MAXIMUM;
+        if (mapping->flag & TEXMAP_CLIP_MIN) {
+          maximumNode->locx = node->locx + (node->width + 20.0f) * 2.0f;
+        }
+        else {
+          maximumNode->locx = node->locx + node->width + 20.0f;
+        }
+        maximumNode->locy = node->locy;
+        bNodeSocket *sockMaximumB = BLI_findlink(&maximumNode->inputs, 1);
+        copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->max);
+        bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
+
+        LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+          if (link->fromsock == sockMappingResult) {
+            bNodeSocket *sockMaximumResult = nodeFindSocket(maximumNode, SOCK_OUT, "Vector");
+            nodeAddLink(ntree, maximumNode, sockMaximumResult, link->tonode, link->tosock);
+            nodeRemLink(ntree, link);
+          }
+        }
+        if (!(mapping->flag & TEXMAP_CLIP_MIN)) {
+          bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
+          nodeAddLink(ntree, node, sockMappingResult, maximumNode, sockMaximumA);
+        }
+
+        need_update = true;
+      }
+
+      bNode *minimumNode = NULL;
+      if (mapping->flag & TEXMAP_CLIP_MIN) {
+        minimumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+        minimumNode->custom1 = NODE_VECTOR_MATH_MINIMUM;
+        minimumNode->locx = node->locx + node->width + 20.0f;
+        minimumNode->locy = node->locy;
+        bNodeSocket *sockMinimumB = BLI_findlink(&minimumNode->inputs, 1);
+        copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->min);
+
+        bNodeSocket *sockMinimumResult = nodeFindSocket(minimumNode, SOCK_OUT, "Vector");
+        bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Vector");
+
+        if (maximumNode) {
+          bNodeSocket *sockMaximumA = BLI_findlink(&maximumNode->inputs, 0);
+          nodeAddLink(ntree, minimumNode, sockMinimumResult, maximumNode, sockMaximumA);
+        }
+        else {
+          LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+            if (link->fromsock == sockMappingResult) {
+              nodeAddLink(ntree, minimumNode, sockMinimumResult, link->tonode, link->tosock);
+              nodeRemLink(ntree, link);
+            }
+          }
+        }
+        bNodeSocket *sockMinimumA = BLI_findlink(&minimumNode->inputs, 0);
+        nodeAddLink(ntree, node, sockMappingResult, minimumNode, sockMinimumA);
+
+        need_update = true;
+      }
+
+      MEM_freeN(node->storage);
+      node->storage = NULL;
+
+      AnimData *animData = BKE_animdata_from_id(&ntree->id);
+      if (animData && animData->action) {
+        const char *nodePath = BLI_sprintfN("nodes[\"%s\"]", node->name);
+        for (FCurve *fcu = animData->action->curves.first; fcu; fcu = fcu->next) {
+          if (STRPREFIX(fcu->rna_path, nodePath) &&
+              !BLI_str_endswith(fcu->rna_path, "default_value")) {
+
+            MEM_freeN(fcu->rna_path);
+            if (BLI_str_endswith(fcu->rna_path, "translation")) {
+              fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[1].default_value");
+            }
+            else if (BLI_str_endswith(fcu->rna_path, "rotation")) {
+              fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[2].default_value");
+            }
+            else if (BLI_str_endswith(fcu->rna_path, "scale")) {
+              fcu->rna_path = BLI_sprintfN("%s.%s", nodePath, "inputs[3].default_value");
+            }
+            else if (minimumNode && BLI_str_endswith(fcu->rna_path, "min")) {
+              fcu->rna_path = BLI_sprintfN(
+                  "nodes[\"%s\"].%s", minimumNode->name, "inputs[1].default_value");
+            }
+            else if (maximumNode && BLI_str_endswith(fcu->rna_path, "max")) {
+              fcu->rna_path = BLI_sprintfN(
+                  "nodes[\"%s\"].%s", maximumNode->name, "inputs[1].default_value");
+            }
+          }
+        }
+      }
+    }
+  }
+
+  if (need_update) {
+    ntreeUpdateTree(NULL, ntree);
+  }
+}
+
 void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
 {
   /* Particle shape shared with Eevee. */
@@ -950,4 +1089,13 @@ void do_versions_after_linking_cycles(Main *bmain)
     }
     FOREACH_NODETREE_END;
   }
+
+  if (!MAIN_VERSION_ATLEAST(bmain, 281, 8)) {
+    FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+      if (ntree->type == NTREE_SHADER) {
+        update_mapping_node_inputs_and_properties(ntree);
+      }
+    }
+    FOREACH_NODETREE_END;
+  }
 }
index 47433693e7b786f274fbf686e36182ac98536da5..8e6b09be2c724ace3d69880463dab16523b38205 100644 (file)
@@ -731,37 +731,7 @@ static void node_buts_image_user(uiLayout *layout,
 
 static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
 {
-  uiLayout *row, *col, *sub;
-
-  uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
-
-  row = uiLayoutRow(layout, false);
-
-  col = uiLayoutColumn(row, true);
-  uiItemL(col, IFACE_("Location:"), ICON_NONE);
-  uiItemR(col, ptr, "translation", 0, "", ICON_NONE);
-
-  col = uiLayoutColumn(row, true);
-  uiItemL(col, IFACE_("Rotation:"), ICON_NONE);
-  uiItemR(col, ptr, "rotation", 0, "", ICON_NONE);
-
-  col = uiLayoutColumn(row, true);
-  uiItemL(col, IFACE_("Scale:"), ICON_NONE);
-  uiItemR(col, ptr, "scale", 0, "", ICON_NONE);
-
-  row = uiLayoutRow(layout, false);
-
-  col = uiLayoutColumn(row, true);
-  uiItemR(col, ptr, "use_min", 0, IFACE_("Min"), ICON_NONE);
-  sub = uiLayoutColumn(col, true);
-  uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
-  uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
-
-  col = uiLayoutColumn(row, true);
-  uiItemR(col, ptr, "use_max", 0, IFACE_("Max"), ICON_NONE);
-  sub = uiLayoutColumn(col, true);
-  uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
-  uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
+  uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
 }
 
 static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
index 99a710947534b0e8aad838dcaf3a3740cc88ca5d..9c0cf3e6bea7e84d04515f154d57f9fced1e9e15 100644 (file)
@@ -318,7 +318,7 @@ static GPUMaterialLibrary gpu_shader_material_light_path_library = {
 
 static GPUMaterialLibrary gpu_shader_material_mapping_library = {
     .code = datatoc_gpu_shader_material_mapping_glsl,
-    .dependencies = {NULL},
+    .dependencies = {&gpu_shader_material_math_util_library, NULL},
 };
 
 static GPUMaterialLibrary gpu_shader_material_map_range_library = {
index ef47ac2be982dee0aa881dae53b735fb92814feb..07f152439fe7fa5f411da31283a20967a3a5de26 100644 (file)
@@ -1,7 +1,27 @@
-void mapping(
+void mapping_mat4(
     vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
 {
   mat4 mat = mat4(m0, m1, m2, m3);
   outvec = (mat * vec4(vec, 1.0)).xyz;
   outvec = clamp(outvec, minvec, maxvec);
 }
+
+void mapping_point(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+  result = (euler_to_mat3(rotation) * (vector * scale)) + location;
+}
+
+void mapping_texture(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+  result = safe_divide(transpose(euler_to_mat3(rotation)) * (vector - location), scale);
+}
+
+void mapping_vector(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+  result = euler_to_mat3(rotation) * (vector * scale);
+}
+
+void mapping_normal(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+  result = normalize(euler_to_mat3(rotation) * safe_divide(vector, scale));
+}
index 0be7da0cc4c2d586ce255bf8fa8bad12de01f04e..fd9aaf4ae86f2685d103f4cdc50c64b824c79d28 100644 (file)
@@ -85,6 +85,30 @@ void vector_normalize(vec3 normal, out vec3 outnormal)
 
 /* Matirx Math */
 
+mat3 euler_to_mat3(vec3 euler)
+{
+  float cx = cos(euler.x);
+  float cy = cos(euler.y);
+  float cz = cos(euler.z);
+  float sx = sin(euler.x);
+  float sy = sin(euler.y);
+  float sz = sin(euler.z);
+
+  mat3 mat;
+  mat[0][0] = cy * cz;
+  mat[0][1] = cy * sz;
+  mat[0][2] = -sy;
+
+  mat[1][0] = sy * sx * cz - cx * sz;
+  mat[1][1] = sy * sx * sz + cx * cz;
+  mat[1][2] = cy * sx;
+
+  mat[2][0] = sy * cx * cz + sx * sz;
+  mat[2][1] = sy * cx * sz - sx * cz;
+  mat[2][2] = cy * cx;
+  return mat;
+}
+
 void direction_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
 {
   vout = (mat * vec4(vin, 0.0)).xyz;
index 0787f41b810e64c8da4c2a139f2025b61aba78dd..ee5e9a13f665605dd655b7d6b8054a132119bfd2 100644 (file)
@@ -1169,6 +1169,14 @@ typedef struct NodeDenoise {
 #define SHD_AO_INSIDE 1
 #define SHD_AO_LOCAL 2
 
+/* Mapping node vector types */
+enum {
+  NODE_MAPPING_TYPE_POINT = 0,
+  NODE_MAPPING_TYPE_TEXTURE = 1,
+  NODE_MAPPING_TYPE_VECTOR = 2,
+  NODE_MAPPING_TYPE_NORMAL = 3,
+};
+
 /* math node clamp */
 #define SHD_MATH_CLAMP 1
 
index b3e1f22f413db74eb5b1f0eed7cc81ef07173f51..e72a55b5a9ec7de730f4f9659e35fd6c00a96539 100644 (file)
@@ -184,6 +184,7 @@ extern const EnumPropertyItem rna_enum_file_sort_items[];
 extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
 
 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[];
 
index 988533e0f0ea7bf387c9572f944bf89ff4abf4d0..6a4d59bd8837cb855d7d6f0f8fff752e880ebc95 100644 (file)
@@ -102,6 +102,26 @@ static const EnumPropertyItem node_chunksize_items[] = {
 };
 #endif
 
+const EnumPropertyItem rna_enum_mapping_type_items[] = {
+    {NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
+    {NODE_MAPPING_TYPE_TEXTURE,
+     "TEXTURE",
+     0,
+     "Texture",
+     "Transform a texture by inverse mapping the texture coordinate"},
+    {NODE_MAPPING_TYPE_VECTOR,
+     "VECTOR",
+     0,
+     "Vector",
+     "Transform a direction vector. Location is ignored"},
+    {NODE_MAPPING_TYPE_NORMAL,
+     "NORMAL",
+     0,
+     "Normal",
+     "Transform a unit normal vector. Location is ignored"},
+    {0, NULL, 0, NULL, NULL},
+};
+
 const EnumPropertyItem rna_enum_node_math_items[] = {
     {NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
     {NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
@@ -3213,13 +3233,6 @@ static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene),
   nodeUpdate(ntree, node); /* to update image node sockets */
 }
 
-static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
-  bNode *node = ptr->data;
-  BKE_texture_mapping_init(node->storage);
-  rna_Node_update(bmain, scene, ptr);
-}
-
 static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
 {
   bNode *node = ptr->data;
@@ -4034,68 +4047,13 @@ static void def_sh_output_linestyle(StructRNA *srna)
 
 static void def_sh_mapping(StructRNA *srna)
 {
-  static const EnumPropertyItem prop_vect_type_items[] = {
-      {TEXMAP_TYPE_TEXTURE,
-       "TEXTURE",
-       0,
-       "Texture",
-       "Transform a texture by inverse mapping the texture coordinate"},
-      {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
-      {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
-      {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
-      {0, NULL, 0, NULL, NULL},
-  };
-
-  static float default_1[3] = {1.f, 1.f, 1.f};
-
   PropertyRNA *prop;
 
-  RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
-
   prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
-  RNA_def_property_enum_sdna(prop, NULL, "type");
-  RNA_def_property_enum_items(prop, prop_vect_type_items);
+  RNA_def_property_enum_sdna(prop, NULL, "custom1");
+  RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
   RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
-  prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
-  RNA_def_property_float_sdna(prop, NULL, "loc");
-  RNA_def_property_ui_text(prop, "Location", "");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
-  /* Not PROP_XYZ, this is now in radians, no more degrees */
-  prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
-  RNA_def_property_float_sdna(prop, NULL, "rot");
-  RNA_def_property_ui_text(prop, "Rotation", "");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
-  prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
-  RNA_def_property_float_sdna(prop, NULL, "size");
-  RNA_def_property_float_array_default(prop, default_1);
-  RNA_def_property_flag(prop, PROP_PROPORTIONAL);
-  RNA_def_property_ui_text(prop, "Scale", "");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
-  prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_XYZ);
-  RNA_def_property_float_sdna(prop, NULL, "min");
-  RNA_def_property_ui_text(prop, "Minimum", "Minimum value for clipping");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
-  prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_XYZ);
-  RNA_def_property_float_sdna(prop, NULL, "max");
-  RNA_def_property_float_array_default(prop, default_1);
-  RNA_def_property_ui_text(prop, "Maximum", "Maximum value for clipping");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
-  prop = RNA_def_property(srna, "use_min", PROP_BOOLEAN, PROP_NONE);
-  RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MIN);
-  RNA_def_property_ui_text(prop, "Has Minimum", "Whether to use minimum clipping value");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
-  prop = RNA_def_property(srna, "use_max", PROP_BOOLEAN, PROP_NONE);
-  RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MAX);
-  RNA_def_property_ui_text(prop, "Has Maximum", "Whether to use maximum clipping value");
-  RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
+  RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
 }
 
 static void def_sh_attribute(StructRNA *srna)
index 2015356d071808d3bf5f08fa8c4014eeb8abe447..2fc0e2bdf2db74e756a016b682fe80e909c31aa3 100644 (file)
@@ -465,18 +465,6 @@ static void rna_def_texmapping(BlenderRNA *brna)
       {0, NULL, 0, NULL, NULL},
   };
 
-  static const EnumPropertyItem prop_vect_type_items[] = {
-      {TEXMAP_TYPE_TEXTURE,
-       "TEXTURE",
-       0,
-       "Texture",
-       "Transform a texture by inverse mapping the texture coordinate"},
-      {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
-      {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
-      {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
-      {0, NULL, 0, NULL, NULL},
-  };
-
   static const EnumPropertyItem prop_xyz_mapping_items[] = {
       {0, "NONE", 0, "None", ""},
       {1, "X", 0, "X", ""},
@@ -493,7 +481,7 @@ static void rna_def_texmapping(BlenderRNA *brna)
 
   prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
   RNA_def_property_enum_sdna(prop, NULL, "type");
-  RNA_def_property_enum_items(prop, prop_vect_type_items);
+  RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
   RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
   RNA_def_property_update(prop, 0, "rna_Texture_mapping_update");
 
index 65676a5ea91c0dee419007d3ae376676faee0254..a2b18b614808098323ee80c2723cc455bc54cab3 100644 (file)
@@ -280,7 +280,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
     tmat2 = GPU_uniform((float *)texmap->mat[2]);
     tmat3 = GPU_uniform((float *)texmap->mat[3]);
 
-    GPU_link(mat, "mapping", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
+    GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
 
     if (texmap->type == TEXMAP_TYPE_NORMAL) {
       GPU_link(mat, "vector_normalize", in[0].link, &in[0].link);
index e58a5d72f2870e7846745aa07dd0b7f4c8ad75b4..d607fcdc7a1adebfaf788779048727082dbd5d49 100644 (file)
 
 /* **************** MAPPING  ******************** */
 static bNodeSocketTemplate sh_node_mapping_in[] = {
-    {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
+    {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
+    {SOCK_VECTOR, 1, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+    {SOCK_VECTOR, 1, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+    {SOCK_VECTOR, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
     {-1, 0, ""},
 };
 
@@ -34,91 +37,27 @@ static bNodeSocketTemplate sh_node_mapping_out[] = {
     {-1, 0, ""},
 };
 
-static void *node_shader_initexec_mapping(bNodeExecContext *UNUSED(context),
-                                          bNode *node,
-                                          bNodeInstanceKey UNUSED(key))
-{
-  TexMapping *texmap = node->storage;
-  BKE_texture_mapping_init(texmap);
-  return NULL;
-}
-
-/* do the regular mapping options for blender textures */
-static void node_shader_exec_mapping(void *UNUSED(data),
-                                     int UNUSED(thread),
-                                     bNode *node,
-                                     bNodeExecData *UNUSED(execdata),
-                                     bNodeStack **in,
-                                     bNodeStack **out)
-{
-  TexMapping *texmap = node->storage;
-  float *vec = out[0]->vec;
-
-  /* stack order input:  vector */
-  /* stack order output: vector */
-  nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
-  mul_m4_v3(texmap->mat, vec);
-
-  if (texmap->flag & TEXMAP_CLIP_MIN) {
-    if (vec[0] < texmap->min[0]) {
-      vec[0] = texmap->min[0];
-    }
-    if (vec[1] < texmap->min[1]) {
-      vec[1] = texmap->min[1];
-    }
-    if (vec[2] < texmap->min[2]) {
-      vec[2] = texmap->min[2];
-    }
-  }
-  if (texmap->flag & TEXMAP_CLIP_MAX) {
-    if (vec[0] > texmap->max[0]) {
-      vec[0] = texmap->max[0];
-    }
-    if (vec[1] > texmap->max[1]) {
-      vec[1] = texmap->max[1];
-    }
-    if (vec[2] > texmap->max[2]) {
-      vec[2] = texmap->max[2];
-    }
-  }
-
-  if (texmap->type == TEXMAP_TYPE_NORMAL) {
-    normalize_v3(vec);
-  }
-}
-
-static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
-{
-  node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
-}
-
 static int gpu_shader_mapping(GPUMaterial *mat,
                               bNode *node,
                               bNodeExecData *UNUSED(execdata),
                               GPUNodeStack *in,
                               GPUNodeStack *out)
 {
-  TexMapping *texmap = node->storage;
-  float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
-  float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
-  static float max[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
-  static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
-  GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
-
-  tmin = GPU_uniform((domin) ? texmap->min : min);
-  tmax = GPU_uniform((domax) ? texmap->max : max);
-  tmat0 = GPU_uniform((float *)texmap->mat[0]);
-  tmat1 = GPU_uniform((float *)texmap->mat[1]);
-  tmat2 = GPU_uniform((float *)texmap->mat[2]);
-  tmat3 = GPU_uniform((float *)texmap->mat[3]);
-
-  GPU_stack_link(mat, node, "mapping", in, out, tmat0, tmat1, tmat2, tmat3, tmin, tmax);
-
-  if (texmap->type == TEXMAP_TYPE_NORMAL) {
-    GPU_link(mat, "vector_normalize", out[0].link, &out[0].link);
-  }
+  static const char *names[] = {
+      [NODE_MAPPING_TYPE_POINT] = "mapping_point",
+      [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
+      [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
+      [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
+  };
+
+  return GPU_stack_link(mat, node, names[node->custom1], in, out);
+}
 
-  return true;
+static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node)
+{
+  bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
+  nodeSetSocketAvailability(
+      sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
 }
 
 void register_node_type_sh_mapping(void)
@@ -127,11 +66,8 @@ void register_node_type_sh_mapping(void)
 
   sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
   node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
-  node_type_size(&ntype, 320, 160, 360);
-  node_type_init(&ntype, node_shader_init_mapping);
-  node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
-  node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping);
   node_type_gpu(&ntype, gpu_shader_mapping);
+  node_type_update(&ntype, node_shader_update_mapping);
 
   nodeRegisterType(&ntype);
 }