Kronephon
Kronephon

Reputation: 325

Angle between view vector and normal?

Rather standard GLSL problem. Unfortunatly although I'm familiar with the math behind it, I'm not that certain on the implementation at the webgl level. And shaders are rather tricky to debug.

I'm trying to get the angle between the view vector and the normal of an object, at the glsl shader level. I'm using threejs but making my own sharers through them.

Here's the relevant part of the vertex shader:

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

    vec3 nmalInWorld = normalize(normalMatrix * normal);
    vec3 camInWorld = cameraPosition;
    vec4 posInWorld = modelViewMatrix * vec4(position, 1.0);
    posInWorld /= posInWorld[3];
    angle = -dot(normalize(posInWorld - vec4(cameraPosition, 1.0)), normalize(vec4(nmalInWorld,1.0)));
    if(angle > 0.7){
      angle = 1.0;
    }else{
      angle = 0.0;
    }

I've tried several permutations of this arrangement so I apologize in advance if it's needlessly complicated. I do get something rather similar to what I want - it it certainly always the same in respect to camera perspective but it's not centered for some reason I don't understand. The fragment shader just directly patches angle to a color field.

enter image description here

As you can see the white point isn't centered in the middle of the sphere which is the intended result. I don't really see why. Perhaps it's missing a perspective transform application? Tried it with no success. I don't believe the view vector should be relevant in this situation, the sphere should remain colored the same regardless of the target of the camera.

Upvotes: 2

Views: 1654

Answers (1)

Rabbid76
Rabbid76

Reputation: 210889

posInWorld, vec4(cameraPosition, 1.0) and vec4(nmalInWorld,1.0) are Homogeneous coordinates.

The Dot product of 2 Cartesian Unit vectors is equal to the Cosine of the angle between the vectors.

The "view" vector is the normalized cartesian vector from the position of the vertex to the position of the camera. When a vertex position is transformed by modelViewMatrix, then the result is a position in view space. The view space position of the camera is (0, 0, 0), because the origin of the viewspace is the position of the camera:

vec4 posInView = modelViewMatrix * vec4(position, 1.0);
posInView /= posInView[3];

vec3 VinView = normalize(-posInView.xyz); // (0, 0, 0) - posInView

The normalMatrix transforms a vector from model space to view space:

vecr NinView = normalize(normalMatrix * normal);

VinView and NinView are both vectors in viewspace. The former points from the vertex to the camera the later is the normal vector of the surface at the vertex coordinate.
The cosine of the angle between the 2 vectors can be get by the dot product:

float NdotV = dot(NinView, VinView);

Upvotes: 2

Related Questions