What is the way to assign distinct colors to points in three.js through dat.gui based on their distance from the origin?

Currently, I am developing a 3D Pi Estimator using three.js. You can view the source code at https://jsfiddle.net/fny94e7w/.

let num_points = 5000;
            let in_sphere = 0;
            let out_sphere = 0;
            let geometry_point = new THREE.SphereGeometry( 0.1, 3, 2 );
            for (let i = 0; i < num_points; i++) {
                let material_point = new THREE.MeshBasicMaterial( { color: 0xffffff } );
                let point = new THREE.Mesh( geometry_point, material_point );
                let point_pos_x = (Math.random() - 0.5) * 20;
                let point_pos_y = (Math.random() - 0.5) * 20;
                let point_pos_z = (Math.random() - 0.5) * 20;
                if (Math.pow(point_pos_x, 2) + Math.pow(point_pos_y, 2) + Math.pow(point_pos_z, 2) <= 100) {
                    point.material.color.setHex( 0x42c5f5 );
                    in_sphere++;
                }
                else {
                    point.material.color.setHex( 0xffffff );
                    out_sphere++;
                }
                point.position.set(point_pos_x,
                                   point_pos_y,
                                   point_pos_z);
                scene.add( point );
            }

The points are colored based on their position relative to a sphere at the origin. I am seeking guidance on creating a GUI using dat.gui for interactive customization of point colors inside and outside the sphere.

I am also exploring the use of InstancedMesh to improve performance, as the simulation struggles with over 15000 points. The challenge lies in assigning different colors to points based on their positions. Any suggestions on utilizing InstancedMesh to address this issue and integrate it with dat.gui would be greatly appreciated.

Answer №1

Here's the updated version of your code utilizing InstancedMesh.

body {
  overflow: hidden;
  margin: 0;
}

#info {
  position: absolute;
  top: 10px;
  width: 100%;
  text-align: center;
  z-index: 100;
  display: block;
  color: white;
  font-family: 'Courier New', monospace;
  s
}

#lil-gui {
  left: 10px;
  top: 70px;
}
      
<div id="info">3d pi estimator <br> dots in sphere: 0 • dots outside sphere: • pi estimate: </div>
<script type="module">
import * as THREE from 'https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b6c2dec4d3d3f6c086988785809886">[email protected]</a>';
import { OrbitControls } from 'https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e99d819b8c8ca99fd9c7d8dadfc7d9">[email protected]</a>/examples/jsm/controls/OrbitControls.js';
import { GUI } from "https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="72061a00171732425c4341445c42">[email protected]</a>/examples/jsm/libs/lil-gui.module.min.js';


const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

const controls = new OrbitControls( camera, renderer.domElement );
controls.autoRotate = true;
camera.position.z = 30;
camera.position.y = 15;
controls.update();

const geometry_cube = new THREE.BoxGeometry( 20, 20, 20 );
const edges_cube = new THREE.EdgesGeometry( geometry_cube );
const cube = new THREE.LineSegments( edges_cube, new THREE.LineBasicMaterial( { color: 0xffffff } ) );
scene.add( cube );

const geometry_sphere = new THREE.SphereGeometry( 10, 32, 16 );
const material_sphere = new THREE.MeshBasicMaterial( { color: 0xffffff } );
const sphere = new THREE.Mesh( geometry_sphere, material_sphere );
sphere.material.transparent = true;
sphere.material.opacity = 0.5;
scene.add( sphere );

let num_points = 30000;
let in_sphere = 0;
let out_sphere = 0;
let geometry_point = new THREE.SphereGeometry( 0.1, 3, 2 );
let colorController = {
  color1: "#ffffff",
  color2: "#42c5f5"
};
let uniforms = {
  color1: {value: new THREE.Color(colorController.color1)},
  color2: {value: new THREE.Color(colorController.color2)}
};
let material_point = new THREE.MeshBasicMaterial( { 
  color: 0xffffff,
  onBeforeCompile: shader => {
    shader.uniforms.color1 = uniforms.color1;
    shader.uniforms.color2 = uniforms.color2;
    shader.vertexShader = `
      attribute float colorIdx;
      varying float vColorIdx;
      ${shader.vertexShader}
    `.replace(
      `#include <begin_vertex>`,
      `#include <begin_vertex>
        vColorIdx = colorIdx;
      `
    );
    //console.log(shader.vertexShader);
    shader.fragmentShader = `
      uniform vec3 color1;
      uniform vec3 color2;
      varying float vColorIdx;
      ${shader.fragmentShader}
    `.replace(
      `vec4 diffuseColor = vec4( diffuse, opacity );`,
      `
      vec3 finalColor = mix(color1, color2, vColorIdx);
      finalColor *= diffuse;
      vec4 diffuseColor = vec4( finalColor, opacity );
      `
    );
    //console.log(shader.fragmentShader);
  }
} );
let point = new THREE.InstancedMesh( geometry_point, material_point, num_points );
let dummy = new THREE.Object3D();
let colorIdx = [];
for (let i = 0; i < num_points; i++) {
    dummy.position.random().subScalar(0.5).multiplyScalar(20);
    dummy.updateMatrix();
    point.setMatrixAt(i, dummy.matrix);
    if (dummy.position.length() <= 10) {
        colorIdx.push(1);
        in_sphere++;
    }
    else {
        colorIdx.push(0);
        out_sphere++;
    }
}
geometry_point.setAttribute("colorIdx", new THREE.InstancedBufferAttribute(new Float32Array(colorIdx), 1));
scene.add(point);

let gui = new GUI({autoplace:false});
gui.domElement.id = "lil-gui"
gui.addColor(colorController, "color1").onChange(val => {uniforms.color1.value.set(val)});
gui.addColor(colorController, "color2").onChange(val => {uniforms.color2.value.set(val)});

