Changing the color of faces in Three.js: A beginner's guide

I am struggling to modify the color of a specific face on a mesh within a WebGL environment. While I can successfully change the entire mesh color, I am unable to target and update an individual face. The relevant code snippet can be found below:

// Updated Per Lee!

var camera = _this.camera;      
var projector = new THREE.Projector();
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1,                                  - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );

var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectObjects( kage.scene.children );

if ( intersects.length > 0 ) {
    face = intersects[0].face;
    var faceIndices = ['a', 'b', 'c', 'd'];         
    var numberOfSides = ( face instanceof THREE.Face3 ) ? 3 : 4;
    // assign color to each vertex of current face
    for( var j = 0; j < numberOfSides; j++ )  {
        var vertexIndex = face[ faceIndices[ j ] ];
    // initialize color variable
    var color = new THREE.Color( 0xffffff );
    color.setRGB( Math.random(), 0, 0 );
    face.vertexColors[ j ] = color;
    }
}

Additionally, I have created the object—a cube—in the following manner:

// this material causes a mesh to use colors assigned to vertices
var material = new THREE.MeshBasicMaterial( { 
    color: 0xf0f0f0, 
    shading: THREE.FlatShading,
    vertexColors: THREE.VertexColors 
});

var directionalLight = new THREE.DirectionalLight(0xEEEEEE);
directionalLight.position.set(10, 1, 1).normalize();
kage.scene.add(directionalLight);

var cube = new THREE.Mesh(new THREE.CubeGeometry(300, 300, 300,1,1,1), material);
cube.dynamic = true;
kage.scene.add(cube);

Despite changing the material, the cube consistently appears white regardless of light color. Although the intersection logic correctly identifies the selected face, the color remains unaltered.

This is my first time seeking help on Stackoverflow, so pardon any potential confusion in my edits.

Answer №1

  • Make sure to update the library to r53 for optimal performance.
  • Include vertexColors: THREE.FaceColors in the material settings.
  • To apply random colors to faces, use

    face.color.setRGB( Math.random(), Math.random(), Math.random())
    .

    No longer necessary to iterate through all 4 sides (a,b,c,d) for THREE.Face4 or 3 sides (a,b,c) for THREE.Face3.

    This feature is compatible with both WebGL and Canvas rendering.

See example here

Download three.js r53 here

Answer №2

If you have a geometry named "myGeometry" that contains the face you want to change the color of, and you know the index of the specific face as "faceIndex", you can follow these steps:

// Define characters for labeling face indices
var faceIndices = ['a', 'b', 'c', 'd'];  

var face = myGeometry.faces[ faceIndex ];   

// Check if the face is a triangle or a quadrilateral
var numberOfSides = ( face instanceof THREE.Face3 ) ? 3 : 4;

// Assign colors to each vertex of the current face
for( var j = 0; j < numberOfSides; j++ )  
{
    var vertexIndex = face[ faceIndices[ j ] ];
    // Initialize color variable
    var color = new THREE.Color( 0xffffff );
    color.setRGB( Math.random(), 0, 0 );
    face.vertexColors[ j ] = color;
}

To ensure that the mesh reflects the vertex colors on its faces, use the following material:

// This material enables the mesh to display colors assigned to vertices
var cubeMaterial = new THREE.MeshBasicMaterial( 
    { color: 0xffffff, shading: THREE.FlatShading, 
    vertexColors: THREE.VertexColors } );

Answer №3

As a newcomer to three.js, I find many of the examples to be unnecessarily lengthy and complex. The following snippet allows you to color all 12 triangular faces of a cube in WebGLRenderer r73.

One observation I made while working on this is that the face order may seem a bit peculiar, especially for someone like me who is still learning.

