We currently have a system where we read off the velocities of points on a mesh.
This uses the Sample Skeletal mesh node.
This offers two options: local and world.
The issue we have is that bone local ends up giving us (for example) an up vector when the bone itself is rotating. Understandable, but it doesn’t tell us much about how it’s moving in world space.
Using world space gives us the correct velocity in world space but it also includes the character motion - the character velocity.
The solution we have come up with is to transform the local space velocity into actor local space, this removes the character velocity while giving a world space vector for emitting particles.
The problem is this doesn’t work with in place animation and all our animation clips need some pretty complex systems to convert all our animation into root motion. This is just to preserve the principle that the actor transform is local to the character itself.
The core problem here is that we need an independent reference transform to hold the local world space velocity in. That’s the only use for the actor transform. We would like to change our animation to provide this transform space as an additional bone and avoid all the root motion dependencies.
Problem is our FX team have hit a block on how to actually implement this in Niagara. Do you have any hints as to how we would do this?
Hey Thor,
I don’t think I fully understand what velocity you’re trying to sample from the mesh. Local sampling gives you the bone velocity from the characters perspective, world sampling gives you the velocity from the perspective from someone else looking at the bone. Do you want the velocity from world sampling, but minus the characters velocity? If you use that to spawn particles it might look weird, as it doesn’t make physical sense.
If your niagara system is attached to the skeletal mesh actor, you can use the system’s transform (Engine.Owner.SystemLocalToWorld) and velocity (Engine.Owner.Velocity) to transform your sampled bone values into whatever you need.
Regards,
Michael
Apologies, let me try and clarify the initial message, as I think we need to do a better job of explaining what we are trying to do.
We currently have a complex setup that bakes the Root Motion of the character into animation curves and we then use them to move the character in the world. With this setup, we can easily sample the Skeletal Mesh in either Local Space or World Space since the Actor moves in the World. This allows us to spawn particles on the surface of the Skeletal Mesh and sample the triangle’s Local Velocity, which we then apply to the particle’s initial Velocity. As an example, if a character is running forward and swinging its arms up and down, when spawning particles on the surface of its arms, we are able to apply to the particles the local velocity of the arms, ignoring the forward motion of the actor.
However, what we would like to do instead, is to disable Root Motion, keep the actor at the World’s origin and bake the World Space motion into the pelvis of the Skeletal Mesh animation. By doing so, it would make our pipeline considerably simpler, but we would lose the ability to sample the Skeletal Mesh in Local Space. Using the same example as before, if we now spawn the particles on the character’s arm and sample the Local Space velocity, the sampled value will contain both the forward motion and the arm movement up and down combined, and we are unable to filter out the motion of the Character in the World.
We are looking for a solution that could help us retain the ability to sample the local velocity of the “arms”, filtering out the “pelvis”.
Okay, so here are some possible solutions you could try after baking your root motion into the animation:
(1) Sample the pelvis bone velocity separately and subtract it from the sampled arm velocity
(2) If the error rate of (1) is too high, maybe add a dummy bone to the mesh that only has the baked root motion, so you can sample it in niagara
(3) Keep the velocity curve you for the root motion as separate asset and provide its data to the niagara system either via user parameter or by using a curve data interface. Use it to subtract the baked motion from the sampled one.
I would suggest using option 3, as it provides you with the most flexibility and a curve can be reused in other systems like Blueprint or Materials as well, if needed.
That’s why I said that the first solution where you just sample the pelvis bone might give you too much error. But for the other two solutions you would just bake the rotation into the bone or curve asset as well. “Get Skinned Bone Data” gives you the full transform + velocity, so you can store a separate rotation value for each frame.
Thank you so much for your reply, we didn’t think about trying to use a dummy bone or baking motion using a curve data interface, however we did try sampling the pelvis bone velocity directly and subtracting it from the sampled arms velocity.
This perfectly compensates any translation motion added to the pelvis bone, however it doesn’t account for its rotation motion. We tried calculating the angular velocity of the arms bones relative to the pelvis using the pevlis’ previous and current orientations, this needs to be done on each arm bone every frame, since the velocity would be different the further away the arm bone is from the pelvis, we then subtracted this one from the sampled velocity too. We got some promising results but the rotation still wasn’t getting fully cancelled out, especially when quick rotations were applied to the pelvis.
It sounds like all the 3 suggested approaches would only compensate for the pelvis’ translation movement, and fail when rotation is introduced on the pelvis.
The nodes we are using are Get Skinned Triangle Data and Get Skinned Bone Data WS , they both reference the same code where the skeletal mesh animation gets sampled, in the first one the sampled values are in local space, in the second one they get transformed to World Space. If we remove root motion and move the pelvis of the character within the animation they will output the World space value only as the actor is not moving.
What we would need is a Get Skinned Triangle Data in Target Bone Space , we would need to find a way to access the bone buffer and change the way the data is sampled so that the motion coming from the “Target Bone” (pelvis) gets ignored, this would make the velocity sampled in the Target Bone space.