Mesh rotation in spatial shader

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By creative-mind

Hi, I am trying to reproduce a paper for shader planet. I am generating a plane mesh on which I apply the spatial shader fort vertices displacement. However, I need the plane to always face the camera - it’s simple on CPU (look_at function) but I need to do it inside the shader to get a proper VERTEX positions. In the paper there is an equation for computing the Rotation matrix as follows:

enter image description here

My implementation in Godot is as follows:

vec3 w = normalize(cam_pos);
vec3 v = normalize(cross(w, vec3(0,0,1)));
vec3 u = cross(w, v);
mat3 rot_mat = mat3(u, v, w);

My question is: How to apply the rotation matrix rot_mat to rotate the whole mesh to face the camera? I tried to multiply the rotation matrix with vertices and got somewhat meaningfull outcome, but far from correct.

Thanks for any help! :wink:

:bust_in_silhouette: Reply From: rossunger

is there a reason you’re not using a Sprite3D node to achieve this? it has a billboard option that makes the sprite face the camera. I think it also includes built-in optimizations.

Obviously, Sprite3D can only carry the texture and move it arround in 3d space.

I need to generate a terrain based on the heightmap on the fly. I do it by pre-generating a plane mesh of a custom resolution and apply a spatial shader on it that updates each vertex’s elevation based on the heightmap pixel.

It is of course possible to use look_at function to make the pre-generated mesh always look in the camera direction, which would be an equivalent of the billboard effect you mentioned. However, when I did so, I couldn’t estimate the rotated position of the vertices as their position inside the shader is always local. So I need to do the rotation (this billboard effect) inside the shader to update the vertices position on the fly and to map them properly on the heightmap texture to make the feeling of static terrain when orbiting the planet.

creative-mind | 2022-12-18 23:19

I feel like i’m not totally understanding what you’re doing.

If you want to make a mesh from a heightmap, and have that mesh always face the camera, why are you doing everything in shader? and not just making a node, and rotating that node to face the camera? is this for optimization reasons?

rossunger | 2022-12-18 23:23

TLDR: I tried rotating the mesh with the look_at function to always face the camera. However, I had a problem with mapping the heightmap pixels to corresponding vertices. Basically, the texture mapping was not corresponding to the currently shown side of the planet.

What am I trying to do:
I want to implement an effective way to render the planet in real-time by just rendering the current field of view - the pre generated mesh of fixed resolution. I simply morph the mesh into the shape of the planet surface (just a slice that is visible) given the camera position. So if the camera is far from the mesh, it has a spherical shape and the closer tha camera the more flat the mesh is. I am however stuck with mapping the heightmap texture to the surface of the mesh when the camera rotates around the planet. In the shader there is no information about vertex orientation towards the camera if I rotate it outside the shader - I only have the camera position itself. Also in the paper I am trying to reproduce, they use a Rotation matrix to first rotate the vertices towards the camera and only then when the vertices correspond to the correct position on the unit sphere, map them to the heightmap texture. I have a separate function for mapping the position on the unit sphere to the texture position.

creative-mind | 2022-12-19 08:39

:bust_in_silhouette: Reply From: creative-mind

Looks like I eventually found the answer myself. The problem is that apprently in Godot the rotation matrix needs to be transposed.

So the final code that works for me looks like this:

vec3 w = normalize(cam_pos);
vec3 v = normalize(cross(w, vec3(0,0,1)));
vec3 u = cross(w, v);

mat3 rot_mat = transpose(mat3(u, v, w));
VERTEX *= rot_mat;