Trying to paint each cube face with a different color, I found a thread that presents a way to achieve this:
var geometry = new THREE.BoxGeometry(5, 5, 5);
for (var i = 0; i < geometry.faces.length; i++) {
geometry.faces[i].color.setHex(Math.random() * 0xffffff);
}
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
vertexColors: THREE.FaceColors
});
But with three.js r86, I get the following result:
Got the triangles that make up each face, painted individually.
To achieve the desirable effect, I used the following adaptation of the above code:
var geometry = new THREE.BoxGeometry(5, 5, 5);
for ( var i = 0; i < geometry.faces.length; i += 2 ) {
var faceColor = Math.random() * 0xffffff;
geometry.faces[i].color.setHex(faceColor);
geometry.faces[i+1].color.setHex(faceColor);
}
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
vertexColors: THREE.FaceColors
});
But this all seems a bit over worked!
'use strict';
var camera, scene, renderer, cube;
init();
render();
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// renderer
renderer = new THREE.WebGLRenderer({
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
camera.position.z = 12;
// Mesh - cube
var geometry = new THREE.BoxGeometry(5, 5, 5);
for (var i = 0; i < geometry.faces.length; i += 2) {
var faceColor = Math.random() * 0xffffff;
geometry.faces[i].color.setHex(faceColor);
geometry.faces[i + 1].color.setHex(faceColor);
}
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
vertexColors: THREE.FaceColors
});
cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Light
var pointLight = new THREE.PointLight(0xFFFFFF);
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
scene.add(pointLight);
}
function render() {
cube.rotation.x = 16;
cube.rotation.y = 4;
cube.rotation.z -= 5;
renderer.render(scene, camera);
}
body,
canvas {
margin: 0;
padding: 0;
}
body {
overflow: hidden;
background-color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/86/three.js"></script>
Am I missing something on three.js to accomplish the face painting as a whole ?
Using groups will split the geometry in 6 faces, for drawing a simple cube you can also use a simple custom
ShaderMaterial
.Splitting geometry in 6 groups requires more draw calls, instead of using 1 draw call for drawing a cube you are using 6, one for each face.
Using a
ShaderMaterial
requires only 1 draw call:Vertex Shader:
Fragment Shader:
This way you could also use GLSL color blending for merging different colors.
Custom
ShaderMaterial
just setting vertex and fragment shader source strings:Color Cube custom
Mesh
:Use it:
If you switch to
BufferGeometry
you can usegroups
to control the material of sections of your geometry. Groups are based on the vertex indices, and allow you to define a material index, which will reference a material inside an array of materials.Consider:
This tells the geometry to start a new group of triangles at indices index 12, and accounts for 6 indices (which reference 6 vertices). The final parameter tells the group of triangles to use material index 2 (index 2 of the array of materials you use to create the mesh).
In the example below, I've given each side of a cube a different color. You might think this is the same effect as setting face colors, but note that this is setting a material per group, not just a color, which can lead to creating some really cool effects.
Edit: Adding a second example using the base
BoxBufferGeometry
Based on pailhead's comment to the original post, here's a snippet which uses unmodified
BoxBufferGeometry
. But as they mentioned in their comment, you'll still need to know which group corresponds to which face.