I am instantiating meshes procedurally (via DrawMeshInstancedIndirect) and I want the mesh to be “orientated” depending on the normal at the position where it’s instantiated.
I have the normal information (as a Vector) in my shader in the vert function but I don’t find how to rotate my vertices using this normal.
I tried to use a Matrix with the mul function but I didn’t found how to construct it (all my attempts have failed).
I don’t want to compute the rotation informations out of the shader ; I need to construct all my rotation informations in the shader using the normal (and possibly with normalized vectors like up, forward, etc.).
It’s impossible to create an 3D orientation from just a single vector direction, you need at least two non-colinear vectors (pointing in different directions), or a vector and a rotation around that vector. The later is less data, but more expensive to create an orientation (aka rotation) matrix from. So all you really need is the normal and then pick some arbitrary second vector to use.
The easiest way to think of a rotation matrix is three vectors that are pointing in the directions you want each axis of an object to be aligned to. Right, Up, and Forward.
So, we can use the normal as the up vector, and use a constant float3(0,0,1) as the reference forward vector, and calculate a right vector with a cross product. A cross product of two vectors produces a third vector that is perpendicular to both of the input vectors. However unless you want a mesh that’s kind of squished, you need all three vectors to be perpendicular to each other, but the starting normal won’t be perpendicular to the constant forward vector most of the time. However we can use a cross product to produce a new forward vector that is.
I didn’t try your code because i’ve already used that one and I can say that it works very well. If someone just want a quick way to use it, you need a unitary vector as the “default” normal (the UP vector) and the normal of the terrain at te point where the mesh is instanciated.
And then, here is the function that gives the matrix:
float3x3 NormalRotationMatrix(float3 v1, float3 v2) //-- v1 = up vector and v2 the normal that i want for my vertices
{
float3 axis = cross(v1, v2);
float cosA = dot(v1, v2);
float k = 1.0f / (1.0f + cosA);
float3x3 result =
float3x3(
(axis.x * axis.x * k) + cosA,
(axis.y * axis.x * k) - axis.z,
(axis.z * axis.x * k) + axis.y,
(axis.x * axis.y * k) + axis.z,
(axis.y * axis.y * k) + cosA,
(axis.z * axis.y * k) - axis.x,
(axis.x * axis.z * k) - axis.y,
(axis.y * axis.z * k) + axis.x,
(axis.z * axis.z * k) + cosA
);
return result;
}
Then, here’s the way to use the matrix for applying the rotation :