I know that the challenge of customizable materials has been discussed quite a bit, but here is a feature I would love to see to that end. I've included proposed (incomplete) code changes, and I could try doing the PR, but I am not sure if the idea is well conceived.
Problem:
I often run into situations where I want to use an existing material, e.g. THREE.MeshPhongMaterial and modify the shaders. Rebuilding such materials from scratch as a THREE.ShaderMaterial is cumbersome, but my current solution.
This tool I found allows you to insert code into existing shaders, which is nice, though a bit hacky.
https://www.npmjs.com/package/three-material-modifier
But in some cases I would like to modify a line or more.
Proposed Solution:
Materials allow a shaderChunks argument to be passed, which is an object containing glsl strings that override ShaderChunks used by ShaderLib. For example:
var shaderChunks = {
//monochrome just from R channel of texture
map_fragment: "diffuseColor *= vec4(vec3(texture2D( map, vUv ).x),1.0);"
};
var material = new THREE.MeshBasicMaterial({shaderChunks:shaderChunks});
Implementation
I started making some changes to see how hard it would be:
https://github.com/nhalloran/three.js/commit/7795a9af5c3df1cf919c84d8fdff8c49be74278d
https://github.com/nhalloran/three.js/commit/44d35a5fbcf996f779f5e33e548b043912bcb109
But a tricky part would be the handling the #includes in the ShaderLib directory
https://github.com/mrdoob/three.js/tree/dev/src/renderers/shaders/ShaderLib
I'm not exactly sure how those are built....
Would love feedback before going any further towards a PR.
Have you checked out Material.onBeforeCompile() (see #11475)? It allows you to modify built-in materials via a callback function.
There is also an example that illustrates the approach: https://threejs.org/examples/webgl_materials_modified.html
@nhalloran
Maybe also check out this PR and pitch in with some thoughts. So far i've not seen anyone use onBeforeCompile but i've seen a lot of:
THREE.ShaderChunk.some_chunk = myChunk
It seems intuitive and natural that you would pass bits, or chunks of data into the material. Even the name ShaderChunk sounds appropriate for this.
https://github.com/mrdoob/three.js/pull/13198
myMaterial.shader.chunks.fog_fragment = myFogFragment
myMaterial.shader.uniforms.vertex.myVertFloat = { type: 'f', value: 1 }
myMaterial.shader.attributes.index = { type: 'f' }
//etc..
It's very unlikely that onBeforeCompile will ever change. I'd love to compare notes if you find a good way of using it.
Please use Material.onBeforeCompile() for such use cases for now. Alternatively, have a look at the experimental NodeMaterial.
Most helpful comment
Have you checked out
Material.onBeforeCompile()(see #11475)? It allows you to modify built-in materials via a callback function.There is also an example that illustrates the approach: https://threejs.org/examples/webgl_materials_modified.html