tefusion / godot-subdiv

Fast Subdivision in Godot with opensubdiv
https://godotengine.org/asset-library/asset/1488
MIT License
46 stars 1 forks source link

Add BlendShapes #8

Closed fire closed 2 years ago

fire commented 2 years ago

Design required.

tefusion commented 2 years ago

My plan for that currently is to cache a copy of the vertex array and the current blend shape values within the QuadMesh that would only get updated by blendshapes and used by skinning. I wrote something like that some time ago in gdscript and it worked quite well for me to when a blendshape value changes unapply the last one and then apply the new one after. Don't know if that's a good solution though.

tefusion commented 2 years ago

Added like that in fcbe43bb2a3b19cb093b17d8eb525768eb21e612

There's still some things missing though. A big problem is reloading the scene won't load in the values again (they do get saved, maybe I'm just missing a function).

fire commented 2 years ago

Can test https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/AnimatedMorphCube

fire commented 2 years ago

It's normal that values on the mesh that aren't in an animation is lost.

fire commented 2 years ago

That glb crashes.
AnimatedMorphCube.zip

tefusion commented 2 years ago

That glb crashes. AnimatedMorphCube.zip

Not a blend shape issue, forgot to handle meshes without uv's (uv array is null)

fire commented 2 years ago

Blend shape animation failure with test cases. The plate is normal. Subdiv 2.

image

godot-subdiv_main.zip

Appearance of a working import. (ignore the plate)

image

tefusion commented 2 years ago

Thanks for giving some examples! Animations are likely not working because animation player differentiates between blend shape tracks and non blend shape tracks.

One can fix this by calling a simple script that creates value tracks for all BlendShape tracks, I'll probably add this to the importer.

for animation_library_name in get_animation_library_list():
var anim_lib:AnimationLibrary=get_animation_library(animation_library_name)
for animation_name in anim_lib.get_animation_list():
    var animation: Animation=anim_lib.get_animation(animation_name)
    for track_idx in range(0, animation.get_track_count()):
        if animation.track_get_type(track_idx)==Animation.TYPE_BLEND_SHAPE:
            var fake_anim=animation.add_track(Animation.TYPE_VALUE)
            animation.track_set_path(fake_anim, animation.track_get_path(track_idx))
            for key_idx in range(0, animation.track_get_key_count(track_idx)):
                var val=animation.track_get_key_value(track_idx, key_idx)
                var time=animation.track_get_key_time(track_idx, key_idx)
                var transition=animation.track_get_key_transition(track_idx, key_idx)
                animation.track_insert_key(fake_anim, time, val, transition)
            animation.track_swap(track_idx, fake_anim)
            animation.remove_track(fake_anim)

The reason this is an issue is because blend shapes aren't actual blend shapes in this. If the set_blend_shape_value is overrideable (I don't think they are) this wouldn't be an issue..

fire commented 2 years ago

I can propose set_blend_shape_value to be override able.

Are there any other requests?

fire commented 2 years ago

Here are the two apis. https://docs.godotengine.org/en/latest/classes/class_meshinstance3d.html and https://docs.godotengine.org/en/latest/classes/class_importermeshinstance3d.html

MeshInstance3D ImporterMeshInstance3D
set_mesh(value) set_mesh(value)
get_mesh() get_mesh()
set_skeleton_path(value) set_skeleton_path(value)
get_skeleton_path() get_skeleton_path()
set_skin(value) set_skin(value)
get_skin() get_skin()
void create_convex_collision ( bool clean=true, bool simplify=false )
void create_debug_tangents ( )
void create_multiple_convex_collisions ( )
void create_trimesh_collision ( )
int find_blend_shape_by_name ( StringName name )
get_active_material ( int surface ) const
get_blend_shape_count ( ) const
get_blend_shape_value ( int blend_shape_idx ) const
get_surface_override_material ( int surface ) const
int get_surface_override_material_count ( ) const
void set_blend_shape_value ( int blend_shape_idx, float value )
void set_surface_override_material ( int surface, Material material )
tefusion commented 2 years ago

I can propose set_blend_shape_value to be override able.

Are there any other requests?

That'd be great! I think to make it work with AnimationPlayer BlendShape tracks the functions find_blend_shape_by_name and set_blend_shape_value are necessary. The two getters for count and value would be nice but not really needed for this.

fire commented 2 years ago

I have bound all the methods in MeshInstance3D, ImporterMeshInstance3D, and ImporterMesh. PR and proposal in a bit.

fire commented 2 years ago

As far as I know they should already be exposed... will photo a photo

tefusion commented 2 years ago

As far as I know they should already be exposed... will photo a photo

ah great you included "as virtual methods". They already are overridable the actual change would be to make them virtual to allow giving custom values to calls like this: https://github.com/godotengine/godot/blob/61644f1dbe5389ed02a13f0940b05699db645919/scene/animation/animation_player.cpp#L309 where the node gets casted to MeshInstance

fire commented 2 years ago

can you reply in the proposal?

fire commented 2 years ago

I think you got this to work.

tefusion commented 2 years ago

I think you got this to work.

I was able to get blend shapes working as virtuals in https://github.com/tefusion/godot/commit/b7950af5171493dee483ec7780381f329e5d364a, but trying to get everything else working with MeshInstance3D was still too tedious with many workarounds everywhere to the point of giving up. To make it less tedious set_mesh would also need to be virtual, but then some internal stuff doesn't get set or the skeleton access etc.. For the first release to the asset lib of this SubdivMeshInstance3D will just be a GeometryInstance. We should probably add that quick converter script to the importer for animation tracks then. (The only loss of not inheriting from MeshInstance3D then is the EditorPlugin)

tefusion commented 2 years ago

But yeah blend shapes mostly work now, I'll open another issue for the meshinstance extension in here and maybe keep a tracker of what would be needed there.