godotengine / godot-blender-exporter

Addon for Blender to directly export to a Godot Scene
GNU General Public License v2.0
1.16k stars 132 forks source link

Blender 2.81: AttributeError: 'ShaderNodeMapping' object has no attribute 'rotation' #292

Open akien-mga opened 4 years ago

akien-mga commented 4 years ago

OS: Linux

Godot version: Not used, test failure.

Blender version: 2.81 (stable)

Issue description: The current test suite fails first due to the change in arguments for mesh.update(), which #284 fixes.

After fixing that, another error comes up:

Exporting /home/akien/Projects/godot/godot-blender-exporter/tests/test_scenes/material_cycle/material_normal.blend
Read blend: /home/akien/Projects/godot/godot-blender-exporter/tests/test_scenes/./material_cycle/material_normal.blend
[INFO]: Found Godot project directory at /home/akien/Projects/godot/godot-blender-exporter/tests/godot_project
[INFO]: Exporting scene: Scene
[INFO]: Exporting 10 objects
[INFO]: Exporting Blender object: test_normal_tangent
[INFO]: Exporting Blender object: test_mapping_vector
Traceback (most recent call last):
  File "/home/akien/Projects/godot/godot-blender-exporter/./tests/export_test_scenes.py", line 62, in run_with_abort
    function()
  File "/home/akien/Projects/godot/godot-blender-exporter/./tests/export_test_scenes.py", line 53, in main
    export_escn(out_path, config)
  File "/home/akien/Projects/godot/godot-blender-exporter/./tests/export_test_scenes.py", line 15, in export_escn
    io_scene_godot.export(out_file, config)
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/__init__.py", line 272, in export
    export_godot.save(FakeOp(), bpy.context, filename, **default_settings)
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/export_godot.py", line 318, in save
    exp.export()
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/export_godot.py", line 267, in export
    self.export_scene()
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/export_godot.py", line 211, in export_scene
    self.export_object(obj, root_gd_node)
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/export_godot.py", line 123, in export_object
    parent_gd_node)
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/mesh.py", line 45, in export_mesh_node
    mesh_id = mesh_exporter.export_mesh(escn_file, export_settings)
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/mesh.py", line 175, in export_mesh
    mesh
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/mesh.py", line 288, in generate_surfaces
    mat
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/material/material.py", line 53, in export_material
    escn_file, export_settings, bl_object, material
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/material/material.py", line 84, in generate_material_resource
    escn_file, export_settings, bl_object, material, mat
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/material/script_shader/node_tree.py", line 518, in export_script_shader
    shader_node_tree)
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/material/script_shader/node_tree.py", line 456, in parse_shader_node_tree
    converter.parse_node_to_fragment()
  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/material/script_shader/node_converters.py", line 793, in parse_node_to_fragment
    rot_mat = self.bl_node.rotation.to_matrix().to_4x4()
AttributeError: 'ShaderNodeMapping' object has no attribute 'rotation'

Minimal reproduction project: Run make all with Blender 2.81.

akien-mga commented 4 years ago

This is caused by https://developer.blender.org/rBbaaa89a0bc54a659f9ddbc34cce21d6920c0f6a6

Here's an example of a later fix to affected code in node shader utils: https://developer.blender.org/D5693

Doing the same changes for the transform properties works fine, but then there's the problem of min/max being outright removed, and I'm not familiar enough with this code yet to know how to handle it.

Changes I tried so far:

diff --git a/io_scene_godot/converters/material/script_shader/node_converters.py b/io_scene_godot/converters/material/script_shader/node_converters.py
index 2e79538..d66b811 100644
--- a/io_scene_godot/converters/material/script_shader/node_converters.py
+++ b/io_scene_godot/converters/material/script_shader/node_converters.py
@@ -790,12 +790,13 @@ class MappingNodeConverter(NodeConverterBase):
     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)
+        rot_mat = self.bl_node.inputs['Rotation'].default_value.to_matrix().to_4x4()
+        loc_mat = mathutils.Matrix.Translation(self.bl_node.inputs['Location'].default_value)
+        bl_node_sca = self.bl_node.inputs['Scale'].default_value
         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]),
+            (bl_node_sca[0], 0, 0),
+            (0, bl_node_sca[1], 0),
+            (0, 0, bl_node_sca[2]),
         )).to_4x4()

         in_vec = self.in_sockets_map[self.bl_node.inputs[0]]

Follow-up error:

  File "/home/akien/.config/blender/2.81/scripts/addons/io_scene_godot/converters/material/script_shader/node_converters.py", line 815, in parse_node_to_fragment
    clamp_min = blender_value_to_string(self.bl_node.min)
AttributeError: 'ShaderNodeMapping' object has no attribute 'min'
akien-mga commented 4 years ago

Edit: Improved patch to also update the node_mapping signature accordingly.

Simply removing the min and max stuff seems to make things export fine, though I'm not sure if the in_arguments now have all entries required by the node function. Edit: Fixed signature.

diff --git a/io_scene_godot/converters/material/script_shader/node_converters.py b/io_scene_godot/converters/material/script_shader/node_converters.py
index 2e79538..7d14174 100644
--- a/io_scene_godot/converters/material/script_shader/node_converters.py
+++ b/io_scene_godot/converters/material/script_shader/node_converters.py
@@ -790,12 +790,13 @@ class MappingNodeConverter(NodeConverterBase):
     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)
