瀏覽代碼

Conformance with Blender2.81

1. ShaderNodeMapping socket and property change,
see https://wiki.blender.org/wiki/Reference/Release_Notes/2.81/Python_API
2. Exclude two unused input socket (dhdx, dhdy) in BumpNode
Jason0214 5 年之前
父節點
當前提交
04ab6cbcc5

+ 111 - 35
io_scene_godot/converters/material/script_shader/node_converters.py

@@ -1,3 +1,4 @@
+# pylint: disable-msg=too-many-lines
 """a set of shader node converters responsible for generate"""
 import logging
 from collections import deque
@@ -19,6 +20,9 @@ def blender_value_to_string(blender_value):
 
         return "vec%d(%s)" % (len(tmp), ", ".join(tmp))
 
+    if isinstance(blender_value, mathutils.Euler):
+        return "vec3(%s)" % ', '.join([str(d) for d in blender_value])
+
     if isinstance(blender_value, mathutils.Matrix):
         # godot mat is column major order
         mat = blender_value.transposed()
@@ -109,6 +113,7 @@ class ShadingFlags:
 
 class NodeConverterBase:
     # pylint: disable-msg=too-many-instance-attributes
+    # pylint: disable-msg=too-many-public-methods
     """helper class which wraps a blender shader node and
     able to generate fragment/vertex script from the node"""
 
@@ -323,6 +328,30 @@ class NodeConverterBase:
                 "point_space_convert_world_to_view")
         self.add_function_call(function, [var, 'INV_CAMERA_MATRIX'], [])
 
+    def location_to_mat(self, loc_vec):
+        """Convert a vec3 location to homogeneous space mat4 representation"""
+        loc_mat = self.generate_variable_id_str("location")
+        self.local_code.append("mat4 %s" % loc_mat)
+        function = find_function_by_name("location_to_mat4")
+        self.add_function_call(function, [loc_vec], [loc_mat])
+        return loc_mat
+
+    def rotation_to_mat(self, rot_vec):
+        """Convert a euler angle XYZ rotation to mat4 representation"""
+        rot_mat = self.generate_variable_id_str("rotation")
+        self.local_code.append("mat4 %s" % rot_mat)
+        function = find_function_by_name("euler_angle_XYZ_to_mat4")
+        self.add_function_call(function, [rot_vec], [rot_mat])
+        return rot_mat
+
+    def scale_to_mat(self, scale_vec):
+        """Convert a vec3 scale to mat4"""
+        sca_mat = self.generate_variable_id_str("scale")
+        self.local_code.append("mat4 %s" % sca_mat)
+        function = find_function_by_name("scale_to_mat4")
+        self.add_function_call(function, [scale_vec], [sca_mat])
+        return sca_mat
+
     def _initialize_value_in_socket(self, socket, blnode_to_converter_map):
         type_str = socket_to_type_string(socket)
         id_str = self.generate_socket_id_str(socket)
@@ -571,6 +600,8 @@ class BumpNodeConverter(NodeConverterBase):
         in_arguments = list()
         for socket in self.bl_node.inputs:
             socket_var = self.in_sockets_map[socket]
+            if socket.name in ('Height_dx', 'Height_dy'):
+                continue
             if socket.name == 'Normal' and socket.is_linked:
                 self.zup_to_yup(socket_var)
                 self.world_to_view(socket_var)
@@ -788,50 +819,95 @@ class ImageTextureNodeConverter(NodeConverterBase):
 class MappingNodeConverter(NodeConverterBase):
     """Converter for ShaderNodeMapping"""
 
+    # pylint: disable-msg=too-many-statements
     def parse_node_to_fragment(self):
-        function = find_node_function(self.bl_node)
-
-        rot_mat = self.bl_node.rotation.to_matrix().to_4x4()
-        loc_mat = mathutils.Matrix.Translation(self.bl_node.translation)
-        sca_mat = mathutils.Matrix((
-            (self.bl_node.scale[0], 0, 0),
-            (0, self.bl_node.scale[1], 0),
-            (0, 0, self.bl_node.scale[2]),
-        )).to_4x4()
-
         in_vec = self.in_sockets_map[self.bl_node.inputs[0]]
