Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to apply blendshapes and generate a MeshInstance #24

Closed
Tracked by #63198
Lexpartizan opened this issue Sep 5, 2019 · 61 comments
Closed
Tracked by #63198

Add an option to apply blendshapes and generate a MeshInstance #24

Lexpartizan opened this issue Sep 5, 2019 · 61 comments

Comments

@Lexpartizan
Copy link

Lexpartizan commented Sep 5, 2019

Describe the project you are working on:

I trying make in-game character generator for godot from project MakeHuman. Like Skyrim or Fallout 3-4.
https://github.com/Lexpartizan/Go_MakeHuman_dot/
https://www.youtube.com/watch?v=cPVjNh2Ki4I
I make blend-file with one model with 200+ shapekeys. Importing to Godot.
I need setup blendshapes value and customize the appearance of the character.
I can this and on my github page have godot project with this example.

Describe how this feature / enhancement will help your project:

Then applying all shapes and generate MeshInstance without blend_shapes, because file with blendshapes for each character takes up a lot of memory space.

Mesh after import to Godot with all shapekeys- 100 Mb.
But, you need make resource local for different characters.
1 character on screen - 100 Mb video-memory. This is only vertex - memory.
10 character on screen - 1Gb video-memory.
Without blendshapes - 1 character only 2,5 Mb. Zombie rush possible! And each zombie unique.
AAA-feature with one small function.

And i dont know how make that. I don't even know if this is possible.
So, this feature request.
I think the character generator is a very important part of many role-playing games and its effective implementation it just depends on whether it is possible to apply shapekeys and get ready a small version of this mesh. Inefficient it is already working and can be used in games with a small number of characters in the frame, for example in fighting games.
I can make this in blender, but for in-game character generator this must be maked via code.
I asked this question on forums, discord, Q&A, etc and did not get an answer.

Is there a reason why this should be core and not an add-on in the asset library?:
Because this is the basic function for working with the mesh. And other functions to work with blendshape already have.

If this enhancement will not be used often, can it be worked around with a few lines of script?:
That's possible. So I want to know these lines ;-).

Now I have the nerve to ask a question already on a github. Sorry for that. And sorry for my english. I hope you could understand the problems from this vague description.

@Lexpartizan Lexpartizan changed the title Applying shapekeys and generate MeshIntance. Applying blendshapes and generate MeshIntance. Sep 5, 2019
@fire
Copy link
Member

fire commented Sep 5, 2019

I'm having a hard time understanding your request.

  1. Are blend shapes are expensive memory wise? We have 4/6/8 gb video cards and smaller amounts for mobile.
  2. In 3.1, blend shapes are expensive on the gpu. There's patches incoming for performance and for blend shape freezing if blend shape is unchanged.
  3. In a character generator saving the blend shape to a mesh is probably the most efficient way to save memory. At this level you can save each of the meshes directly with the interpolated vertex value.
  4. There are special techniques for crowds that Godot doesn't have

@Lexpartizan
Copy link
Author

I'm having a hard time understanding your request.
Sorry for this. English not my language.

  1. I have 2 Gb videomemory. And many other users too. f it were random access memory, I would not worry. She's cheap. But video cards cost unbelievable money now.
  2. Glad to hear that.
  3. Thats exactly what i want in this proposal. How to do this in code?

@nathanfranke
Copy link
Contributor

nathanfranke commented Sep 5, 2019

If this could be solved with just a few lines of code, why not implement such a function into one of the mesh classes. This would not effect performance at all for those who don't use it.

@Lexpartizan
Copy link
Author

So you can give me this few lines of code?
I would be very grateful.
I really need this very much.

@Lexpartizan
Copy link
Author

I think that the engine is already building the surface I need (How else would a 3D model be displayed from a blendshapes?), but I need a function so that I can get the resulting mesh.

@nathanfranke
Copy link
Contributor

So you can give me this few lines of code?
I would be very grateful.
I really need this very much.

I am going by the idea that this could be solved by a script. Sorry, I don't actually know how to do it. Good luck though, keep researching

