My method to bake simulations from Blender to Godot

To anyone interested in transfering simulations from Blender to Godot, I made this python script for blender that creates a rig to bake the cloth/liquid simulations to a rig, based on this video.

import bpy
from bpy import context
from mathutils import Vector

def AddEmptiesAtVertices(length):
    objects = bpy.context.view_layer.objects
    obj = objects.active
    coll = bpy.data.collections.new("empties")
    bpy.context.scene.collection.children.link(coll)
    if not obj or obj.type != 'MESH':
        return
    
    empties = []
    for v in obj.data.vertices:
        mt = bpy.data.objects.new(
            f"Vert{v.index}",
            None,
        )
        mt.empty_display_type = 'ARROWS'
        mt.empty_display_size = length
        mt.parent = obj
        mt.parent_type = 'VERTEX'
        mt.parent_vertices = [v.index] * 3
        coll.objects.link(mt)
        empties.append(mt)
    
    return empties
        

def AddBonesAtVertices(length, use_normals, empty_names):
    objects = bpy.context.view_layer.objects
    obj = objects.active
    if not obj or obj.type != 'MESH':
        return

    points = []
    normals = []
    data = []
    for v in obj.data.vertices:
        p = obj.matrix_world @ v.co
        target = v.normal @ obj.matrix_world
        dir = target - p
        dir.normalize()
        dir = dir * length
        n = p + dir * (-1)
        points.append(p)
        if not use_normals:
            n = Vector((p[0], p[1], p[2] + length))
        normals.append(n)

    amt = bpy.data.armatures.new(obj.name + "_vBones")
    rig = bpy.data.objects.new(obj.name + '_vRig', amt)
    
    bpy.context.collection.objects.link(rig)
    objects.active = rig

    bpy.ops.object.editmode_toggle()
    for i, l in enumerate(zip(points, normals)):        
        bone = amt.edit_bones.new(str(i))
        bone.head = l[0]
        bone.tail = l[1]
        
        bpy.ops.object.posemode_toggle()
        pose_bone = bpy.context.object.pose.bones[str(i)]
        bpy.context.object.data.bones.active = pose_bone.bone
        pose_bone.bone.select = True
        constraint = pose_bone.constraints.new("COPY_LOCATION")
        constraint.target = empty_names[i]
        bpy.ops.object.editmode_toggle()
    
    bpy.ops.object.editmode_toggle() 

bpy.ops.object.mode_set(mode='OBJECT')
empties = AddEmptiesAtVertices(0.5)
AddBonesAtVertices(0.5, False, empties)

Once you have the simulation, you run the script having the mesh with the simulation selected. Then it will create a bunch of empties parented to each vertex of the mesh, and a rig with a bone position at each vertex of the rig and with a copy location constraint pointing to their empty counterpart. This way, the rig follows the simulation. Depending on the amount of vertices and the specs of your computer, the script can freeze Blender for a while, be patient!

To bake the simulation to the rig you can go to pose mode, select all the bones, and go to pose > animation > bake action. It will open this menu:

The important setting here is Visual Keying, where the information of the copy location constraint resides. Once baked, voilĂ , you have a rig with an animation doing the simulation that you can export to Godot. I used this method for simulating the sail in a ship:

I still haven’t tested the performance of this method. It creates a rig with as many bones as vertices in the mesh, and the animations can have one keyframe per frame (this one depends on how you bake the action in blender).

2 Likes

Vertex animation textures are better suited to per-vertex animations, though more complicated to export and import. They are often used for groups of animated background characters (due to it’s near zero CPU usage) or baked physics simulations with a high vertex count.

1 Like

This is really cool, thanks for sharing!!!

1 Like

whoa that’s crazy, I didn’t know about texture animations! Could you blend and make a state machine between different texture animations? I have to try! Thanks for sharing!

You could blend VATs through the mix function in a shader. A state machine would have to be done in scripts, and altering the shader unifroms. Certainly a lot of great Godot functionality is lost as you have to make your own shaders, I don’t think it’s standard in any engine considering it can be finicky for every use case.

1 Like