I am trying to use more than two map channels in three.js to assign textures to my models. To my surprise no native materials in three.js support multiple sets of uvs.. Thus I have to use ShaderMaterial and write my own vertex/fragment shaders to have access to multiple map channels.
Now I did manage to get multi channel uvs to work with a simple code I worte:
<script id="vertex_shh" type="x-shader/x-vertex">
//VERTEX SHADER//
varying vec2 vUv;
attribute vec2 uv2;
varying vec2 vUv2;
attribute vec2 uv3;
varying vec2 vUv3;
attribute vec2 uv4;
varying vec2 vUv4;
attribute vec2 uv5;
varying vec2 vUv5;
void main()
{
vUv = uv;
vUv2 = uv2;
vUv3 = uv3;
vUv4 = uv4;
vUv5 = uv5;
vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
gl_Position = projectionMatrix * mvPosition;
}
// END //
</script>
<script id="fragment_shh" type="x-shader/x-fragment">
//FRAGMENT SHADER//
uniform sampler2D tCh1;
uniform sampler2D tCh2;
uniform sampler2D tCh3;
uniform sampler2D tCh4;
uniform sampler2D tCh5;
varying vec2 vUv;
varying vec2 vUv2;
varying vec2 vUv3;
varying vec2 vUv4;
varying vec2 vUv5;
void main(void)
{
vec3 DiffuseComp;
vec4 TexCh1 = texture2D(tCh1, vUv);
vec4 TexCh2 = texture2D(tCh2, vUv2);
vec4 TexCh3 = texture2D(tCh3, vUv3);
vec4 TexCh4 = texture2D(tCh4, vUv4);
vec4 TexCh5 = texture2D(tCh5, vUv5);
DiffuseComp = ((TexCh1.rgb * (1.0 - TexCh4.rgb) + (TexCh2.rgb * TexCh4.rgb)) * (1.0 - TexCh5.rgb)) + (TexCh3.rgb * TexCh5.rgb);
gl_FragColor= vec4(DiffuseComp, 1.0);
}
// END //
/* SHADER */
var vertShader = document.getElementById('vertex_shh').innerHTML;
var fragShader = document.getElementById('fragment_shh').innerHTML;
var attributes = {};
var uniforms = {
tCh1: { type: "t", value: Textura1},
tCh2: { type: "t", value: Textura2},
tCh3: { type: "t", value: Textura3},
tCh4: { type: "t", value: Textura4},
tCh5: { type: "t", value: Textura5}
};
/* MATERIAL */
var multitexsh = new THREE.ShaderMaterial({
uniforms: uniforms,
attributes: attributes,
vertexShader: vertShader,
fragmentShader: fragShader
});
However, my problem is that I basically need a shader with this functionality AND some basic features of the Phong shader: lighting (from scene lights) and specular highlights. I am totally lost here. I've tried looking for ways to either add this functionality to native shaders or add the mentioned features from phong material to my own shader, but found no info that would be sufficient to do that with my very basic coding skills.. Could anybody step in and help me out here?
EDIT:
Thanks to pailhead got it working with onBeforeCompile. This is on r89, updated code bellow:
/* MANAGERS, LOADERS */
var manager = new THREE.LoadingManager();
var loader = new THREE.FBXLoader( manager );
var textureLoader = new THREE.TextureLoader( manager );
/*TEXTURE */
var prodtex ='textures/testing/cubetex.jpg';
var prodtex2 ='textures/testing/cube_blendmap.jpg';
var Textura1 = textureLoader.load (prodtex);
var Textura2 = textureLoader.load (prodtex);
var Textura3 = textureLoader.load (prodtex2);
/* MATERIAL */
var MAT = new THREE.MeshPhongMaterial();
MAT.map = Textura1;
/* MY SHADER CHANGES*/
const uv2_chunkToReplaceVS = 'attribute vec2 uv2; varying vec2 vUv2; attribute vec2 uv3; varying vec2 vUv3;'
const uv2_chunkToReplaceVSV = 'vUv2 = uv2; vUv3 = uv3;'
const uv2_chunkToReplaceFS = 'uniform sampler2D tCh1; uniform sampler2D tCh2; uniform sampler2D tCh3; varying vec2 vUv2; varying vec2 vUv3;'
const map_chunkToReplaceFSV = 'vec4 TexCh1 = texture2D(tCh1, vUv); vec4 TexCh2 = texture2D(tCh2, vUv2); vec4 TexCh3 = texture2D(tCh3, vUv3); vec4 texelColor = texture2D( map, vUv ); texelColor = mapTexelToLinear( texelColor ); TexCh1 = mapTexelToLinear( TexCh1 ); TexCh2 = mapTexelToLinear( TexCh2 ); TexCh2 = mapTexelToLinear( TexCh2 ); diffuseColor *= TexCh1 * (1.0 - TexCh3) + (TexCh2 * TexCh3);'
MAT.onBeforeCompile = shader=>{
shader.uniforms.tCh1= {type: "t", value: Textura1};
shader.uniforms.tCh2= {type: "t", value: Textura2};
shader.uniforms.tCh3= {type: "t", value: Textura3};
shader.fragmentShader = shader.fragmentShader.replace('#include <map_fragment>', map_chunkToReplaceFSV);
shader.vertexShader = shader.vertexShader.replace('#include <uv2_pars_vertex>', uv2_chunkToReplaceVS );
shader.vertexShader = shader.vertexShader.replace('#include <uv2_vertex>', uv2_chunkToReplaceVSV );
shader.fragmentShader = shader.fragmentShader.replace('#include <uv2_pars_fragment>', uv2_chunkToReplaceFS);
};
/* MODEL */
loader.load( ('models/' + 'cube' + '.FBX'), function( object ) {
//set material//
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = MAT;
};
} );
scene.add (object);
});