@fire
Copy link
Member

fire commented Sep 5, 2019

A possible design could be this:

  • Limited to non-mobile editor platforms because of problems fetching the mesh data from the GPU
  • Supply the list of blend shape indexes to merge and which ones to copy
  • Copy the original mesh
  • Take the blend shape at a linear interpolated value between 0 and 1
  • Merge all the target blend shapes to one blend shape
  • Copy the untouched blend shapes to the mesh instance
  • Save the output as another MeshInstance

@Lexpartizan
Copy link
Author

my "research" did not lead to anything. Not my level programming.
However, I did a lot of boring work to translate most of Makehuman project into a Godot. This work relates more to blender and modeling than to programming. And I think that the character generator (open source) would be useful to the whole community, not just me. But I’m stuck with this optimization, which limits this character editor too much. It would be a shame to throw all the work to the dump when you need only a few lines of code, one function.
So I turn to the community for help.
I'm going to go in for clothes for the characters, but that doesn't make sense if two characters eat up all of the available video memory.
Therefore, I VERY need help with this.

@Lexpartizan
Copy link
Author

Merge all the target blend shapes to one blend shape

How make this in godot?
I know how to do this in theory. I know how to do it in Blender.

But I don’t know how to do this in a godot with code.

@fire
Copy link
Member

fire commented Sep 5, 2019

https://github.com/godotengine/godot/blob/34d74840396853f561964c3f4f6e56ac63a57640/scene/resources/surface_tool.cpp#L772

This is for the one blend shape and will get the blend shape mesh. Once you have the blend mesh and the original mesh, you can read the vertexes and linear interpolate with the blend value between 0.0 and 1.0.

https://docs.godotengine.org/en/3.1/classes/class_@gdscript.html#class-gdscript-method-lerp

Break up the three components of the position. Use lerp ( target_mesh_float, blend_shape_float, blend_weight ) over all the vertex locations.

Edited:

https://docs.godotengine.org/en/latest/classes/class_mesh.html#class-mesh-method-surface-get-blend-shape-arrays

@fire fire changed the title Applying blendshapes and generate MeshIntance. Applying blendshapes and generate MeshInstance. Sep 5, 2019
@Lexpartizan
Copy link
Author

Thank you, you gave me something to think about. Yeah, that makes sense. Although I still don't understand how to work with vertices. Not my level. So help is still needed.

@slapin
Copy link

slapin commented Sep 6, 2019

Well, it is possible to do just in plain gdscript. See my repository at https://github.com/gamedev-kindness/make-target
This basically shows why things like this are better implemented in engine as C++ - it is very hard to make them run at adequate speeds. It is just a bit too slow.

What you generally do

  1. Find vertex differencies between base mesh and blend shapes (see ArrayMesh documentation for details or ping me on discord or look at code in the above repo for reference).
  2. Generate texture using UV coordinates as triangle vertices and vertex difference value as color.
  3. In viewer apply the difference to vertex coodrinate (multiply by modifier value).

The problem is that there is no way to modify ArrayMesh vertices en masse with sparce indices - i.e. supplying array of indices and array of deltas and modify mesh in one shot in most effective way. I think this is what mostly needed for the solution to succeed.

@Lexpartizan
Copy link
Author

@slapin
I don't really understand how to generate UV texture and how to work with colors in it. Also, I think the offset and vertex recalculation of each frame in the viewport will have a negative impact on performance. I will try a couple of weeks, looking at Your code, start working with vertices and get some result on my own. But I will definitely address you on discord (especially since You speak Russian). I understand You're working on a similar project.

@slapin
Copy link

slapin commented Sep 7, 2019 via email

@slapin
Copy link

slapin commented Sep 7, 2019

This proposal explains technical dependency to make proper character customization editors: #41

@Lexpartizan
Copy link
Author

