Create an array of various sized spheres using a range of theta values using THREE.js

Currently, I am utilizing the following code snippet:

var geometry = new THREE.SphereGeometry( 15, 32, 16, 0, 2*Math.PI, 0, x);

This code generates a portion of a sphere resembling this shape:

https://i.sstatic.net/WArPm.png

The challenge I face is that I require thousands of similar shapes, all sharing the same center and radius but with unique rotations and small x values.

I have explored options like instancing, however, I haven't found a suitable method to achieve what I envision. Any insights or suggestions would be greatly appreciated.

Answer №1

Utilize an extra InstancedBufferAttribute to transmit phi angles per instance in InstancedMesh, and manipulate those values in the vertex shader to construct the desired parts by employing the .onBeforeCompile() method.

body{
  overflow: hidden;
  margin: 0;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="30445842555570001e0103061e00">[email protected]</a>/build/three.module.js";
import {OrbitControls} from "https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="384c504a5d5d780816090b0e1608">[email protected]</a>/examples/jsm/controls/OrbitControls.js";

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 5000);
camera.position.set(0, 0, 50);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", (event) => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

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

let light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));

const MAX_COUNT = 10000;
let g = new THREE.SphereGeometry(1, 20, 10, 0, Math.PI * 2, Math.PI * 0.25, Math.PI * 0.5);
let m = new THREE.MeshLambertMaterial({
  side: THREE.DoubleSide,
  onBeforeCompile: shader => {
    shader.vertexShader = `
      attribute float instPhi;
      
      // straight from the docs on Vector3.setFromSphericalCoords
      vec3 setFromSphericalCoords( float radius, float phi, float theta ) {

        float sinPhiRadius = sin( phi ) * radius;

        float x = sinPhiRadius * sin( theta );
        float y = cos( phi ) * radius;
        float z = sinPhiRadius * cos( theta );

        return vec3(x, y, z);

      }
      
      ${shader.vertexShader}
    `.replace(
      `#include <beginnormal_vertex>`,
      `#include <beginnormal_vertex>
        
        vec3 sphPos = setFromSphericalCoords(1., instPhi * (1. - uv.y), PI * 2. * uv.x); // compute position
        objectNormal = normalize(sphPos); // normal is just a normalized vector of the computed position
        
     `).replace(
      `#include <begin_vertex>`,
       `#include <begin_vertex>
        transformed = sphPos; // set computed position
       `
     );
    //console.log(shader.vertexShader);
  }
});
let im = new THREE.InstancedMesh(g, m, MAX_COUNT);
scene.add(im);

let v3 = new THREE.Vector3();
let c = new THREE.Color();
let instPhi = []; // data for Phi values
let objMats = new Array(MAX_COUNT).fill().map((o, omIdx) => {
  let om = new THREE.Object3D();
  om.position.random().subScalar(0.5).multiplyScalar(100);
  om.rotation.setFromVector3(v3.random().multiplyScalar(Math.PI));
  om.updateMatrix();
  im.setMatrixAt(omIdx, om.matrix);
  im.setColorAt(omIdx, c.set(Math.random() * 0xffffff))
  instPhi.push((Math.random() * 0.4 + 0.1) * Math.PI);
  return om;
});
g.setAttribute("instPhi", new THREE.InstancedBufferAttribute(new Float32Array(instPhi), 1));

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

</script>

You may consider using InstancedBufferGeometry for further enhancements. Let your creativity shine :)

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

Transform the API response from a string into an array containing multiple objects

