There’s two types of shader writing added to three.js as follows. One uses textContent and the other uses onBeforeCompile and replace function. The latter seems quite verbose. Are they interchangeable ? Is it necessary to divide the shader writing to the two methods? Please kindly advise. Thanks.
(1) const material = new THREE.ShaderMaterial({
uniforms: this.uniforms,
vertexShader: vertexShader.textContent,
fragmentShader: fragmentShader.textContent,
(2) let material = new LineMaterial({
onBeforeCompile: shader => {
shader.vertexShader = uniform sampler2D data; ${shader.vertexShader} .replace(
The first method is for when you want to write the entire shader from scratch.
The onbeforecompile method, is a way of editing an existing shader/material, to add or extend it with some custom tweaks or functionality.
I myself prefer to use onbeforecompile with the existing materials like MeshBasicMaterial or MeshStandardMaterial, because you inherit all the existing functionality of the material, and only have to modify the parts that you need to, instead of re-implementing the entire material from scratch.
however… sometimes the built in material shaders change due to updates in threejs so it can cause your onbeforecompile solution to break and require repair later.
Thanks for your info. The source code looks so enormous and needs much time to learn about their functions and implementations. Is there any online tool to debug shader like the source code while building a project using the built in ones? Shadertoy or what?
I just use the chrome debugger… it will dump shader syntax errors. Logic errors are harder since there are no inspection facilities, so you have to debug by like… emitting colors for different conditions and stuff.
Thanks for the link. One question, can I mix with the two types of shader writing? Like, for vertex shader, use textContent. Use “onBeforeCompile and replace” for fragment. Is it workable for three.js?
Nope, since three.js injects tons of it’s own uniforms and built-in functions, replacing the entire vertexShader with a custom string would render fragmentShader invalid in 99.9% of cases.
The usual way to replace entire vertex shader would be to do the following:
vertexShader = vertexShader.replace('#include <worldpos_vertex>',
`
#include <worldpos_vertex>
// Override gl_Position here to any desired value
`);
And for the fragmentShader:
fragmentShader = fragmentShader.replace('#include <dithering_fragment>',
`
#include <dithering_fragment>
// Override gl_FragColor here to any desired value
`);