So, I want to animate a mesh in C4D and bring it into UE4. The animation would move the vertices, not the location of the mesh itself (otherwise I would just use blueprints). An example of the animation I want to bring in is here: Spline Wrap - YouTube
My question is, how is this done. All I ever see is blah blah character blah blah skeleton. I don’t want to change the animation when it gets into UE4, I just want to, at most, define when it starts and stops (aka the speed). All I would be doing with said animated mesh is have it spawn, do its animation, then destroy itself. So, what do I do/where is there a tutorial on this because I am not seeing it. T_T
hey there!
here is a similar thread that has an answer from our animation programmer:
Baking Animations on Vertices
The current solution/workaround is to create a skeleton that has a joint/vertex, and bake the vertex animation down onto the joints, then skin the mesh to the skeleton (each vertex skinned to its corresponding joint).
The other is to create a morph target for every frame of the animation and import as a skel mesh, with the mesh weighted to 1 bone, and all of the blendshapes created.
Both of these are tedious and I would recommend scripting such a task if possible. I am unfamiliar with cinema4D though and do not know what types of scripting they support.
So… while both of these sound beyond awkward, the skeleton one sounds a bit easier. Is there an example of how to do this? On any 3D program (I’ll figure out how it translates to C4D myself).
The idea is to bring something like this: - YouTube into UE4 in as simple a way as possible.
sure! so I’m going to show some python scripting here on how I would tackle this in Maya. With scripting, this becomes a trivial task, whereas having to do this manually would be tedious and boring
#first, we need to find the vertices of the mesh. In this case, it requires you to select the mesh before running the script
#this tells us the first element in our selection
object = cmds.ls(sl = True)[0]
#get the vertices of the selected object
vertices = cmds.polyEvaluate(v = True)
#create a root joint to parent all created joints under
cmds.select(clear = True)
root = cmds.joint(name = "root")
cmds.select(clear = True)
#go through each vertex of the mesh, and create a joint for that vertex
for i in range(vertices):
#create the joint
cmds.select(clear = True)
joint = cmds.joint(name = "joint_" + str(i))
cmds.select(clear = True)
#parent the joint under the root
cmds.parent(joint, "root")
#select a vertex on the mesh, and create an emitter for it
#Emitters are super handy for this since it gives you an object to constrain the joint to!
cmds.select(object + ".vtx[" + str(i) + "]")
emitter = cmds.emitter()[1]
#constrain the joint to the emitter
constraint = cmds.parentConstraint(emitter, joint)[0]
At this point, you would now have joints following your mesh, and you could select them all, and bake the animation down to the joints.
In maya, this is edit–>keys–>bake simulation.
Then you would need to skin your mesh to those bones. You could script this as well, or you could do it manually, depending on your vert count.
Awesome! I saw this, worked to find a way to replicate the motion within maya (which i can, apparently) but when I tried to run the script in the python script thing, it shows this: # Error: NameError: file line 4: name ‘cmds’ is not defined # Whats wrong?
Doh! Sorry bout that. Just add the following at the very top of the code:
import maya.cmds as cmds
Also, can you tell me the name of the skinning method to look up? Never skinned things/used bones at all before.
Hmmm. Well, It almost seems to work out. I select the mesh and the bones, export selected (make sure constraints are checked, since my mesh is getting its animation from motionpath + flow path object), but when I drop the fbx file into my project (I use a blank project for testing purposes), it complains about there being no bind pose, and even when I check ‘import animation’ when it asks what to import, the mesh doesn’t move when I attach the imported animation to the mesh/skeleton. What am I doing wrong? Do I have to do something more with the constraints, even though I baked the joints?
Is the mesh skinned to the bones? I’ll write you a quick script shortly that you can use to skin the mesh to the created joints.
Alrighty, so here is the process I used. Run the first script posted above to get joints following the vertices. Then select all those joints and bake the animation down to them.
Then run the following script, once again, selecting the mesh like before:
#first, we need to find the vertices of the mesh. In this case, it requires you to select the mesh before running the script
#this tells us the first element in our selection
cmds.currentTime(0)
object = cmds.ls(sl = True)[0]
object = cmds.duplicate(object, name = object + "_skinned")[0]
#get the vertices of the selected object
vertices = cmds.polyEvaluate(v = True)
#select the object and all of the created joints
cmds.select("root", hi = True)
cmds.select(object, add = True)
skin = cmds.skinCluster(sm = 0, nw = 1, tsb = True)[0]
#go through each vertex of the mesh, and create a joint for that vertex
for i in range(vertices):
#skin the vertex to the corresponding joint
cmds.skinPercent( skin, object + ".vtx[" + str(i) + "]", transformValue=[("joint_" + str(i), 1)])
This script will duplicate the object so we have a clean version that it can then skin to the joints that have the animation. Once you run the script, select the root joint, and the skinned mesh(it has a suffix indicating this) and export selected FBX.
That should do it!
Awesome! It worked! I have one more request, if I may be so bold. Can these be slightly changed to work with multiple meshes? I am using these meshes as the base for VFX (stuff like you might see in Tera: Rising) and it is alot easier to make all the movement of a vfx in maya all in one scene, but when I tried to use the first script on a second mesh, I gave me an error saying it couldn’t find a joint zero. And when I selected multiple meshes, it only ran through the process for one.
I can definitely do that for you! Quick question though, would all of the mesh joints be under a unified root joint, or should they all have their own root joint?
Thanks!
I would imagine it would all be under one unified root joint, unless there are particular advantages to having them have separated root joints? (Remember, never used joints or skeletons before)
My goal is to get the approximate correct timing of each part in relation to each other in Maya and then maybe fine tune the overall speed of the animation playback in UE4 (you can do that right?)
Here you go! simply select the objects you want, and the script will take care of the rest, including baking the simulation down on the joints. When it is done, you will be left with the root joint hierarchy and meshes that have “_skinned” as the suffix, and you’ll want to export selected on those.
Hope this helps you out!
Edit: Also, you can definitely adjust the play rate in UE4. Simply select the anim sequence in Persona, and in the details panel you should see the option to adjust the rate. Fun tip! -1 will actually play an animation in reverse!
#this tells us the first element in our selection
objects = cmds.ls(sl = True)
#create a root joint to parent all created joints under
cmds.select(clear = True)
root = cmds.joint(name = "root")
cmds.select(clear = True)
for object in objects:
#get the vertices of the selected object
vertices = cmds.polyEvaluate(object, v = True)
#go through each vertex of the mesh, and create a joint for that vertex
for i in range(vertices):
#create the joint
cmds.select(clear = True)
joint = cmds.joint(name = object + "_joint_" + str(i))
cmds.select(clear = True)
#parent the joint under the root
cmds.parent(joint, "root")
#select a vertex on the mesh, and create an emitter for it
#Emitters are super handy for this since it gives you an object to constrain the joint to!
cmds.select(object + ".vtx[" + str(i) + "]")
emitter = cmds.emitter()[1]
#constrain the joint to the emitter
constraint = cmds.parentConstraint(emitter, joint)[0]
#bake all of the joints using the timeline as the range
start = cmds.playbackOptions(q = True, min = True)
end = cmds.playbackOptions(q = True, max = True)
cmds.select("root", hi = True)
cmds.bakeResults(simulation = True, time = (start, end))
#skin the meshes to the joints
for object in objects:
#this tells us the first element in our selection
cmds.currentTime(0)
dupe = cmds.duplicate(object, name = object + "_skinned")[0]
#get the vertices of the selected object
vertices = cmds.polyEvaluate(dupe, v = True)
#select the object and all of the created joints
cmds.select("root", hi = True)
cmds.select(dupe, add = True)
skin = cmds.skinCluster(sm = 0, nw = 1, tsb = True)[0]
#go through each vertex of the mesh, and create a joint for that vertex
for i in range(int(vertices)):
#skin the vertex to the corresponding joint
cmds.skinPercent( skin, dupe + ".vtx[" + str(i) + "]", transformValue=[(object + "_joint_" + str(i), 1)])
Excellent! I was worried at first because it acted strangely when I had a group object being animated and the meshes were under the group, but when I checked the import in UE4 it turned out just fine! I’ll definately turn this into a button for maya and then in a couple days I’ll try and make a post showing off my finished first results. Can’t thank you enough Jeremy!
Actually, looking closer at the UE4 part of things, I notice that the imported meshes are all viewed as one mesh, not several, meaning I can’t apply different materials to the different planes. Currently, I have it so that each plane has its UVs taking up the entire UV space, thinking that I could have a material for each plane. I could just fit them all into one UV space, but the stretching that would have resulted was necessary for my workflow. Any way to separate them out in order to give each plane its own material in UE4?
My guess is the original meshes were possibly all sharing the same material ID? (default lambert).
The manual way is to select an object, right click and choose assign favorite material → lambert (or phong, or whatever you want).
Another quick script you can run on the selection of skinned meshes to do the same:
import maya.cmds as cmds
#assign a unique material ID to each selected object
selection = cmds.ls(sl = True)
for each in selection:
material = cmds.shadingNode("phong", asShader = True, name = each + "_Material")
cmds.select(each)
cmds.hyperShade(assign = material)
cmds.select(clear = True)
Let me know if that does what you’re looking for!
Have a good weekend!