浏览代码

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"""
 """a set of shader node converters responsible for generate"""
 import logging
 import logging
 from collections import deque
 from collections import deque
@@ -19,6 +20,9 @@ def blender_value_to_string(blender_value):
 
 
         return "vec%d(%s)" % (len(tmp), ", ".join(tmp))
         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):
     if isinstance(blender_value, mathutils.Matrix):
         # godot mat is column major order
         # godot mat is column major order
         mat = blender_value.transposed()
         mat = blender_value.transposed()
@@ -109,6 +113,7 @@ class ShadingFlags:
 
 
 class NodeConverterBase:
 class NodeConverterBase:
     # pylint: disable-msg=too-many-instance-attributes
     # pylint: disable-msg=too-many-instance-attributes
+    # pylint: disable-msg=too-many-public-methods
     """helper class which wraps a blender shader node and
     """helper class which wraps a blender shader node and
     able to generate fragment/vertex script from the node"""
     able to generate fragment/vertex script from the node"""
 
 
@@ -323,6 +328,30 @@ class NodeConverterBase:
                 "point_space_convert_world_to_view")
                 "point_space_convert_world_to_view")
         self.add_function_call(function, [var, 'INV_CAMERA_MATRIX'], [])
         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):
     def _initialize_value_in_socket(self, socket, blnode_to_converter_map):
         type_str = socket_to_type_string(socket)
         type_str = socket_to_type_string(socket)
         id_str = self.generate_socket_id_str(socket)
         id_str = self.generate_socket_id_str(socket)
@@ -571,6 +600,8 @@ class BumpNodeConverter(NodeConverterBase):
         in_arguments = list()
         in_arguments = list()
         for socket in self.bl_node.inputs:
         for socket in self.bl_node.inputs:
             socket_var = self.in_sockets_map[socket]
             socket_var = self.in_sockets_map[socket]
+            if socket.name in ('Height_dx', 'Height_dy'):
+                continue
             if socket.name == 'Normal' and socket.is_linked:
             if socket.name == 'Normal' and socket.is_linked:
                 self.zup_to_yup(socket_var)
                 self.zup_to_yup(socket_var)
                 self.world_to_view(socket_var)
                 self.world_to_view(socket_var)
@@ -788,50 +819,95 @@ class ImageTextureNodeConverter(NodeConverterBase):
 class MappingNodeConverter(NodeConverterBase):
 class MappingNodeConverter(NodeConverterBase):
     """Converter for ShaderNodeMapping"""
     """Converter for ShaderNodeMapping"""
 
 
+    # pylint: disable-msg=too-many-statements
     def parse_node_to_fragment(self):
     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]]
         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.out_sockets_map[output_socket] = out_vec
 
 
-        self.add_function_call(function, in_arguments, [out_vec])
         if self.bl_node.vector_type == "NORMAL":
         if self.bl_node.vector_type == "NORMAL":
             # need additonal normalize
             # need additonal normalize
+            self.local_code.append("// Normalization for NORMAL mapping")
             self.local_code.append(
             self.local_code.append(
                 '%s = normalize(%s)' % (out_vec, out_vec)
                 '%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) {
 void dir_space_convert_world_to_view(inout vec3 dir, in mat4 view_mat) {
     dir = normalize(view_mat * vec4(dir, 0.0)).xyz;
     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="""
     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,
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
     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'
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_normal;
 	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
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	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'
 	// 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,
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
     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'
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_normal;
 	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
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	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'
 	// 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,
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
     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'
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_normal;
 	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
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	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);
 	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,
 void node_bsdf_diffuse(vec4 color, float roughness, out vec3 albedo,
         out float specular_out, out float oren_nayar_roughness_out) {
         out float specular_out, out float oren_nayar_roughness_out) {
     albedo = color.rgb;
     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,
 void point_space_convert_view_to_model(inout vec3 pos,
         in mat4 inv_model_mat, in mat4 inv_view_mat) {
         in mat4 inv_model_mat, in mat4 inv_view_mat) {
     pos = (inv_model_mat * (inv_view_mat * vec4(pos, 1.0))).xyz;
     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) {
 void space_convert_yup_to_zup(inout vec3 dir) {
     dir = mat3(vec3(1, 0, 0), vec3(0, 0, 1), vec3(0, -1, 0)) * dir;
     dir = mat3(vec3(1, 0, 0), vec3(0, 0, 1), vec3(0, -1, 0)) * dir;
 }
 }
@@ -524,13 +621,22 @@ void fragment () {
 	// type: 'ShaderNodeMapping'
 	// type: 'ShaderNodeMapping'
 	// input sockets handling
 	// input sockets handling
 	vec3 node1_in0_vector = node0_out0_object;
 	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
 	// output sockets definitions
 	vec3 node1_out0_vector;
 	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'
 	// node: 'Diffuse BSDF'
@@ -1044,12 +1150,14 @@ void fragment () {
 	float node2_in0_strength = float(1.0);
 	float node2_in0_strength = float(1.0);
 	float node2_in1_distance = float(0.10000000149011612);
 	float node2_in1_distance = float(0.10000000149011612);
 	float node2_in2_height = dot(node1_out0_color.rgb, vec3(0.2126, 0.7152, 0.0722));
 	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
 	// output sockets definitions
 	vec3 node2_out0_normal;
 	vec3 node2_out0_normal;
 	
 	
 	node_bump(node2_in0_strength, node2_in1_distance, node2_in2_height,
 	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);
 	dir_space_convert_view_to_world(node2_out0_normal, INV_VIEW_MAT);
 	space_convert_yup_to_zup(node2_out0_normal);
 	space_convert_yup_to_zup(node2_out0_normal);