I have some progress witn that.
I followed @fire 's advice and looked into @slapin 's code. Now I got a Mesh without blendshapes, until I checked how things are with UV textures and normals. But it's a big step for me. And Yes, there are very few lines of code.
I hope that tomorrow a little bit will straighten him out, of commentary and lay here.
I'm only going to save the value of the keys for each character, and when a character appears on scene he generates a mesh for himself, which is not saved anywhere, but simply hangs in memory until the character is removed from the scene.

@slapin
Copy link

slapin commented Sep 7, 2019

Would be nice if #41 would be added to core, that would save a lot of trouble. Please vote for it on the go.
@fire thanks

@Lexpartizan
Copy link
Author

Oh yeah, thank you so much to everyone who helped me with this. Especially, @fire and @slapin

@golddotasksquestions
Copy link

And I think that the character generator (open source) would be useful to the whole community, not just me.

Are you aware of this project:
https://github.com/Grumoth/godot-character-creator
https://www.youtube.com/watch?v=uowc04bAKPg&list=PL1x_Sm7RYv5fHdlsmnGPt2hYEh2wI8Cwv&index=1

@Lexpartizan
Copy link
Author

@golddotasksquestions,
No, thanks for information. Good generator! Download and watch his code tomorrow.
I trying just make Makehuman for Godot.

@slapin
Copy link

slapin commented Sep 9, 2019 via email

@Lexpartizan
Copy link
Author

Lexpartizan commented Sep 9, 2019

Is there any way to get ArrayMesh with a regular array with vertices, UV coordinates and so on? From them you can build ArrayMesh, but I would just like to read these values. I use MeshDataTool now, but it is too slow. I would like to get a regular array of vertices and work with them. And then create a new ArrayMesh. Now i have 50 different characters on the screen and 60 frames per second. Video Memory consumption= 35 MB. But I want a faster way to create character.
In addition, there is one small bug. When I use the mesh in the scene, but he's laying there just as the data (I read blendshapes from this) and the screen is not displayed, it still consumes the VideoMemory (VideoMemory, not RAM!), so I should just reset this value.

var mdt = MeshDataTool.new()
mdt.create_from_surface(load(basis_mesh), 0)
for i in range(mdt.get_vertex_count()):
	var vertex = mdt.get_vertex(i)
	mdt.set_vertex(i, Vector3 (lerp (vertex.x, blendshp[shape1][0][i].x,ix),lerp (vertex.y, blendshp[shape1][0][i].y,ix),lerp (vertex.z,blendshp[shape1][0][i].z,ix)))
mesh=Mesh.new()
mdt.commit_to_surface(mesh)

Sorry. I already found surface_get_arrays ( int surf_idx ) Thanks!
This function was in Mesh, not ArrayMesh.

@slapin
Copy link

slapin commented Sep 9, 2019 via email

@Lexpartizan
Copy link
Author

Yes, i dont use meshes.
This, by the way, gives opportunity not use blendshapes foe GLES2.
surface_get_arrays() - in Mesh doc, not ArrayMesh doc. That's why I didn't find her right away.

@Lexpartizan
Copy link
Author

Lexpartizan commented Sep 10, 2019

So slow!

for i in range(size_vertex_arr):
		basis_mesh[Mesh.ARRAY_VERTEX][i].x=lerp (basis_mesh[Mesh.ARRAY_VERTEX][i].x, blendshp["blndshp"][name_shp][0][i].x, value)
		basis_mesh[Mesh.ARRAY_VERTEX][i].y=lerp (basis_mesh[Mesh.ARRAY_VERTEX][i].y, blendshp["blndshp"][name_shp][0][i].y, value)
		basis_mesh[Mesh.ARRAY_VERTEX][i].z=lerp (basis_mesh[Mesh.ARRAY_VERTEX][i].z, blendshp["blndshp"][name_shp][0][i].z, value)

0.5 sec for model with 16000 triangles.
if 200 blendshapes - 100 sec for each character...
But engine generate model on screen from mesh with blendshapes realtime

@slapin
Copy link

slapin commented Sep 10, 2019 via email

@Lexpartizan
Copy link
Author

