I need guidance, how we can map one texture into three different RGB channels in a GLB file and I am not loading any texture from outside I just need to manipulate that textures which are with GLB model. I write below code
gltf.scene.traverse(function (child) {
if (child instanceof THREE.Mesh) {
const mat = new THREE.MeshPhysicalMaterial({})
if (value === 'normalMap') {
if (child.material.normalMap) {
child.material.map = child.material.normalMap;
child.material.needsUpdate = true;
console.log('Normal map exist');
}
}
if (value === 'alphaMap') {
if (child.material.alphaMap) {
child.material.map = child.material.alphaMap;
child.material.needsUpdate = true;
console.log('Alpha map exist');
}
}
if (value === 'aoMap') {
if (child.material.aoMap) {
child.material.map = child.material.roughnessMap;
child.material.needsUpdate = true;
console.log('AO map exist');
}
}
if (value === 'emissiveMap') {
if (child.material.emissiveMap) {
child.material.map = child.material.emissiveMap;
child.material.needsUpdate = true;
console.log('Emissive map exist');
}
}
if (value === 'roughnessMap') {
if (child.material.roughnessMap) {
child.material.map = child.material.roughnessMap;
//mat.needsUpdate = true;
child.material.needsUpdate = true;
console.log("mat", mat)
console.log('Roughness map exist');
}
}
if (value === 'metalnessMap') {
if (child.material.metalnessMap) {
console.log(child.userData)
//child. = mat;
child.material.map = child.material.metalnessMap;
child.material.needsUpdate = true;
console.log('Metalness map exist');
}
}
In the above code roughness map, metalness map and ao map all share same textures and I don’t need how split this texture into three parts for RGB channels. Thanks for your time and help
I tried this but didn’t work, main issue is I can’t able to understand how I divide texture into three channels like donmccurdy sir did, just wanna know is it possible, if yes then how and one more article is there
in the above link they explain but I didn’t find any path.
Ok… I am slightly confused… What effect are you trying to achieve here. Are you just trying to visualize the different textures, or what are you trying to get done. Because, from your code, it does seem as though you are just trying to visualize the textures.
are you able to create a fiddle of your entire code? Rather than just the traversal. That would be helpful, at least for me, if not for others as well.
You are getting the logs. Is it only on Roughness, occlusion, and metallic that you are getting the issue? And, if so, are you still getting the logs? I know gltf format does combine metalness/roughness map (blue channel is metalness, green is roughness), and I don’t know if it combines the alpha map as well (if so, it would be red channel). Umm… You could use the onBeforeCompile with the material to update the fragment shader a bit.
Side note: You shouldn’t need to update the material. The only time you would need to do that is if you are changing whether or not the material has its own map property.
Edit:
Why not try logging the material, and checking all the roughness, metalness, and ao map to see if they are the same texture. Dunno if that would work, but it might be worth a try.
yes, you are right in single texture image I have three channels RGB in image but I don’t know to pass single by single to three Metalness, Roughness and Occlusion. If I run my code it shows together with mixing of ORM values. I hope you understand my point and you have any resource related to onBeforeCompile and how we can override fragment shaders for this.
Ok… results of my testing. Using needsUpdate does recompile the material, but it doesn’t trigger the onBeforeCompile function.
Best thought of mine, add a uniform to the shader, call it like, imageType. In the shader, add a conditional, and if imageType is one of 3 values, update gl_FragColor with the correct texel.
That would probably look something like this:
//When loading the gltf (or before the first render frame) inside a traverse function
child.material.onBeforecompile = function(shader){
//unprocessed fragment shader. Change this, change what gets plugged
// into three.js You will need to figure out where to change the code
// Putting it directly at the end might work.
shader.fragmentShader;
//add something similar to this code
`if([uniform name] == [whatever number you are using to signify roughness map]){
gl_FragColor.rgb = texture2D(roughnessMap, vUv).ggg;
}else if([uniform name] == [metalness map number]){
gl_FragColor.rgb = texture2D(metalnessMap, vUv).bbb;
}else if([uniform name] == [ao map number]){
gl_FragColor.rgb = texture2D(aoMap, vUv).rrr;
}`;
//putting this (or similar) at the beginning
'uniform int [uniform name];';
shader.uniforms.[uniform name] = {};
Object.defineProperty(shader.uniforms.[uniform name], "value", {get:function(){
return child.material.[uniform name];
}
}
And then, in the traversal, you would just do
child.material.[uniform name] = [number for whatever option was chosen];
And, that should work. No guarantees, and you will probably have to do a bit of debugging. But, fingers crossed, that should work.
Edit:
Also make sure to replace the stuff in brackets. I don’t know if i made that obvious, but, please do not just copy paste that code. Replace the things in brackets (and the brackets themselves) with what they mean. I have done dumber things, and dont want you to waste lots of time debugging that because of a misunderstanding.