How can I transform a string API response into an array of objects? When making a GET request, the result is returned as a single long string: const state = { strict: true, airports: [] }; const getters = { allAirports: (state) => state.ai ...

Exploring the power of VueJs through chaining actions and promises

Within my component, I have two actions set to trigger upon mounting. These actions individually fetch data from the backend and require calling mutations. The issue arises when the second mutation is dependent on the result of the first call. It's cr ...

How to showcase base64 encoded images in pug (jade) with node.js

Can anyone help with decoding this mysterious data and displaying the image? I'm using pug as my template engine. Below is the questionable data that needs to be shown as an image: /9j/4AAQSkZJRgABAQEAYABgAAD/4QBaRXhpZgAATU0AKgAAAAgABQ ...and so f ...

When using React MUI datatables, unable to align icons to the left

I'm currently working on implementing react mui datatables and I am looking to include additional buttons within the toolbar. Specifically, I would like to place an icon on the right-hand side of the toolbar. Here are my complete options: const op ...

Error message: "Angular dependencies and provider not accessible"

I recently came across a file upload script on Github that I decided to implement. <script type="text/javascript" src="{% static 'bower_components/angular-file-upload/angular-file-upload.min.js' %}"></script> Furthermore, I have cre ...

Angular 14 presents an issue where the injectable 'PlatformLocation' requires compilation with the JIT compiler; however, the '@angular/compiler' module is currently missing

I've encountered the following error and have tried multiple solutions, but none of them have been successful: Error: The injectable 'PlatformLocation' requires JIT compilation with '@angular/compiler', which is not available. ...

What is the best way to refresh the ITHit Ajax File Browser within an Angular single page application once all the components are already initialized?

Due to a variety of reasons that I won't delve into, I have managed to encapsulate the ITHit Ajax File browser within an Angular Controller, which is then loaded and enclosed within an Angular-UI-Router UI-View. All the configurations are set up thro ...

Tips for incorporating JavaScript into elements that have been modified using jQuery's .html() method

Consider this example: $('#key').on('click', function(){ $('.task').html("<button id='key'>Button</button>"+Date()); }) <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.j ...

How to make Angular 5 wait for promises to finish executing in a for loop

My task involves working with an array like this: arr = ['res1', 'res2', 'res3']; For each value in the arr, I need to make an API call that returns a promise. arr.forEach(val => this.getPromise(val)); The getPromise me ...

identify the alteration in course

At the moment, I'm engaged in a school assignment during my high school years. I'm interested in finding out if it's possible to access real-time data on different types of manoeuvres, such as turning left or right. Is there a specific funct ...

Mastering the Art of Content Swapping in SPA

Hey there! I'm in the process of creating a webpage using tornado io and incorporating various graphs. To add some single page app magic, I decided to swap out content within a div like so: <div id="chartType"> Chart goes here</div> <a ...

Use jQuery to compare the input values whenever they are modified

I am trying to synchronize the input values of two inputs as they are typed in. The code I have seems to work sometimes, but not consistently. Here is the code snippet: $('#google-querynav').keypress(function() { var text = $(this).val(); ...

Express: router.route continues processing without sending the request

I've implemented the following code in my Express application: var express = require('express'); // Initializing Express var app = express(); // Creating our app using Express var bodyParser = require(' ...

JQGrid will automatically conceal any row that contains a false value in a given cell

I'm attempting to conceal a row if a specific cell within it contains the value false. To achieve this, I have experimented with using a formatter in the following manner: $("#list").jqGrid({ //datatype: 'clientSide', ...

Retrieving data from getServerSideProps and utilizing it inside Layout component in Next.js

Currently, I am in the process of developing a web application with Next.js. This project involves creating an admin dashboard that will be utilized to manage various tasks, each with its own SSR page. DashboardLayout : export const DashboardLayout = ({ch ...

Which is more efficient: Implementing caching on the frontend or on the

Currently, I am using ajax to send requests to the backend server, where operations are performed and responses are received: function getData() { new Ajax().getResponse() .then(function (response) { // handle response }) .catch(functi ...

Utilizing reusable functionalities within Vuex

Currently, while working on my NUXT project, I am facing a situation where I find myself repeatedly copying the same actions into multiple store modules. To streamline this process, I have extracted these actions into a separate file and now import them in ...

A guide on utilizing should.js to verify object equality when dealing with a property value that is NaN

It appears that there may be a bug in should.js related to the special value NaN, which is not equal to itself. ({ a: 1, c: 3, b: 2, d: NaN }).should.eql({ a: 1, c: 3, b: 2, d: NaN }); Despite the expectation that this tes ...

Trigger jQuery function when a particular class of an element is modified

Is there a way to trigger an event when a specific class is added to a button element? I am trying to figure out how to listen for the class adding event. This is what I have so far: <script type="text/javascript"> $(document).ready(fu ...

Error! The function worker.recognize(...).progress is throwing an error. Any ideas on how to resolve this

Here is the code snippet: //Imports const express = require('express'); const app = express(); const fs = require("fs"); const multer = require('multer'); const { createWorker } = require("tesseract.js"); co ...