It is very sad. It is interesting how surface with blendshapes are rendered. Better, as I understand it, the engine builds the surface we need with the help of the GPU. And then it displays. It remains just in time to get this surface ...
In theory, the work has already been done, it remains to find out how to get the result.

Yes, C ++ will allow you to use this with GLES 2, but it doesn’t interest me much.
100 ms for how many vertices and blends?
GDscript 400-500 ms for 1 blendshape and 16000 verts.

@slapin
Copy link

slapin commented Sep 10, 2019 via email

@GeorgeS2019
Copy link

GeorgeS2019 commented Jul 29, 2021

@Lexpartizan @slapin I do not plan to hijack this discussion, but I need feedback!

Recently Aviv shows the pipeline from Character Creator 3 to Godot. which preserve the BLENDSHAPEs in godot.

I seek feedback on

  • limit of using Character creator 3 mesh, skin and shader license in Godot.
  • is there challenge of porting shader to godot for making skin realistic.

Generally, I am interested on blendshape, skin realism for making realistic 3D character in godot.

@Lexpartizan
Copy link
Author

@GeorgeS2019
Sorry for delay reply.

First, character studio is paid and expensive. That's why I don't want to get involved with him. Secondly, those blendshapes that are available in the godot, as a result, allow only to control the facial expressions of the character, but not to change his face or body. That is, it is not suitable for an in-game character generator, you get only one character, even if it is of high quality.

Yes, i want to realistic skin too.

@GeorgeS2019
Copy link

GeorgeS2019 commented Aug 3, 2021

@Lexpartizan @fire
Thanks for the support.

YES! It is time the Godot community gathers interest to support in-game character generator with realistic 3D human with believable skin and emotion intense facial animation . Impressive work has progressed in 3D avartar e.g. VRM

The Character Creator 3 to Godot (Tutorial) shows how to preserve facial animation with way to integrate skeletal animation from Mixamo

Hopefully more people join in to this discussion so we could properly formulate a Godot proposal.

@fire
Copy link
Member

fire commented Aug 3, 2021

I wanted to reiterate that Blendshape to Skinned meshes can be done via https://github.com/electronicarts/dem-bones and is used in recent games like TLOU2 (The Last of Us 2). There is a recent GDC talk about this.

@Lexpartizan
Copy link
Author

To be honest, I would prefer something like a modifier in a blender called "surface deform" to realistic skin. This would help with clothing for different characters. So that the clothes have a shrinkage on the figure of the character automatically. And a good skin is made even in substance painter, using quite a standard pbr shader. And I would also really like to have lessons on compute shaders published, since I couldn't really understand what it is, but it seems to me that they are able to solve the problem with generating a small mesh from a large one with a bunch of blendshapes. While I'm doing this on the CPU.

@slapin
Copy link

slapin commented Aug 5, 2021 via email

@Lexpartizan
Copy link
Author

Compute shaders won't help much with generating one mesh from another.
In fact, the blend shapes in GODOT 4 are already processed by the compute shader. So such shaders are very good for processing data arrays.

In this case, it is quite likely that you will be able to solve not only a simple problem in the form of a lerp between the basic forms, but also prepare data, that is, calculate for each vertex of the clothing which triangle of the body it corresponds to. Of course, the data preparation can be calculated in advance and does not need realtime, but the application of this data (when we are already putting clothes on the character using this data) should be quite fast (it is not necessary to do this in every frame, you can generate meshes when loading a level, for example, but it is still very slow on the CPU).

@slapin
Copy link

slapin commented Aug 6, 2021 via email

@clayjohn
Copy link
Member

clayjohn commented Aug 6, 2021

I know I am late to the party but SurfaceTool has a create_from_blend_shapes function already https://docs.godotengine.org/en/stable/classes/class_surfacetool.html#class-surfacetool-method-create-from-blend-shape

