javascriptthree.jsglslfragment-shaderbuffer-geometry

Threejs: make custom shader match the standard rendering


For performance reasons I need to display hundred of moving tetrahedrons in a scene. There for I use instancedbuffergeometry which requires a custom shader.

The scene also contains objects with regular geometry (non-buffer) and some lights (I prepared boiled-down snippet: https://jsfiddle.net/negan/xs3k1yz4/ ).

My problem is that the tetrahedrons are not shaded such that their lighting plausibly fits to the rest of the scene. The reason is probably the primitive shader I built:

<script id="vertexShader" type="x-shader/x-vertex">
attribute vec3 offset;
attribute vec4 color;
varying vec4 vColor;
varying vec3 vNormal;
void main() {
	vColor = color;
	vNormal = normalMatrix * vec3(normal);
	gl_Position = projectionMatrix *
				modelViewMatrix *
				vec4(position*1.0+offset,1.0);
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
	varying vec4 vColor;
    varying vec3 vNormal;

	void main() {  
		float di = 0.4*dot(vNormal,normalize(vec3(1.,1.,0.)))+0.4*dot(vNormal,normalize(vec3(1.,0.,1.)));
		di = di+0.2;
		vec4 vColor2= vColor*vec4(1.0,1.,1.,0.2)*di;
		gl_FragColor = vColor2;// adjust the alpha
	}
</script>

Is there a way to make the custom shader fit the lights I defined in the scene? The shader also renders the faces in such a way which does not make the impression of directed light. I'd rather like to have single faces lit evenly rather that have the color interpolated from the vertices but I was unable to achieve that.

Any pointer or help is appreciated.


Solution

  • Here's a gist of the full fragment and vertex shader source for a Three.js MeshPhongMaterial shader, as of r83.

    Three.js builds shaders using a string concatenation system, so figuring out the source of a shader from looking at the Three.js source will be almost impossible.

    The above Gist was generated by installing the shader editor Chrome extension, going to a Three.js example page that has a MeshPhongMaterial like this one and using the shader editor to inspect the full source of a running shader program:

    shader editor source

    Three.js passes all default uniforms, like lighting data, to all shader programs, so if you create a custom shader with the above Gist code, lights, bones, etc, will all work automatically.

    I would take the full source code and add your logic in manually, literally adding the result of your calculations to the existing gl_FragColor = ...

    In the future, my tool ShaderFrog will let you automatically add any Three.js shader feature (lights, bones, morph targets, etc) to any custom shader. ShaderFrog can already combine any shaders together automatically, but I haven't done the manual work needed to fully support Three features yet.