+        rot_mat = self.bl_node.inputs['Rotation'].default_value.to_matrix().to_4x4()
+        loc_mat = mathutils.Matrix.Translation(self.bl_node.inputs['Location'].default_value)
+        bl_node_sca = self.bl_node.inputs['Scale'].default_value
         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]),
+            (bl_node_sca[0], 0, 0),
+            (0, bl_node_sca[1], 0),
+            (0, 0, bl_node_sca[2]),
         )).to_4x4()

         in_vec = self.in_sockets_map[self.bl_node.inputs[0]]
@@ -811,18 +812,10 @@ class MappingNodeConverter(NodeConverterBase):
             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

         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)

         output_socket = self.bl_node.outputs[0]
         out_vec = self.generate_socket_id_str(output_socket)
diff --git a/io_scene_godot/converters/material/script_shader/shader_functions.py b/io_scene_godot/converters/material/script_shader/shader_functions.py
index fc40eac..c7f24b9 100644
--- a/io_scene_godot/converters/material/script_shader/shader_functions.py
+++ b/io_scene_godot/converters/material/script_shader/shader_functions.py
@@ -401,15 +401,8 @@ void node_gamma(vec4 color, float gamma, out vec4 out_color) {
 """),

     ShaderFunction(code="""
-void node_mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin,
-        float domax, out vec3 outvec) {
+void node_mapping(vec3 vec, mat4 mat, 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);
-    }
 }
 """),

diff --git a/io_scene_godot/converters/utils.py b/io_scene_godot/converters/utils.py
index ced196e..d0325e3 100644
--- a/io_scene_godot/converters/utils.py
+++ b/io_scene_godot/converters/utils.py
@@ -39,8 +39,10 @@ def triangulate_mesh(mesh):
         tri_mesh, faces=tri_mesh.faces, quad_method="ALTERNATE")
     tri_mesh.to_mesh(mesh)
     tri_mesh.free()
-
-    mesh.update(calc_loop_triangles=True)
+    if bpy.app.version[1] > 80:
+        mesh.update()
+    else:
+        mesh.update(calc_loop_triangles=True)

 class MeshResourceKey:

The export comparison then fails due to those changes, but this might be the expected outcome:

diff -aur -x '*.escn.import' -r tests/godot_project/exports/material_cycle/material_normal.escn tests/reference_exports/material_cycle/material_normal.escn
--- tests/godot_project/exports/material_cycle/material_normal.escn     2019-11-22 13:52:16.155042000 +0100
+++ tests/reference_exports/material_cycle/material_normal.escn 2019-11-22 13:26:23.935001073 +0100
@@ -170,8 +170,15 @@
 }

-void node_mapping(vec3 vec, mat4 mat, out vec3 outvec) {
+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);
+    }
 }

@@ -201,10 +208,6 @@
        // 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 = float(<Euler (x=0.1361, y=-0.1606, z=0.1431),
-               order='XYZ'>);
-       vec3 node1_in3_scale = vec3(1.0, 4.800000190734863, 7.399999618530273);
        // output sockets definitions
        vec3 node1_out0_vector;

@@ -212,7 +215,8 @@
                -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)), node1_out0_vector);
+               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);

        // node: 'Diffuse BSDF'
@@ -285,8 +289,15 @@
 }

-void node_mapping(vec3 vec, mat4 mat, out vec3 outvec) {
+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);
+    }
 }

@@ -316,17 +327,14 @@
        // 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 = float(<Euler (x=0.2304, y=0.1431, z=0.0000),
-               order='XYZ'>);
-       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)), node1_out0_vector);
+               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);

        // node: 'Diffuse BSDF'
@@ -379,8 +387,15 @@
 }

-void node_mapping(vec3 vec, mat4 mat, out vec3 outvec) {
+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);
+    }
 }

@@ -410,16 +425,13 @@
        // 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 = float(<Euler (x=1.5708, y=0.0000, z=0.0000),
-               order='XYZ'>);
-       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)), node1_out0_vector);
+               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);
        node1_out0_vector = normalize(node1_out0_vector);

@@ -467,8 +479,15 @@
 }

-void node_mapping(vec3 vec, mat4 mat, out vec3 outvec) {
+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);
+    }
 }

@@ -505,17 +524,13 @@
        // 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 = float(<Euler (x=1.5708, y=0.0000, z=0.0000),
-               order='XYZ'>);
-       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)), node1_out0_vector);
+               1.0)), vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0), 0.0, 0.0, node1_out0_vector);

        // node: 'Diffuse BSDF'
@@ -1029,15 +1044,12 @@
        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));
-       float node2_in3_height_dx = float(1.0);
-       float node2_in4_height_dy = float(1.0);
-       vec3 node2_in5_normal = NORMAL;
+       vec3 node2_in3_normal = NORMAL;
        // output sockets definitions
        vec3 node2_out0_normal;

        node_bump(node2_in0_strength, node2_in1_distance, node2_in2_height,
-               node2_in3_height_dx, node2_in4_height_dy, node2_in5_normal, VERTEX, 0.0,
-               node2_out0_normal);
+               node2_in3_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);
DimitriyPS commented 4 years ago

I tried to export from Blender 2.81 just a model, disabled the export of materials, but it was not successful. The exporter only works at 2.80.