However, I see three things that need to be added for this proposal to be fulfilled effectively:

  1. The logic needs to take the BlendShapeMode into account (e.g. normalized or relative)
  2. The logic needs to allow for a blending amount (so you can bake halfway between 2 blend shapes for example)
  3. The option needs to be exposed to an editor button

I'm not convinced that a GPU-based solution would be valuable enough here. Doing it CPU-side should be nearly as fast and much more convenient.

The logic can be copied from the GLES2 CPU blend shapes function https://github.com/godotengine/godot/blob/8db0bd44249e9cac56cf24c7c192bc782c118638/drivers/gles2/rasterizer_scene_gles2.cpp#L1388

@Lexpartizan
Copy link
Author

Lexpartizan commented Aug 9, 2021

@clayjohn Thank you very much! Especially for specifying a link to the code. I will definitely study and try the method from the surface tool.

Update. As far as I understand, create_from_blend_shape ( Mesh existing, int surface, String blend_shape ) just extracts one blendshapes, and does not apply ALL the blendshapes as we need. And not have weight of blending.

@fire
Copy link
Member

fire commented Aug 9, 2021

Here's a sketch of an api.

Array MeshInstance3D::bake_custom_blendshapes(Map<StringName, float> blends)
Array MeshInstance3D::bake_current_blend_shapes() {
    Map<StringName, float> blends;
    // foreach blend shape insert into blends
    Array baked_mesh = bake_custom_blendshapes(blends);
    return baked_mesh;
}
void MeshInstance3D::apply_current_blend_shapes() {
    Array baked_mesh = bake_current_blend_shapes();
    mesh = baked_mesh;
}

@fire
Copy link
Member

fire commented Oct 2, 2021

Status: Broken from 3.x upgrade.

I am working on a Dem Bones module for Godot Engine. I am not sure if it will be accepted into Godot Engine core, but I will attempt to create the blend shape to skeletal bone Godot Engine c++ module.

https://github.com/V-Sekai/godot-dem-bones

Skinning decomposition refers to the family of automated methods to convert any animated mesh sequences to skinning models and bone transformations. The power and usefulness of these methods in game production pipeline is any arbitrary, highly deformable models controlled by complex deformation rigs can be generated offline, and then converted to skinning model for real time replaying in game engines. This solution allows artists using all possible rigging tools without worrying about the performance penalty in the game play. Skinning decomposition can be used to compress animations of blendshapes, muscle simulation or cloth simulation. Independent components of the method can also be used to track bones animation or to solve skinning weights from range of motion (ROM) poses.

The state-of-the-art skinning decomposition solution was introduced in the SIGGRAPH Asia 2012 technical paper “Smooth Skinning Decomposition with Rigid Bones” by Binh Le and Zhigang Deng. Since then, this method has been implemented in some animation tools for game production, including Hans Godard's skinning converter, Autodesk Maya’s bake deformer, or SideFX Houdini’s skinning converter, to name a few. At EA, we also use this technique in our content pipeline quite successfully since 2015.

@fire
Copy link
Member

fire commented Jan 6, 2022

Going to poke this and add it to my list.

@YuriSizov YuriSizov moved this to In Discussion in Godot Proposal Metaverse Jul 21, 2022
@YuriSizov YuriSizov moved this from In Discussion to Ready for Review in Godot Proposal Metaverse Jul 21, 2022
@YuriSizov YuriSizov moved this from Ready for Review to Ready for Implementation in Godot Proposal Metaverse Jul 21, 2022
@reduz
Copy link
Member

reduz commented Jul 21, 2022

In Godot 4, if you dont touch the skeleton or shape keys, then the model is not updated and there is zero performance loss already.
What we could do is optionally make this a two pass process. First process shapekeys, then skeleton. This way, if shapekeys do not change, then they are not updated.

@akien-mga
Copy link
Member

Implemented by godotengine/godot#76725.

@github-project-automation github-project-automation bot moved this from Ready for Implementation to Implemented in Godot Proposal Metaverse Apr 22, 2024
@akien-mga akien-mga added this to the 4.3 milestone Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Implemented
Development

No branches or pull requests