+        output_socket = self.bl_node.outputs[0]
+        out_vec = self.generate_socket_id_str(output_socket)
 
-        if self.bl_node.vector_type == "TEXTURE":
-            # Texture: Transform a texture by inverse
-            # mapping the texture coordinate
-            transform_mat = (loc_mat @ rot_mat @ sca_mat).inverted_safe()
-        elif self.bl_node.vector_type == "POINT":
-            transform_mat = loc_mat @ rot_mat @ sca_mat
-        else:  # node.vector_type in ("VECTOR", "NORMAL")
-            # no translation for vectors
-            transform_mat = rot_mat @ sca_mat
-
-        mat = blender_value_to_string(transform_mat)
-        clamp_min = blender_value_to_string(self.bl_node.min)
-        clamp_max = blender_value_to_string(self.bl_node.max)
-        use_min = 1.0 if self.bl_node.use_min else 0.0
-        use_max = 1.0 if self.bl_node.use_max else 0.0
+        self.local_code.append("// Mapping type: %s" %
+                               self.bl_node.vector_type)
+
+        # In Blender2.80 and before, input location, rotation and scale are
+        # constants. Therefore, the final transform matrix can be compute in
+        # parsing step.
+        # However, starting from Blender2.81, all these inputs are sockets
+        # (which means they can be variables), so the computation has to be
+        # done at shader runtime.
+        if bpy.app.version <= (2, 80, 0):
+            loc_mat = mathutils.Matrix.Translation(self.bl_node.translation)
+            rot_mat = self.bl_node.rotation.to_matrix().to_4x4()
+            sca_mat = mathutils.Matrix((
+                (self.bl_node.scale[0], 0, 0),
+                (0, self.bl_node.scale[1], 0),
+                (0, 0, self.bl_node.scale[2]),
+            )).to_4x4()
+
+            function = find_node_function(self.bl_node)
+            if self.bl_node.vector_type == "TEXTURE":
+                # texture inverse mapping
+                transform_mat = (loc_mat @ rot_mat @ sca_mat).inverted_safe()
+            elif self.bl_node.vector_type == "POINT":
+                transform_mat = loc_mat @ rot_mat @ sca_mat
+            elif self.bl_node.vector_type == "NORMAL":
+                # inverse transpose
+                transform_mat = (rot_mat @ sca_mat).inverted_safe().T
+            else:  # "VECTOR"
+                # no translatio
+                transform_mat = rot_mat @ sca_mat
+            transform_mat = blender_value_to_string(transform_mat)
+
+            clamp_min = blender_value_to_string(self.bl_node.min)
+            clamp_max = blender_value_to_string(self.bl_node.max)
+            use_min = 1.0 if self.bl_node.use_min else 0.0
+            use_max = 1.0 if self.bl_node.use_max else 0.0
+
+            in_arguments = list()
+            in_arguments.append(in_vec)
+            in_arguments.append(transform_mat)
+            in_arguments.append(clamp_min)
+            in_arguments.append(clamp_max)
+            in_arguments.append(use_min)
+            in_arguments.append(use_max)
+
+            self.add_function_call(function, in_arguments, [out_vec])
 
