Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

three.js ShaderMaterial FlatShading

Tags:

three.js

glsl

I'm writing a custom ShaderMaterial and decided to include lights and fog. So far so good and I got the shader integrated with three.js build it fog, ambient and point lights (it serves my purpose).

However, the shading I get its smooth, not flat. Before you guys decide to suggest adding the shading: THREE.FlatShading flag to the ShaderMaterial, remember that this is a custom Shader and therefore that won't really do anything.

Since FlatShading is done by calculating the triangle centroid and fill all the colors based on that vector, I thought using the normal of the triangle vertices would do the trick.. obviously it doest... Is that a way of correctly have a FlatShading light where all the pixels inside the triangle have 1 single colour? If so, what am I missing?

here's my shader in CoffeeScript

class SomeShader

constructor: ->

    @defines = {}

    @uniforms = THREE.UniformsUtils.merge [
        THREE.UniformsLib['fog']
        THREE.UniformsLib['lights']
        {
            color: { type: 'c', value: new THREE.Color(0xffffff) }
        }
    ]

    @vertex = [
        'uniform vec3 ambientLightColor;'
        '#if MAX_POINT_LIGHTS > 0'
        '   uniform vec3 pointLightColor[MAX_POINT_LIGHTS];'
        '   uniform vec3 pointLightPosition[MAX_POINT_LIGHTS];'
        '   uniform float pointLightDistance[MAX_POINT_LIGHTS];'
        '#endif'

        'uniform vec3 color;'
        'varying vec4 v_color;'

        'void main() {'
        # lights
        '   vec3 norm = normalMatrix * normal;'
        '   vec3 pos = (modelViewMatrix * vec4(position-norm, 1.0 )).xyz;'
        '   vec3 outgoingLight = vec3(1.);'
        '   vec4 addedLights = vec4(0., 0., 0., 1.);'
        '   #if MAX_POINT_LIGHTS > 0'
        '   for(int l = 0; l < MAX_POINT_LIGHTS; l++) {'
        '       vec3 lightDirection = normalize(pos - pointLightPosition[l]);'
        '       addedLights.rgb += clamp(dot(-lightDirection, norm), 0.0, 1.0) * pointLightColor[l];'
        '   }'
        '   #endif'
        '   addedLights += vec4(ambientLightColor, 1.);'
        '   v_color = vec4(outgoingLight, 1.) * addedLights;'
        '   gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);'
        '}'
    ].join '\n'

    @fragment = [
        THREE.ShaderChunk['fog_pars_fragment']

        'varying vec4 v_color;'

        'void main() {'
        '   vec3 outgoingLight = vec3( 1. );'
            THREE.ShaderChunk['fog_fragment']
        '   gl_FragColor = v_color * vec4(outgoingLight, 1.);'
        '}'
    ].join '\n'
like image 304
andrevenancio Avatar asked Mar 14 '26 07:03

andrevenancio


1 Answers

You are using ShaderMaterial and your are displacing your vertices in the vertex shader with a noise function. You also want to recompute the vertex normals so the shading is flat -- i.e., faceted.

To do that, you need to compute new normals using screen-space derivatives in the fragment shader, and also do your lighting calculation in the fragment shader.

So, in your vertex shader, compute the following varying:

varying vec3 vViewPosition;

vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );
vViewPosition = - mvPosition.xyz; // vector from vertex to camera

Then, in the fragment shader, compute the normal using screen-space derivatives:

normal = normalize( cross( dFdx( vViewPosition ), dFdy( vViewPosition ) ) );

Now, use your lighting model to compute the shading in the fragment shader.

three.js r.73

like image 105
WestLangley Avatar answered Mar 17 '26 00:03

WestLangley



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!