var geometry = new THREE.BoxGeometry( 1, 1, 1 );
console.log(geometry.faces.length); // 12 triangles
geometry.faces[0].color = new THREE.Color(0x000000); //Right 1
geometry.faces[1].color = new THREE.Color(0xFF0000); //Right 2
geometry.faces[2].color = new THREE.Color(0xFF8C08); //Left 1
geometry.faces[3].color = new THREE.Color(0xFFF702); //Left 2
geometry.faces[4].color = new THREE.Color(0x00FF00); //Top 1
geometry.faces[5].color = new THREE.Color(0x0000FF); //Top 2
geometry.faces[6].color = new THREE.Color(0x6F00FF); //Bottom 1
geometry.faces[7].color = new THREE.Color(0x530070); //Bottom 2
geometry.faces[8].color = new THREE.Color(0x3F3F3F); //Front 1
geometry.faces[9].color = new THREE.Color(0x6C6C6C); //Front 2
geometry.faces[10].color = new THREE.Color(0xA7A7A7);//Rear 1
geometry.faces[11].color = new THREE.Color(0xFFFFFF);//Rear 2

Answer №4

According to the documentation on Three JS Geometry, in order to notify a change in faces, the property Geometry.elementsNeedUpdate must be set to true.

The code below demonstrates how to alter the colors of all faces:

mesh.material.vertexColors = THREE.FaceColors

var faces = mesh.geometry.faces;

for(var i = 0 ; i < faces.length; i++){
  var face = faces[i];
  var color = new THREE.Color("rgb(255, 0, 0)");
  face.color = color;
}

mesh.geometry.elementsNeedUpdate = true;

render();

Answer №5

It seems that the approach mentioned above is specifically tailored for the WebGLRenderer. For a solution that caters to both the CanvasRenderer and WebGLRenderer, it may require a more intricate process, although the outcome is likely to be more efficient in terms of memory usage and performance.

Upon reviewing the source code of THREE.js Projector.js, here's how I tackled it:

// initializing the face materials
var material_1 = new THREE.MeshLambertMaterial(
    {color : 0xff0000, shading: THREE.FlatShading, overdraw : true}
);
var material_2 = new THREE.MeshLambertMaterial(
    {color : 0x00ff00, shading: THREE.FlatShading, overdraw : true}
);

// creating a geometry object 
var geom = new THREE.CubeGeometry(1,1,1);

// directly adding materials to the geometry
geom.materials.push(material_1);
geom.materials.push(material_2);

// assigning materials to individual faces (note the index refers to the geometry, not the material)
for( var i in geom.faces ) {
    var face = geom.faces[i];
    face.materialIndex = i % geom.materials.length;
}

// establishing a unique material for the mesh to instruct the renderer to use face materials
var material = new THREE.MeshFaceMaterial();
var mesh = new THREE.Mesh(geom, material);

This snippet is derived from functional code that I've utilized before. While I haven't executed this exact block of code and my track record isn't flawless at first attempts, I hope it provides assistance to those encountering challenges.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the process of invoking a function from a different component in Vue 3?

I attempted to use the $on method and this.$root.$refs.compname_component = this;, but encountered some errors. Please see my code below: formComponent.vue <template> <div v-if="showForm"> create Form </div> </templa ...

Is there a way to identify the specific list item that a draggable element has been dropped onto within a jQuery sortable with connected draggable lists?

Take a look at these two sets of items: user's inventory <ul id='list1'> <li>Apple</li> <li>Banana</li> </ul>available products <ul id='list2'> <li>Orange</li> ...

A recursive function in ECMAScript 6 using promises

I am currently in the process of developing a foundational class for sequelize.js. This particular class will handle the association of all related tables, with the includeFk function responsible for executing this task. The function involves the use of pr ...

Obtain a random item from an array containing elements with assigned weights

In my game development project, I have an array of objects representing creatures. Each creature object includes a unique identifier and a corresponding weight or probability for spawning. I am struggling to create an algorithm that will randomly spawn cr ...

Are you having trouble grasping JavaScript concepts?

Can Javascript replicate Smalltalk's doesNotUnderstand or Ruby's method_missing functionality? ...

