Browse Source

Export Curve objects as Godot Path nodes. (#380)

* Export Curve objects as Godot Path nodes.

Fixes #330.
Relates to godotengine/godot-proposals#527.

Previously, curves in blender were exported to meshes in Godot.

Now, a bezier curve created in blender will be exported as a Path node
with a Curve3D resource matching the blender data. The curve will have a
child MeshInstance that renders the bevel.

Only bezier curves are exported to Godot Path nodes. Other curves, such
as Nurbs, export only as meshes as they did previously.

* Export all splines but only assign the active one.

* Remove curve test scenes for now.

They are generated with too recent of a blender version. We'll add them
again after bumping the blender CI version.

* Fix pylint warnings.
Ryan Roden-Corrent 4 năm trước cách đây
mục cha
commit
3e66e12d7c

+ 1 - 1
io_scene_godot/converters/__init__.py

@@ -30,7 +30,7 @@ BLENDER_TYPE_TO_EXPORTER = {
     "CAMERA": export_camera_node,
     "LIGHT": export_light_node,
     "EMPTY": export_empty_node,
-    "CURVE": export_mesh_node,
+    "CURVE": export_curve_node,
     "SURFACE": export_mesh_node,
     "META": export_mesh_node,
     "FONT": export_mesh_node

+ 66 - 2
io_scene_godot/converters/simple_nodes.py

@@ -3,12 +3,15 @@ Any exporters that can be written in a single function can go in here.
 Anything more complex should go in it's own file
 """
 
-import math
 import logging
+import math
+import mathutils
 from ..structures import (
-    NodeTemplate, fix_directional_transform, gamma_correct
+    NodeTemplate, fix_directional_transform, gamma_correct, InternalResource,
+    Map, Array
 )
 from .animation import export_animation_data, AttributeConvertInfo
+from .mesh import export_mesh_node
 
 
 def export_empty_node(escn_file, export_settings, node, parent_gd_node):
@@ -165,3 +168,64 @@ def export_light_node(escn_file, export_settings, node, parent_gd_node):
                           light_node, node.data, 'light')
 
     return light_node
+
+
+def _export_spline(escn_file, spline, name):
+    points = Array("PoolVector3Array(")
+    tilts = Array("PoolRealArray(")
+    axis_correct = mathutils.Matrix((
+        (1, 0, 0),  # X in blender is  X in Godot
+        (0, 0, -1),  # Y in blender is -Z in Godot
+        (0, 1, 0),  # Z in blender is  Y in Godot
+    )).normalized()
+
+    src_points = spline.bezier_points
+    if spline.use_cyclic_u:
+        # Godot fakes a closed path by adding the start point at the end
+        # https://github.com/godotengine/godot-proposals/issues/527
+        src_points = [*src_points, src_points[0]]
+
+    for point in src_points:
+        # blender handles are absolute
+        # godot handles are relative to the control point
+        points.extend((point.handle_left - point.co) @ axis_correct)
+        points.extend((point.handle_right - point.co) @ axis_correct)
+        points.extend(point.co @ axis_correct)
+        tilts.append(point.tilt)
+
+    data = Map()
+    data["points"] = points
+    data["tilts"] = tilts
+
+    curve_resource = InternalResource("Curve3D", name)
+    curve_resource["_data"] = data
+    curve_id = escn_file.get_internal_resource(spline)
+    if curve_id is None:
+        return escn_file.add_internal_resource(curve_resource, spline)
+    return escn_file.get_internal_resource(spline)
+
+
+def export_curve_node(escn_file, export_settings, node, parent_gd_node):
+    """Export a curve to a Path node, with a child mesh."""
+    splines = node.data.splines
+
+    path_node = NodeTemplate(node.name, "Path", parent_gd_node)
+    path_node["transform"] = node.matrix_local
+    escn_file.add_node(path_node)
+
+    for spline in splines:
+        # https://docs.blender.org/manual/en/latest/modeling/curves/editing/curve.html#set-spline-type
+        # Godot only supports bezier, and blender cannot convert losslessly
+        if spline.type == "BEZIER":
+            curve_id = _export_spline(escn_file, splines[0], node.data.name)
+            if spline == splines.active:
+                path_node["curve"] = "SubResource({})".format(curve_id)
+
+        # Create child MeshInstance renders the bevel for any curve type
+        mesh_node = export_mesh_node(
+            escn_file, export_settings, node, path_node
+        )
+        # The transform is already set on the path, don't duplicate it
+        mesh_node["transform"] = mathutils.Matrix.Identity(4)
+
+    return path_node