-        in_arguments = list()
-        in_arguments.append(in_vec)
-        in_arguments.append(mat)
-        in_arguments.append(clamp_min)
-        in_arguments.append(clamp_max)
-        in_arguments.append(use_min)
-        in_arguments.append(use_max)
+        else:
+            loc_vec = self.in_sockets_map[self.bl_node.inputs[1]]
+            rot_vec = self.in_sockets_map[self.bl_node.inputs[2]]
+            sca_vec = self.in_sockets_map[self.bl_node.inputs[3]]
+
+            # TODO: for constant inputs, better to convert them to matrix
+            # when exporting
+            loc_mat = self.location_to_mat(loc_vec)
+            rot_mat = self.rotation_to_mat(rot_vec)
+            sca_mat = self.scale_to_mat(sca_vec)
+
+            xform_mat = self.generate_variable_id_str("xform_mat")
+            if self.bl_node.vector_type == "TEXTURE":
+                # texture inverse mapping
+                self.local_code.append("mat4 %s = inverse(%s * %s * %s)" %
+                                       (xform_mat, loc_mat, rot_mat, sca_mat))
+            elif self.bl_node.vector_type == "POINT":
+                self.local_code.append("mat4 %s = %s * %s * %s" %
+                                       (xform_mat, loc_mat, rot_mat, sca_mat))
+            elif self.bl_node.vector_type == "NORMAL":
+                # inverse transpose
+                self.local_code.append("mat4 %s = transpose(inverse(%s * %s))"
+                                       % (xform_mat, rot_mat, sca_mat))
+            else:  # "VECTOR"
+                # no translation
+                self.local_code.append("mat4 %s = %s * %s" %
+                                       (xform_mat, rot_mat, sca_mat))
+            self.local_code.append(
+                "%s = (%s * vec4(%s, 1.0)).xyz;" %
+                (out_vec, xform_mat, in_vec))
 
-        output_socket = self.bl_node.outputs[0]
-        out_vec = self.generate_socket_id_str(output_socket)
         self.out_sockets_map[output_socket] = out_vec
 
-        self.add_function_call(function, in_arguments, [out_vec])
         if self.bl_node.vector_type == "NORMAL":
             # need additonal normalize
+            self.local_code.append("// Normalization for NORMAL mapping")
             self.local_code.append(
                 '%s = normalize(%s)' % (out_vec, out_vec)
             )

+ 33 - 0
io_scene_godot/converters/material/script_shader/shader_functions.py

@@ -833,6 +833,39 @@ void point_space_convert_view_to_world(inout vec3 pos, in mat4 inv_view_mat) {
 void dir_space_convert_world_to_view(inout vec3 dir, in mat4 view_mat) {
     dir = normalize(view_mat * vec4(dir, 0.0)).xyz;
 }
+"""),
+
+    ShaderFunction(code="""
+void location_to_mat4(in vec3 loc, out mat4 loc_mat) {
+    loc_mat = mat4(vec4(1.0, 0.0, 0.0, 0),
+                   vec4(0.0, 1.0, 0.0, 0),
+                   vec4(0.0, 0.0, 1.0, 0),
+                   vec4(loc, 1.0));
+}
+"""),
+
+    ShaderFunction(code="""
+void euler_angle_XYZ_to_mat4(in vec3 rot, out mat4 rot_mat) {
+    mat3 rx = mat3(vec3(1, 0, 0),
+                   vec3(0, cos(rot.x), sin(rot.x)),
+                   vec3(0, -sin(rot.x), cos(rot.x)));
+    mat3 ry = mat3(vec3(cos(rot.y), 0, -sin(rot.y)),
+                   vec3(0, 1, 0),
+                   vec3(sin(rot.y), 0, cos(rot.y)));
+    mat3 rz = mat3(vec3(cos(rot.z), sin(rot.z), 0),
+                   vec3(-sin(rot.z), cos(rot.z), 0),
+                   vec3(0, 0, 1));
+    rot_mat = mat4(rz * ry * rx);
+}
+"""),
+
+    ShaderFunction(code="""
+void scale_to_mat4(in vec3 scale, out mat4 scale_mat) {
+    scale_mat = mat4(vec4(scale.x, 0.0, 0.0, 0.0),
+                     vec4(0.0, scale.y, 0.0, 0.0),
+                     vec4(0.0, 0.0, scale.z, 0.0),
+                     vec4(0.0, 0.0, 0.0, 1.0));
+}
 """),
 
     ShaderFunction(code="""

+ 168 - 60
tests/reference_exports/material_cycle/material_normal.escn

@@ -162,6 +162,28 @@ void dir_space_convert_view_to_model(inout vec3 dir,
 }
 
 
+void euler_angle_XYZ_to_mat4(in vec3 rot, out mat4 rot_mat) {
+    mat3 rx = mat3(vec3(1, 0, 0),
+                   vec3(0, cos(rot.x), sin(rot.x)),
+                   vec3(0, -sin(rot.x), cos(rot.x)));
+    mat3 ry = mat3(vec3(cos(rot.y), 0, -sin(rot.y)),
+                   vec3(0, 1, 0),
+                   vec3(sin(rot.y), 0, cos(rot.y)));
+    mat3 rz = mat3(vec3(cos(rot.z), sin(rot.z), 0),
+                   vec3(-sin(rot.z), cos(rot.z), 0),
+                   vec3(0, 0, 1));
+    rot_mat = mat4(rz * ry * rx);
+}
+
+
+void location_to_mat4(in vec3 loc, out mat4 loc_mat) {
+    loc_mat = mat4(vec4(1.0, 0.0, 0.0, 0),
+                   vec4(0.0, 1.0, 0.0, 0),
+                   vec4(0.0, 0.0, 1.0, 0),
+                   vec4(loc, 1.0));
+}
+
+
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
@@ -170,15 +192,11 @@ void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
 }
 
 