What is the reason for the find() method not displaying the most recent data from a MongoDB database in an Express.js application?

Upon calling the app.post('/form-submit', funtion(req, res)) method, my expectation is for it to first save the data using save(). This works fine, but then when I call the find() method, it shows all the data from the mongoDB database except for ...

Tips on concealing modal popup when the page refreshes successfully

I implemented a progress modal popup to show progress for page reloads. This script is set to the master page and injects the progress modal popup when the form submit event is fired: <script type="text/javascript"> function ...

Which is more recommended to use in AJAX (XMLHttpRequest) - eventListener or readyStateChange method?

As I revisited a video from WWDC12 discussing advanced effects with HTML5, I couldn't help but notice that for the demo they utilized req.addEventListener("load",callback,true) instead of the usual onreadystatechange. This made me wonder: what differ ...

After reloading the page, VueJS and Nuxt.js cause page breaks

I've encountered a strange issue with my application. I have multiple pages and everything seems fine initially: https://i.sstatic.net/xYxxy.png However, upon reloading the page, this is what happens: https://i.sstatic.net/Jo3tz.png Upon pressing C ...

Automatic closing of multile- vel dropdowns in Bootstrap is not enabled by default

I have successfully implemented bootstrap multilevel dropdowns. However, I am facing an issue where only one child is displayed at a time. <div class="container"> <div class="dropdown"> <button class="btn btn-default dropdown-to ...

Adding external stylesheets or libraries in Express is a simple process that can greatly

Currently, I am in the process of developing a todo application using the express framework on a node server. The starting point for my application is an index.ejs file located in the same folder as my jquery.min.js file. However, when I attempt to include ...

Can jQuery effortlessly glide downward, come to a stop, continue downward, and then move upwards?

My webpage features a large table created and populated automatically every minute using ajax. The code structure is as follows: $(document).ready(function(){ setInterval(function(){ $.ajax({ //code to call backend, get the data, ...

The image sequence animation only loads once and does not continue indefinitely

Here is my code snippet: I have a sequence of 15 images that should load one after the other in a loop with a specific time interval. However, I am facing a bug where the images keep playing infinitely when the page loads, but I want them to play only once ...

The image you are looking for on Amazon S3 cannot be found. It is necessary to

Currently, I have a meteor application where I utilize a node framework called knox to upload images to S3. The process works smoothly, but upon receiving the success response from S3 containing the image link, I encounter an issue when attempting to disp ...

Tips for displaying a Rails action without a layout in html format using Ajax

Is it possible to render the new action without the application layout and without altering the current code structure? class FoobarController < ApplicationController def new @foobar = Foobar.new end # ... end When a user clicks on = link_ ...

Error message: "User not found during passport authentication"

I am currently in the process of developing an authentication system for my website. However, I am encountering a specific error message when attempting to log in with any combination on the website: ReferenceError: user is not defined user is not define ...

Why does the Mongoose query findOne({params}) return null when it successfully runs in the mongo shell?

Here are the software versions currently being used: mongoose 4.10.8, mongodb 3.4, express 4.13.4, nodejs 6.11.1, npm 3.10.10, When querying in the Mongo shell, I can easily find a user using findOne: > db.users.findOne({"admin":"true"}).pretty() & ...

Is it advisable to Utilize ES6 Classes in Javascript for Managing React State?

Is it recommended to use ES6 classes directly as React state? I am interested in creating an ES6 class that: Contains member variables that will trigger re-renders on the frontend when changed. Includes methods that sync these member variables with the ...

Tips for refreshing Trackball controls in three.js

In my three.js project, I am faced with the challenge of updating the trackball controls upon window resize. I have found that updating the entire controls by calling the function with new input variables is necessary. Unfortunately, recreating the contr ...

Using JQuery to assign a value to a hidden input field

How do I add value to a hidden input field? In this scenario, the input is created as a variable and later inserted into the DOM if necessary. Here is the code snippet: <script> var form = $('form#small_ad_form'), help = $('di ...