bullybear17
bullybear17

Reputation: 889

Three.js - Trying to load multiple material objects

I am working with three.js and I am trying to load multiple material objects. When I run the code, the first material object maps to the data properly. Once it rotates, the second material object then populates unexpectedly. Ideally I would like the first material object [cubeMaterial] to read in data[0] which is 49 and the second material object [cubeMaterialTwo] to read in data[1] which is 7.

Here is my code:

<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.js"></script>

let scene, camera, renderer;

let cubeGroup;

init();
animate();

function init() {

const data = [
[49, 7]
]

var i = 1;

width = 500
height = 500
fov = 9
aspect = 1/5
near = .1
far = 1000

loader = new THREE.TextureLoader()

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

camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.set(50, 30, 50);
camera.lookAt( scene.position );


cubeGeometries = data.map(row => {
 return row.map(c => {
  return new THREE.BoxBufferGeometry(0.2, c / 8, 0.2);
 })
})

var materialArray = [];

const cubeMaterial = new THREE.MeshBasicMaterial({
 map: loader.load('../path/to/.jpgOne')
});
cubeMaterial.color.convertSRGBToLinear();

const cubeMaterialTwo = new THREE.MeshBasicMaterial({
map: loader.load('../path/to/.jpgTwo')
});
cubeMaterialTwo.color.convertSRGBToLinear();

materialArray.push(cubeMaterial, cubeMaterialTwo);

const cubeMeshes = cubeGeometries.map(row => {
  return row.map(cubeGeometry => new THREE.Mesh(cubeGeometry, materialArray))
})

cubeGroup = new THREE.Group();
 data.forEach((row, i, iarr) => {
  row.forEach((d, j, jarr) => {
   cubeMeshes[i][j].position.set(
    i / iarr.length - 0.5,
    d / 8 * 0.5 - 0.6,
    j / jarr.length - 0.5);

   //cubeMeshes[i][j].scale.set(1,4,1);
   cubeGroup.add(cubeMeshes[i][j]);
  })
 })

const mainLight = new THREE.DirectionalLight(0xffffff, 5.0);
 mainLight.position.set(10, 10, 10);

const ambientLight = new THREE.HemisphereLight(0xddeeff, 0x202020, 3);

var material = new THREE.LineBasicMaterial({
 color: 0x0000ff
});

scene.add(cubeGroup);
scene.add(mainLight);
scene.add(ambientLight);


renderer = new THREE.WebGLRenderer({
  antialias: true
});

renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.outputEncoding = THREE.sRGBEncoding;
renderer.physicallyCorrectLights = true;

document.body.appendChild(renderer.domElement); 

}

function animate() {
 requestAnimationFrame( animate );
 cubeGroup.rotation.y += 0.005;
 renderer.render( scene, camera );

}

Upvotes: 0

Views: 488

Answers (1)

jscastro
jscastro

Reputation: 3780

I have tried your code with a minimum tweak, and it's loading both textures, but you are using them in the opposite sides of the meshes as you are passing the full materialArray to the Mesh constructor. I have created a fiddle loading two textures with your code to repro the issue, but it loads both.

  const cubeMaterial = new THREE.MeshBasicMaterial({
    map: new THREE.TextureLoader().load('https://i.postimg.cc/25m7H09s/metal1.jpg')
  });
  cubeMaterial.color.convertSRGBToLinear();

  const cubeMaterialTwo = new THREE.MeshBasicMaterial({
    map: new THREE.TextureLoader().load('https://i.postimg.cc/pXs9NqTN/OIP.jpg')
  });
  cubeMaterialTwo.color.convertSRGBToLinear();

Not sure if that's what you were trying to achieve or loading two meshes each one with a texture, but definitely the TextureLoader is loading both textures. enter image description here enter image description here

If this answer is solving your initial question, please mark it as "answer accepted", this way will also help other users to know it was the right solution to the problem.

EDIT: I have modified the fiddle loading two textures now with a random for each object... you can try it many times and you'll see it works.

  return row.map(cubeGeometry => new THREE.Mesh(cubeGeometry, materialArray[Math.round(Math.random())]))
  })

enter image description here

EDIT 2: I found the solution to your last issue, as said you need an iterator and each block will have a different texture. Here you have the new fiddle, and the relevant code is just these lines to replace the original.

  let index = 0;
  const cubeMeshes = cubeGeometries.map((row) => {
    index++;
    return row.map((cubeGeometry, index) => new THREE.Mesh(cubeGeometry, materialArray[index]))
  })

Upvotes: 1

Related Questions