-void node_mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin,
-        float domax, out vec3 outvec) {
-    outvec = (mat * vec4(vec, 1.0)).xyz;
-    if (domin == 1.0) {
-        outvec = max(outvec, minvec);
-    }
-    if (domax == 1.0) {
-        outvec = min(outvec, maxvec);
-    }
+void scale_to_mat4(in vec3 scale, out mat4 scale_mat) {
+    scale_mat = mat4(vec4(scale.x, 0.0, 0.0, 0.0),
+                     vec4(0.0, scale.y, 0.0, 0.0),
+                     vec4(0.0, 0.0, scale.z, 0.0),
+                     vec4(0.0, 0.0, 0.0, 1.0));
 }
 
 
@@ -208,15 +226,23 @@ void fragment () {
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_normal;
+	vec3 node1_in1_location = vec3(6.999999523162842, 0.0, 0.0);
+	vec3 node1_in2_rotation = vec3(0.13613566756248474, -0.16057027876377106,
+		0.14311698079109192);
+	vec3 node1_in3_scale = vec3(1.0, 4.800000190734863, 7.399999618530273);
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	
-	node_mapping(node1_in0_vector, mat4(vec4(0.9770439267158508,
-		-0.033913709223270416, -0.01857101544737816, -0.0), vec4(0.14079418778419495,
-		0.2036508023738861, -0.021205507218837738, 0.0), vec4(0.15988115966320038,
-		0.027910366654396057, 0.13216260075569153, -0.0), vec4(-6.83930778503418,
-		0.23739595711231232, 0.1299971044063568, 1.0)), vec3(0.0, 0.0, 0.0), vec3(1.0,
-		1.0, 1.0), 0.0, 0.0, node1_out0_vector);
+	// Mapping type: TEXTURE
+	mat4 node1_var0_location;
+	location_to_mat4(node1_in1_location, node1_var0_location);
+	mat4 node1_var1_rotation;
+	euler_angle_XYZ_to_mat4(node1_in2_rotation, node1_var1_rotation);
+	mat4 node1_var2_scale;
+	scale_to_mat4(node1_in3_scale, node1_var2_scale);
+	mat4 node1_var3_xform_mat = inverse(node1_var0_location * node1_var1_rotation *
+		node1_var2_scale);
+	node1_out0_vector = (node1_var3_xform_mat * vec4(node1_in0_vector, 1.0)).xyz;
 	
 	
 	// node: 'Diffuse BSDF'
@@ -281,6 +307,28 @@ void dir_space_convert_view_to_model(inout vec3 dir,
 }
 
 
+void euler_angle_XYZ_to_mat4(in vec3 rot, out mat4 rot_mat) {
+    mat3 rx = mat3(vec3(1, 0, 0),
+                   vec3(0, cos(rot.x), sin(rot.x)),
+                   vec3(0, -sin(rot.x), cos(rot.x)));
+    mat3 ry = mat3(vec3(cos(rot.y), 0, -sin(rot.y)),
+                   vec3(0, 1, 0),
+                   vec3(sin(rot.y), 0, cos(rot.y)));
+    mat3 rz = mat3(vec3(cos(rot.z), sin(rot.z), 0),
+                   vec3(-sin(rot.z), cos(rot.z), 0),
+                   vec3(0, 0, 1));
+    rot_mat = mat4(rz * ry * rx);
+}
+
+
+void location_to_mat4(in vec3 loc, out mat4 loc_mat) {
+    loc_mat = mat4(vec4(1.0, 0.0, 0.0, 0),
+                   vec4(0.0, 1.0, 0.0, 0),
+                   vec4(0.0, 0.0, 1.0, 0),
+                   vec4(loc, 1.0));
+}
+
+
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
@@ -289,15 +337,11 @@ void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
 }
 
 
-void node_mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin,
-        float domax, out vec3 outvec) {
-    outvec = (mat * vec4(vec, 1.0)).xyz;
-    if (domin == 1.0) {
-        outvec = max(outvec, minvec);
-    }
-    if (domax == 1.0) {
-        outvec = min(outvec, maxvec);
-    }
+void scale_to_mat4(in vec3 scale, out mat4 scale_mat) {
+    scale_mat = mat4(vec4(scale.x, 0.0, 0.0, 0.0),
+                     vec4(0.0, scale.y, 0.0, 0.0),
+                     vec4(0.0, 0.0, scale.z, 0.0),
+                     vec4(0.0, 0.0, 0.0, 1.0));
 }
 
 
@@ -327,14 +371,21 @@ void fragment () {
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_normal;
+	vec3 node1_in1_location = vec3(0.0, -7.399999141693115, 0.0);
+	vec3 node1_in2_rotation = vec3(0.23038344085216522, 0.14311698079109192, 0.0);
+	vec3 node1_in3_scale = vec3(16.599998474121094, 3.999999761581421, 1.0);
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	
-	node_mapping(node1_in0_vector, mat4(vec4(16.43028450012207, 0.0,
-		-2.3676400184631348, 0.0), vec4(0.13027772307395935, 3.894315481185913,
-		0.9040648937225342, 0.0), vec4(0.13886050879955292, -0.22835084795951843,
-		0.9636252522468567, 0.0), vec4(0.0, 0.0, 0.0, 1.0)), vec3(0.0, 0.0, 0.0),
-		vec3(1.0, 1.0, 1.0), 0.0, 0.0, node1_out0_vector);
+	// Mapping type: VECTOR
+	mat4 node1_var0_location;
+	location_to_mat4(node1_in1_location, node1_var0_location);
+	mat4 node1_var1_rotation;
+	euler_angle_XYZ_to_mat4(node1_in2_rotation, node1_var1_rotation);
+	mat4 node1_var2_scale;
+	scale_to_mat4(node1_in3_scale, node1_var2_scale);
+	mat4 node1_var3_xform_mat = node1_var1_rotation * node1_var2_scale;
+	node1_out0_vector = (node1_var3_xform_mat * vec4(node1_in0_vector, 1.0)).xyz;
 	
 	
 	// node: 'Diffuse BSDF'
@@ -379,6 +430,28 @@ void dir_space_convert_view_to_model(inout vec3 dir,
 }
 
 
+void euler_angle_XYZ_to_mat4(in vec3 rot, out mat4 rot_mat) {
+    mat3 rx = mat3(vec3(1, 0, 0),
+                   vec3(0, cos(rot.x), sin(rot.x)),
+                   vec3(0, -sin(rot.x), cos(rot.x)));
+    mat3 ry = mat3(vec3(cos(rot.y), 0, -sin(rot.y)),
+                   vec3(0, 1, 0),
+                   vec3(sin(rot.y), 0, cos(rot.y)));
+    mat3 rz = mat3(vec3(cos(rot.z), sin(rot.z), 0),
+                   vec3(-sin(rot.z), cos(rot.z), 0),
+                   vec3(0, 0, 1));
+    rot_mat = mat4(rz * ry * rx);
+}
+
+
+void location_to_mat4(in vec3 loc, out mat4 loc_mat) {
+    loc_mat = mat4(vec4(1.0, 0.0, 0.0, 0),
+                   vec4(0.0, 1.0, 0.0, 0),
+                   vec4(0.0, 0.0, 1.0, 0),
+                   vec4(loc, 1.0));
+}
+
+
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
@@ -387,15 +460,11 @@ void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
 }
 
 
-void node_mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin,
-        float domax, out vec3 outvec) {
-    outvec = (mat * vec4(vec, 1.0)).xyz;
-    if (domin == 1.0) {
-        outvec = max(outvec, minvec);
-    }
-    if (domax == 1.0) {
-        outvec = min(outvec, maxvec);
-    }
+void scale_to_mat4(in vec3 scale, out mat4 scale_mat) {
+    scale_mat = mat4(vec4(scale.x, 0.0, 0.0, 0.0),
+                     vec4(0.0, scale.y, 0.0, 0.0),
+                     vec4(0.0, 0.0, scale.z, 0.0),
+                     vec4(0.0, 0.0, 0.0, 1.0));
 }
 
 
@@ -425,13 +494,23 @@ void fragment () {
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_normal;
+	vec3 node1_in1_location = vec3(0.0, 0.0, 0.0);
+	vec3 node1_in2_rotation = vec3(1.5707963705062866, 0.0, 0.0);
+	vec3 node1_in3_scale = vec3(1.0, 1.0, 1.0);
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	
-	node_mapping(node1_in0_vector, mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0,
-		-4.371138828673793e-08, 1.0, 0.0), vec4(0.0, -1.0, -4.371138828673793e-08, 0.0),
-		vec4(0.0, 0.0, 0.0, 1.0)), vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0), 0.0, 0.0,
-		node1_out0_vector);
+	// Mapping type: NORMAL
+	mat4 node1_var0_location;
+	location_to_mat4(node1_in1_location, node1_var0_location);
+	mat4 node1_var1_rotation;
+	euler_angle_XYZ_to_mat4(node1_in2_rotation, node1_var1_rotation);
+	mat4 node1_var2_scale;
+	scale_to_mat4(node1_in3_scale, node1_var2_scale);
+	mat4 node1_var3_xform_mat = transpose(inverse(node1_var1_rotation *
+		node1_var2_scale));
+	node1_out0_vector = (node1_var3_xform_mat * vec4(node1_in0_vector, 1.0)).xyz;
+	// Normalization for NORMAL mapping
 	node1_out0_vector = normalize(node1_out0_vector);
 	
 	
