0
\$\begingroup\$

I want to rotate a mesh in a way that the Z axis arrow always points towards the camera. For a script I would do something like this:

Vector3 directionVector = camera.position - myObject.position;
myObject.forward = directionVector.normalized; // I cannot replicate this in shader graph

I can do something similiar in shader graph, but don't know how to apply it.

Shader graph

I am well aware that you cannot simply change the Transform component's value using a shader but I would like to rotate the mesh in a way that is similar as if we point its Z axis arrow towards the camera. How can I do this?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Here's an example in URP shader graph, which expects vertex position/normal/tangent vectors in object space. Different shader graphs sometimes use different conventions, so be sure to specify in your question if you need a solution for a different convention.

Click the image to zoom to a level where you can read all the text: Shader Graph

Here's a walkthrough of the strategy:

  1. Convert the camera's world space position into object space. This gives us a vector in our local working coordinate system from our origin (the object pivot) toward the camera. Normalize it to ensure it's unit length - this will become our new "forward" direction, and we'll rotate our vertices so those on the "+z" side of our model will face this way.

  2. Pick a reference "up" vector to try to align our "+y" side toward. Unfortunately, due to the Hairy Ball Theorem, there's no perfect way to do this without discontinuities. So we'll choose two candidates, world up (preferred), and world right (fallback), and convert them to local space.

    To decide which one to use, we compute the dot product of the local-world-up with our "to-camera" (desired forward) vector, and take the absolute value. If it's close to 1.0, then these vectors are very close to parallel (or anti-parallel), and we use our fallback, otherwise we use our first choice.

  3. Cross our selected reference up vector against our desired forward (all in local space). This gives us a local right vector that's guaranteed parallel to our forward - though it might not be exactly unit length, if our reference up and forward were not quite perpendicular, so we normalize it to make sure.

  4. Cross our desired forward with our new right vector to get a local up vector that's definitely perpendicular to both and unit length (to within a tiny rounding error).

  5. Assemble these three vectors into a rotation matrix, and use it to rotate our local vertex position, normal, and tangent (if you care about lighting and normal mapping, respectively). Output our rotated vectors to the vertex shader result pins.

Note that if this model gets batched with others, the origin we get in the shader math will be the origin of the batch, not the origin of this individual mesh, which can cause our rotation to occur around the wrong point. If you observe this happening, disable batching on this material. (Or, if you need batching, you may have to encode offsets from the local pivot point into vertex colours so they survive the batching tansformation).

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .