user2331095
user2331095

Reputation: 6707

How to implement MeshNormalMaterial in THREE.js by GLSL?

I want to implement a shader like MeshNormalMaterial, but I have no idea how to convert normal to color.

In THREE.js:

enter image description here

My test1:

varying vec3 vNormal;

void main(void) {
    vNormal = abs(normal);
    gl_Position = matrix_viewProjection * matrix_model * vec4(position, 1.0);
}

varying vec3 vNormal;

void main(void) {
    gl_FragColor = vec4(vNormal, 1.0);
}

The result is really bad

My test2:

varying vec3 vNormal;

void main(void) {
    vNormal = normalize(normal) * 0.5 + 0.5;
    gl_Position = matrix_viewProjection * matrix_model * vec4(position, 1.0);
}

varying vec3 vNormal;

void main(void) {
    gl_FragColor = vec4(vNormal, 1.0);
}

This is better than above.

These are just test, I can't find any resources about how to calculate the color...

Can anyone help me ?

Thanks.

Upvotes: 3

Views: 1670

Answers (1)

Rabbid76
Rabbid76

Reputation: 210889

If you want to see the normal vector in view space, the you have to transform the normal vector from the model space to the world space and from the world space to the view space. This can be done in one step by transforming the normal vector with the normalMatrix.

varying vec3 vNormal;

void main(void)
{
    vNormal      = normalMatrix * normalize(normal); 
    gl_Position  = matrix_viewProjection * matrix_model * vec4(position, 1.0);
}

Since a varying variable is interpolated when it is passed from the vertex shader to the fragment shader, according to its Barycentric coordinates, the transformation to the color should be done in the fragment shader. Note, after the interpolation the normal vector has to be normalized again

varying vec3 vNormal;

void main(void)
{
    vec3 view_nv  = normalize(vNormal);
    vec3 nv_color = view_nv * 0.5 + 0.5; 
    gl_FragColor  = vec4(nv_color, 1.0);
}

Since the normal vector is normalized, its component are in the range [-1.0, 1.0]. How to represent it as a color is up to you.
If you use the abs value, then a positive and negative value with the same size have the same color representation. The intensity of the color increases with the grad of the value.

enter image description here

With the formula normal * 0.5 + 0.5 the intensity increases from 0 to 1.

enter image description here

In common the x component is represented red, the y component is green and the z component is blue.

The colors can be saturated, by dividing with the maximum value of its components:

varying vec3 vNormal;

void main(void)
{
    vec3 view_nv  = normalize(vNormal);
    vec3 nv_color = abs(view_nv); 
    nv_color     /= max(nv_color.x, max(nv_color.y, nv_color.z));
    gl_FragColor  = vec4(nv_color, 1.0);
}

enter image description here

Upvotes: 8

Related Questions