@@ -471,6 +550,28 @@ render_mode blend_mix, depth_draw_always, cull_back, diffuse_burley, specular_sc
 
 
 
+void euler_angle_XYZ_to_mat4(in vec3 rot, out mat4 rot_mat) {
+    mat3 rx = mat3(vec3(1, 0, 0),
+                   vec3(0, cos(rot.x), sin(rot.x)),
+                   vec3(0, -sin(rot.x), cos(rot.x)));
+    mat3 ry = mat3(vec3(cos(rot.y), 0, -sin(rot.y)),
+                   vec3(0, 1, 0),
+                   vec3(sin(rot.y), 0, cos(rot.y)));
+    mat3 rz = mat3(vec3(cos(rot.z), sin(rot.z), 0),
+                   vec3(-sin(rot.z), cos(rot.z), 0),
+                   vec3(0, 0, 1));
+    rot_mat = mat4(rz * ry * rx);
+}
+
+
+void location_to_mat4(in vec3 loc, out mat4 loc_mat) {
+    loc_mat = mat4(vec4(1.0, 0.0, 0.0, 0),
+                   vec4(0.0, 1.0, 0.0, 0),
+                   vec4(0.0, 0.0, 1.0, 0),
+                   vec4(loc, 1.0));
+}
+
+
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
@@ -479,24 +580,20 @@ void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
 }
 
 
