Mizok.H
Mizok.H

Reputation: 463

how to render a tetrahedron with different texture on each face (using three.js)?

I have tried a lot but still can't solve this..

How can I render a tetrahedron with different texture on each face?

At beginning I was trying this way.

import * as THREE from 'three';

window.onload = () => {
  const scene = new THREE.Scene()
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
  const renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(window.innerWidth, window.innerHeight)
  document.body.appendChild(renderer.domElement)
  var geometry = new THREE.CylinderGeometry(0, 2, 3, 3, 3, false)
  var materials = [
    new THREE.MeshBasicMaterial({ color: 0xff00ff }),
    new THREE.MeshBasicMaterial({ color: 0xff0000 }),
    new THREE.MeshBasicMaterial({ color: 0x0000ff }),
    new THREE.MeshBasicMaterial({ color: 0x5100ff })
  ]


  var tetra = new THREE.Mesh(geometry, materials)
  scene.add(tetra)
  renderer.render(scene, camera)
  camera.position.z = 5;
  var ambientLight = new THREE.AmbientLight(0xffffff, 0.5)
  scene.add(ambientLight)

  function animate() {
    requestAnimationFrame(animate)
    tetra.rotation.x += 0.04;
    tetra.rotation.y += 0.04;
    renderer.render(scene, camera)
  }
  animate()
}

I use a cylinder geometry to "make" a fake tetrahedron.

But I found that I can't texturing each face of this "tetrahedron", bc cylinder geometry actually have only 3 faces.

Does anyone know how to do it?

P.S. I have also tried TetrahedronGeometry but it just didn't work, I guessed it was because TetrahedronGeometry is basically BufferGeometry and there are no faces property on it.

Upvotes: 1

Views: 378

Answers (2)

Mizok.H
Mizok.H

Reputation: 463

Finally I understood how to make it work using three.js TetrahedronGeometry.

Actually making our own geo is not necessary, but we will have to reset uv array if we are using three.js TetrahedronGeometry.

private initGeometry(){
    const radius = this.config.size*Math.sqrt(6)/4;
    this.geometry = new THREE.TetrahedronGeometry(radius,0);
    console.log(this.geometry.attributes.uv.array);
    this.geometry.addGroup(0, 3, 0);
    this.geometry.addGroup(3, 3, 1);
    this.geometry.addGroup(6, 3, 2);
    this.geometry.addGroup(9, 3, 3);
    this.geometry.setAttribute("uv", new THREE.Float32BufferAttribute([ // UVs, 
//numbers here are to describe uv coordinate, so they are actually customizable
// if you want to customize it, you have to check the vertices position array first. 
    0,0,
    1, 0,
    0.5, 1,
    //
    1, 0,
    0.5, 1, 
    0,0,
    //
    1, 0,
    0.5, 1,
    0,0,
    //
    0,0,
    1, 0,
    0.5, 1
  ], 2));
    this.geometry.rotateY(-Math.PI);
  }

Upvotes: 1

prisoner849
prisoner849

Reputation: 17596

You can build your own geometry or modify an existing one. To have different materials on sides, use groups.

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/[email protected]";
import {OrbitControls} from "https://cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls"

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 5, 10).setLength(3);
let renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener("resize", event => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  rendrer.setSize(innerWidth, innerHeight);
})

let controls = new OrbitControls(camera, renderer.domElement);

// https://discourse.threejs.org/t/tetrahedron-non-indexed-buffer-geometry/12542
// tetrahedron
// ---------------------------------------------------------------------------------------
var pts = [ // https://en.wikipedia.org/wiki/Tetrahedron#Coordinates_for_a_regular_tetrahedron
  new THREE.Vector3(Math.sqrt(8 / 9), 0, -(1 / 3)),
  new THREE.Vector3(-Math.sqrt(2 / 9), Math.sqrt(2 / 3), -(1 / 3)),
  new THREE.Vector3(-Math.sqrt(2 / 9), -Math.sqrt(2 / 3), -(1 / 3)),
  new THREE.Vector3(0, 0, 1)
];

var faces = [ // triangle soup
  pts[0].clone(), pts[2].clone(), pts[1].clone(),
  pts[0].clone(), pts[1].clone(), pts[3].clone(),
  pts[1].clone(), pts[2].clone(), pts[3].clone(),
  pts[2].clone(), pts[0].clone(), pts[3].clone()
];

var geom = new THREE.BufferGeometry().setFromPoints(faces);
geom.rotateX(-Math.PI * 0.5);
geom.computeVertexNormals();

geom.setAttribute("uv", new THREE.Float32BufferAttribute([ // UVs
  0.5, 1, 0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001,
  0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001, 0.5, 1,
  0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001, 0.5, 1,
  0.06698729810778059, 0.2500000000000001, 0.9330127018922194, 0.2500000000000001, 0.5, 1
], 2));
geom.addGroup(0, 3, 0);
geom.addGroup(3, 3, 1);
geom.addGroup(6, 3, 2);
geom.addGroup(9, 3, 3);
// ---------------------------------------------------------------------------------------

let tl = new THREE.TextureLoader();
let tp = "https://threejs.org/examples/textures/";
let tetra = new THREE.Mesh(geom, [
  new THREE.MeshBasicMaterial({map: tl.load(tp + "uv_grid_opengl.jpg")}),
  new THREE.MeshBasicMaterial({map: tl.load(tp + "colors.png")}),
  new THREE.MeshBasicMaterial({map: tl.load(tp + "brick_diffuse.jpg")}),
  new THREE.MeshBasicMaterial({map: tl.load(tp + "758px-Canestra_di_frutta_(Caravaggio).jpg")})
])
scene.add(tetra);

renderer.setAnimationLoop(()=> {
  renderer.render(scene, camera);
});
</script>

Upvotes: 2

Related Questions