Rotating meshes using Vertex Shaders

Rotating (ambient) meshes in your world adds a dynamic element, but doing this on the CPU and having to pass it to the GPU each frame is a relatively slow operation. Without realizing you may be updating your collision every tick too, causing overlap updates and hurting performance even more.

There is an old trick to instead rotate all vertices on the GPU directly using the vertex shader, completely omitting the CPU. Keep in mind that this does not update the rotation of the mesh collision. You should either disable collision or consider using a simple collision shape that doesn’t need to rotate and handles approximate collision regardless of the rotation.

While this trick is pretty common I was surprised to not find clear information on it for UE4. Especially on fixing the normals after moving the vertices around. So this post should serve as a complete tutorial on how to rotate meshes on the GPU within Unreal Engine.

In case you’re wondering, the planet’s mesh in the background isn’t rotating since it’s just a sphere. Instead, you simply add a UV-panner to the texture.

Rotating Vertices on Axis

Rotating the vertices is luckily very easy as we have a ready-to-use material node available: RotateAboutAxis. We plug this into World Position Offset with some simple inputs like Time to determine rotation angle, and the object’s orientation for its rotation Axis.

Note: I used the ObjectPivotPoint, but keep in mind that its not available in the Pixel-shader. The “Normal”-pin runs on the pixel-shader while the “World Position Offset”-pin runs on the vertex shader.

You may notice your lighting doesn’t correctly update now that your mesh rotates on the GPU. We’ll need to fix the vertex normals next.

Fixing Vertex Normals

With the vertices moved around we need to fix the vertex normals as they still point the original direction, causing lighting issues. Again, we have a Material Function already available: FixRotateAboutAxisNormals.

I was able to directly plug this into the pixel shader which is the “Normal” pin. The recommended way (as mentioned in the Material Function’s description) is to add CustomizedUVs (option in the Material properties itself) to the material and instead re-calculate the normals in the vertex shader and pass it as UVs to the pixel shader. This can heavily reduce the number of times you need to re-calculate normals. (equal to the number of vertices in your mesh instead of the number of pixels on-screen for that mesh) This is especially useful if your meshes have low vertex counts.

Closing

Hopefully, you’ve found this helpful. I’m using this ancient trick to rotate ambient meshes such as the space station and asteroids. But don’t forget your collision doesn’t update, so if you want players to interact with the rotated mesh, you might need to alter the collision or use the CPU after all.

15 Responses

  1. Hi Tom, thanks for the guide I have a question and also a problem I can’t seem to workout, If i add a local rotation to the mesh inside a blueprint this seems to affect the logic when the mesh is rotated in worldspace, say i want to rotate a wheel and have it on a 15 degree angle locally in the blueprint, then this wheel must also rotate in the world when it turns left and right? any help would be great thanks.

  2. Thank you so much, you are a Godsend, this saved my butt. I was having terrible motion blur on a rotating minigun and this fixed it. THANK YOU

    • I believe there are nodes available to blend normals map. “BlendAngleCorrectedNormals”-node to combine the normal correction and a normal map is something to try out.

  3. I am new in Shader.
    I use this Rotate shader for simple Cube Mesh but it did not work
    what i did wrong ?

  4. Having trouble getting the correct normals from the FixRotateAboutAxisNormals with billboard vertex operations. Any thoughts on how to tackle that?

      • Trying to billboard some foliage cards to set the whole world on fire on the super cheap. Was trying to add fresnel fading to eliminate seeing the card edges when the player is top-down over them.

        Think I’ll go the more traditional route and only use the billboard cards at distance, and fade into a clustered static mesh that doesn’t billboard to handle the up close stuff, and use the foliage distance features to cross fade smoothly. The near stuff will all be covered up with a player based spawning of particles too, so pretty sure that’ll be a solid solution.

  5. Any tips on getting this to work with the simplegrasswind node? Tried hooking up the same input nodes as this post inside the node/adding normal output, but not getting correct normals.

  6. Pardon an offtopic question, but how did you get node connectors shaped like that? I’ve tried tinkering in Editor settings in Graph section, but I could get only 100% straight connectors or alter slightly curvature of spaghetti nodes

  7. Thanks a lot! This is incredibly interesting and there’s not much info regarding unreal shaders that is also so easy to understand

Leave a comment on this post!