-void node_mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin,
-        float domax, out vec3 outvec) {
-    outvec = (mat * vec4(vec, 1.0)).xyz;
-    if (domin == 1.0) {
-        outvec = max(outvec, minvec);
-    }
-    if (domax == 1.0) {
-        outvec = min(outvec, maxvec);
-    }
-}
-
-
 void point_space_convert_view_to_model(inout vec3 pos,
         in mat4 inv_model_mat, in mat4 inv_view_mat) {
     pos = (inv_model_mat * (inv_view_mat * vec4(pos, 1.0))).xyz;
 }
 
 
+void scale_to_mat4(in vec3 scale, out mat4 scale_mat) {
+    scale_mat = mat4(vec4(scale.x, 0.0, 0.0, 0.0),
+                     vec4(0.0, scale.y, 0.0, 0.0),
+                     vec4(0.0, 0.0, scale.z, 0.0),
+                     vec4(0.0, 0.0, 0.0, 1.0));
+}
+
+
 void space_convert_yup_to_zup(inout vec3 dir) {
     dir = mat3(vec3(1, 0, 0), vec3(0, 0, 1), vec3(0, -1, 0)) * dir;
 }
@@ -524,13 +621,22 @@ void fragment () {
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_object;
+	vec3 node1_in1_location = vec3(8.80000114440918, -3.999999761581421, 0.0);
+	vec3 node1_in2_rotation = vec3(1.5707963705062866, 0.0, 0.0);
+	vec3 node1_in3_scale = vec3(14.399999618530273, 1.0, 1.0);
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	
-	node_mapping(node1_in0_vector, mat4(vec4(14.399999618530273, 0.0, 0.0, 0.0),
-		vec4(0.0, -4.371138828673793e-08, 1.0, 0.0), vec4(0.0, -1.0,
-		-4.371138828673793e-08, 0.0), vec4(8.80000114440918, -3.999999761581421, 0.0,
-		1.0)), vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0), 0.0, 0.0, node1_out0_vector);
+	// Mapping type: POINT
+	mat4 node1_var0_location;
+	location_to_mat4(node1_in1_location, node1_var0_location);
+	mat4 node1_var1_rotation;
+	euler_angle_XYZ_to_mat4(node1_in2_rotation, node1_var1_rotation);
+	mat4 node1_var2_scale;
+	scale_to_mat4(node1_in3_scale, node1_var2_scale);
+	mat4 node1_var3_xform_mat = node1_var0_location * node1_var1_rotation *
+		node1_var2_scale;
+	node1_out0_vector = (node1_var3_xform_mat * vec4(node1_in0_vector, 1.0)).xyz;
 	
 	
 	// node: 'Diffuse BSDF'
@@ -1044,12 +1150,14 @@ void fragment () {
 	float node2_in0_strength = float(1.0);
 	float node2_in1_distance = float(0.10000000149011612);
 	float node2_in2_height = dot(node1_out0_color.rgb, vec3(0.2126, 0.7152, 0.0722));
-	vec3 node2_in3_normal = NORMAL;
+	float node2_in3_height_dx = float(1.0);
+	float node2_in4_height_dy = float(1.0);
+	vec3 node2_in5_normal = NORMAL;
 	// output sockets definitions
 	vec3 node2_out0_normal;
 	
 	node_bump(node2_in0_strength, node2_in1_distance, node2_in2_height,
-		node2_in3_normal, VERTEX, 0.0, node2_out0_normal);
+		node2_in5_normal, VERTEX, 0.0, node2_out0_normal);
 	dir_space_convert_view_to_world(node2_out0_normal, INV_VIEW_MAT);
 	space_convert_yup_to_zup(node2_out0_normal);