document.getElementById("info").innerHTML = "3d pi estimator <br>" + "dots in sphere: " + in_sphere + " • dots outside sphere: " + out_sphere + " • pi estimate: " + ((6 * in_sphere) / (in_sphere + out_sphere)); 

function animate() {
    requestAnimationFrame( animate );
    controls.update(); // Required because of auto-rotation
    renderer.render( scene, camera );
};

animate();
</script>

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

Preventing touchstart default behavior in JavaScript on iOS without disrupting scrolling functionality

Currently experimenting with JavaScript and jQuery within a UIWebView on iOS. I've implemented some javascript event handlers to detect a touch-and-hold action in order to display a message when an image is tapped for a certain duration: $(document) ...

Analyzing and swapping objects within two arrays

Looking for a better way to append an array of objects customData to another array testData? If there are duplicate objects with the same name, replace them in the resulting array while maintaining their order. Here's my current approach in ES6 - any ...

Delay occurs unexpectedly when adding a class with jQuery to multiple elements

I am in the process of creating a flipping counter that is designed to change colors once it reaches a certain target number (in this case, 1000). However, I am noticing that the different sections of the counter do not change color simultaneously, there s ...

Tips on enabling or disabling an ASP button based on the selected value in a dropdown using a JavaScript function

I have an ASP dropdown and a button. I need the button to be disabled when the dropdown's selected value is the first index, and enabled when any other value is selected. Here is my code, however, it is not functioning as expected: function checkSele ...

combine ngClass properties if substitution is true

My directive includes replace: true in the definition. <my-custom-tag> </my-custom-tag> This is the template for the directive: <div data-ng-class="{'class1': condition1, 'class2': condition2}"> </div> When u ...

Utilizing ag-grid with Vue.js: Implementing TypeScript to access parent grid methods within a renderer

I've integrated ag-grid into my project and added a custom cell renderer: https://www.ag-grid.com/javascript-grid-cell-rendering-components/#example-rendering-using-vuejs-components Although the renderer is working well, I'm facing an issue whe ...

Can you explain the extent to which JavaScript's setTimeout() and clearTimeout() apply?

Approximately 30 seconds after a page is loaded or reloaded, a pop-up will be displayed under certain conditions. The following code successfully achieves this functionality: jQuery(document).ready(function($) { .......... if (localStorage.getItem ...

The scraping tool from Snipcart encountered issues while trying to capture product data in a Next.js

I am encountering an issue with Snipcart while using it in a Next.js app integrated with Strapi. The error message I receive when processing a payment is as follows: A 'cart-confirmation' error occurred in Snipcart. Reason: 'product-craw ...

Navigating attributes originating from the key in JSON: A guide to effective management

I'm facing a situation in my application where I have a JSON object structured like this: var pages = { home: { title: "Home", description: "The home page", file: "home.html", url: "/home" }, blog: { ...

Retrieving a JavaScript variable from a different script file

I have a JavaScript script (a) with a function as follows: function csf_viewport_bounds() { var bounds = map.getBounds(); var ne = bounds.getNorthEast(); var sw = bounds.getSouthWest(); var maxLat = ne.lat(); var maxLong = ne.lng(); ...

What is the best way to create an animated, step-by-step drawing of an SVG path

I am interested in creating an animated progressive drawing of a line using CSS with SVG/Canvas and JS. You can view the specific line I want to draw here <svg width="640" height="480" xmlns="http://www.w3.org/2000/svg"> <!-- Created with cust ...

Mapping dual textures onto a Three.js cube

Searching for an updated solution to this issue has been challenging. Many resources mention using MeshFaceMaterial, which is no longer available in three.js (last seen in version 53, current version is 84) From my research, it seems more effective to cre ...

What is the method by which the asynchronous function produces the ultimate output?

Is there a way to modify a Dojo framework-created class with an asynchronous method so that it only returns the final value instead of a Promise or any other type? ...

What is the quickest method to perform a comprehensive comparison of arrays and combine distinct objects?

I am currently working with NextJS and Zustand and I have a state in Zustand that consists of an array of objects: [{a:1, b:2}, {a:2, b:3}] Additionally, there is another incoming array of objects that contains some of the existing objects as well as new ...

Switch from Index.html to Index.html#section1

Currently, I am working on a website and sending someone a draft for review. However, the Home screen is designed as a 'a href' link with "#home". The issue arises when the website opens from my computer; it goes to ...../Index.html instead of .. ...

Which property is best suited for styling a phone number field in the MUI data grid in ReactJS?

I previously utilized the pattern attribute for input fields in pure HTML, but now I no longer have any input fields. What should be my next steps? Can you provide me with a reference in the MUI documentation? https://i.stack.imgur.com/ ...

Ensure the md-sidenav remains open by default

I have set up a md-sidenav in my project. I would like the sidenav to be open by default, while still maintaining an overlay effect on the page and allowing users to close the sidenav, thus avoiding the use of md-is-locked-open. Any suggestions on how I ca ...

Using PHP to upload images through AJAX increases efficiency

Worked tirelessly on this script all night still unable to fix the bug. The issue is that when I select an image and click upload, it uploads the current image file. Then, if I select another image and click upload, it uploads two new files along with the ...

What are the steps to modify the relative URL when using Express proxy?

To prevent the common CORS issue with client-side JavaScript code, I utilize a Node.js Express server. The server is configured with the following code: var app = express(); app.all('/Api/*', function (req, res) { proxy.web(req, res, { ...

Exploring the variable scope in Node.js with a focus on separating routes

My routing configurations are stored in an external folder. Find them in the ./routes directory This is how I set up my routes within the server.js file: app.get('/', routes.index); app.post('/validation', register.valid); The reg ...