Clay Clay - 5 months ago 25
Javascript Question

Change All Other Models' Material to the Selected Model's Material

I am experimenting around the vertex shader of 3D models. My problem is I am having the difficulty of changing all other models' material to the selected model's material. Here, I have 4 models in each viewport. If I had selected the bottom left of the model (v1), the rest of the models' material will change accordingly to the selected model's. In the Model Selection code, I had implemented the logic behind it but it did not update all other models. Below, it is assumed that are 4 vertex shaders and 4 model creations. Please advise. Thank you =)

enter image description here

Vertex Shader

function vertexShader() {
return ['varying vec4 color;',
'uniform float displacement;',

'void main() {',
'vec3 newPos = position + ' + treeCreation() + ';',
'color = vec4(1.0, 0.0, 1.0, 1.0);',
'gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);',
'}'].join('\n');}


Main

function init() {
container = document.getElementById('container');

// scene
scene = new THREE.Scene();

defineViewports();
initCameras();

// shader property
var shaderProp = {
uniforms: {
displacement: {
type: "f",
value: 0.0
}
},
vertexShader: vertexShader(),
fragmentShader: fragmentShader()
};

var shaderMaterial1 = new THREE.ShaderMaterial(shaderProp);

//object loaders with shader properties
var objectLoader = new THREE.ObjectLoader();
objectLoader.load("male_model_object.json", function(object) {
//if you want to add your custom material
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = shaderMaterial1;
}
});

object.position.set(0, 0, 0);
scene.add(object);
objects.push(object);
materials.push(shaderMaterial1);
});

// shader property
var shaderProp = {
uniforms: {
displacement: {
type: "f",
value: 0.0
}
},
vertexShader: vertexShader2(),
fragmentShader: fragmentShader()
};

var shaderMaterial2 = new THREE.ShaderMaterial(shaderProp);

//object loaders with shader properties
var objectLoader2 = new THREE.ObjectLoader();
objectLoader2.load("male_model_object.json", function(object) {
//if you want to add your custom material
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = shaderMaterial2;
}
});

object.position.set(500, 14, 0);
scene.add(object);
objects.push(object);
materials.push(shaderMaterial2);
});

// shader property
var shaderProp = {
uniforms: {
displacement: {
type: "f",
value: 0.0
}
},
vertexShader: vertexShader3(),
fragmentShader: fragmentShader()
};

var shaderMaterial3 = new THREE.ShaderMaterial(shaderProp);

//object loaders with shader properties
var objectLoader3 = new THREE.ObjectLoader();
objectLoader3.load("male_model_object.json", function(object) {
//if you want to add your custom material
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = shaderMaterial3;
}
});

object.position.set(0, 514, 0);
scene.add(object);
objects.push(object);
materials.push(shaderMaterial3);
});

// shader property
var shaderProp = {
uniforms: {
displacement: {
type: "f",
value: randomDisplacementValue()
}
},
vertexShader: vertexShader4(),
fragmentShader: fragmentShader()
};

var shaderMaterial4 = new THREE.ShaderMaterial(shaderProp);

//object loaders with shader properties
var objectLoader4 = new THREE.ObjectLoader();
objectLoader4.load("male_model_object.json", function(object) {
//if you want to add your custom material
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.material = shaderMaterial4;
}
});

object.position.set(500, 514, 0);
scene.add(object);
objects.push(object);
materials.push(shaderMaterial4);
});

//fps
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0px';
container.appendChild(stats.domElement);

//renderer
renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );

window.addEventListener('updateSize', updateSize, false);
window.addEventListener('click', onClick, false);
window.addEventListener('keypress', onDocumentKeyPress, false);}


Model Selection

function onDocumentKeyPress(event) {
switch(event.keyCode) {
// enter
case 13:
if(selectedIndex >= 0) {
// TODO: LOGIC BEHIND GETTING THE EQUATION OF SELECTED MODEL
var shader = objects[selectedIndex].children[0].material.vertexShader;

for(var j = 0; j < objects.length; ++j) {
for(var i = 0; i < materials.length; ++i) {
materials[i].vertexShader = shader;
materials[i].needsUpdate = true;
}
}
}
}}


Renderer

function render() {
updateSize();
for ( var i = 0; i < views.length; ++i ) {
view = views[i];
camera = view.camera;

//view.updateCamera( camera );
var left = Math.floor(windowWidth * view.left);
var bottom = Math.floor(windowHeight * view.bottom);
var width = Math.floor(windowWidth * view.width);
var height = Math.floor(windowHeight * view.height);
renderer.setViewport(left, bottom, width, height);
renderer.setScissor(left, bottom, width, height);
renderer.setScissorTest(true);
renderer.setClearColor(view.background);

camera.aspect = width / height;
camera.updateProjectionMatrix();

renderer.render(scene, camera);
}}

Answer

You can set materials as var reference outside the model and reach by this reference when you need to force the change. Material change will be applied to all models using this material.

var shaderMaterial = new THREE.ShaderMaterial(shaderProp);

var objectLoader = new THREE.ObjectLoader();
    objectLoader.load("male_model_object.json", function(object) {
        object.traverse(function (child) {
          if (child instanceof THREE.Mesh) {
              child.material = shaderMaterial;
          }
        }
    });
    scene.add(object);

function onDocumentKeyPress(event) {
...
    shaderMaterial.vertexShader.value = shader;
    shaderMaterial.needsUpdate = true;
/// make sure you are re-rendering scene, i don't see animation loop in you code
...

}