The most effective method for crafting a seaside parasol in the Three.js framework while maximizing resource usage

Being new to Three.js, I am really enjoying how easy it is to create simple scenes with minimal effort. Currently, I am working on designing a beach scene and my goal is to include 10 thousand beach umbrellas in the scene. To achieve this, I have been using cones for the canopy and cylinders for the poles which has worked quite well. However, to enhance the realism of the scene, I would like to add stripes to the canopy of the umbrellas, similar to what you see on typical beach umbrellas.

I know there are a few different ways I can achieve this:

  • Using a texture
  • Changing material for each face
  • Creating each stripe as a separate mesh

Considering that I plan to have around 10 thousand umbrellas in my scene, I want to ensure that the method I choose keeps the scene lightweight. Therefore, I would appreciate any insights into which approach would be best for optimizing performance while achieving the desired visual effect.

Thank you for your assistance!

Answer №1

Feel free to experiment with instancing:

body{
  overflow: hidden;
  margin: 0;
}
<script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="daaeb2a8bfbf9aeaf4ebece3f4ea">[email protected]</a>/build/three.webgpu.js",
      "three/addons/": "https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="097d617b6c6c493927383f302739">[email protected]</a>/examples/jsm/"
    }
  }
</script>
<script type="module">
import * as THREE from "three";
import {uv, vec2, vec3, fract, attribute, select} from "three";
import {OrbitControls} from "three/addons/controls/OrbitControls.js";
import { mergeGeometries } from "three/addons/utils/BufferGeometryUtils.js";

console.clear();

let scene = new THREE.Scene();
scene.background = new THREE.Color("skyblue");
let camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 1, 1).setLength(10);
let renderer = new THREE.WebGPURenderer({antialias: true});
renderer.setPixelRatio( devicePixelRatio );
renderer.setSize( innerWidth, innerHeight );
document.body.appendChild(renderer.domElement);

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

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

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

let circle = 100;

let sand = new THREE.Mesh(
  new THREE.CircleGeometry(circle, 32).rotateX(-Math.PI * 0.5),
  new THREE.MeshLambertMaterial({color: "#F6DCBD"})
);
scene.add(sand);

let gs = [
  new THREE.CylinderGeometry(0.025, 0.025, 0.9, 3, 1, true).translate(0, 0.45, 0),
  new THREE.LatheGeometry([
    [1, 0.8], [0.66, 0.9], [0.33, 0.96], [0, 1]
  ].map(p => {return new THREE.Vector2(...p)}),
  8)
];
gs.forEach((g, gIdx) => {
  g.setAttribute("color", new THREE.Float32BufferAttribute(new Array(g.attributes.position.count * 3).fill(gIdx), 3));
})
let g = mergeGeometries(gs);
let m = new THREE.MeshLambertNodeMaterial({vertexColors: true});
let amount = 10000;
let io = new THREE.InstancedMesh(g, m, amount);

let dummy = new THREE.Object3D();
let dummyColor = new THREE.Color();
let instColor = [];
for(let i = 0; i < amount; i++){
  dummy.position.setFromCylindricalCoords(Math.sqrt(circle * circle * Math.random()), Math.random() * 2 * Math.PI, 0);
  dummy.rotation.y = Math.PI * 2 * Math.random();
  dummy.rotation.z = Math.PI * 0.05 * Math.sign(Math.random() - 0.5);
  dummy.updateMatrix();
  io.setMatrixAt(i, dummy.matrix);
  dummyColor.setHSL(Math.random(), 0.75, 0.5);
  instColor.push(dummyColor.r, dummyColor.g, dummyColor.b);
}
g.setAttribute("instColor", new THREE.InstancedBufferAttribute(new Float32Array(instColor), 3));

// TLS magic is here
let uvScaled = uv().mul(vec2(1., 3.)).toVar();
let iColor = attribute("instColor").toVar();
let col = select(fract(uvScaled.y).greaterThan(0.5), vec3(1., 1., 1.), iColor).toVar();
m.colorNode = col;

scene.add(io);

renderer.setAnimationLoop(() => {
  controls.update();
  renderer.render(scene, camera);
})
</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

Revamp the style of the date field in a Material UI dialog

I'm currently working on a React project where I am using Material-UI's date picker component to display date items. However, I find that the default style does not meet my requirements. I would like to use a selector for displaying dates in the ...

Challenges with Performance in IONIC Mobile Applications

Currently, we are in the final stages of developing a high-profile mobile application for one of our clients using the IONIC framework. The application performs well when accessed through a Web/Mobile Browser. However, once it is ported into a mobile appli ...

Chrome Extension to Emphasize Every Word

As a novice, I am embarking on the journey of creating my own chrome extension. The idea is to design a popup.html file that showcases a "highlight" button. The functionality would involve clicking this button to highlight all words on the page. Here&apos ...

How to dynamically include a test file in CasperJS using a loop and the require function

A question has come up regarding extended testing within loops. The scenario involves a 3-level loop structure, incorporating URLs, Testfiles, and Viewportsizes as displayed below: var navigation = [ "http://www.url_1.com", "http://www.url_2.com", " ...

Tips for achieving a seamless transition between elements of varying heights in your Bootstrap carousel

I'm currently working on a Bootstrap carousel project with slides of varying heights. The transition animation between slides is quite choppy due to the different sizes of content. I'm looking for a solution to make the transition smoother and mo ...

Google Feed API - Retrieving saved data from RSS feed cache

We have implemented the Google Feed API to display our latest blog posts on our website. However, even after 24 hours, our most recent post is still not appearing on our site. Despite confirming that the RSS feed contains the newest content, it seems that ...

Retrieve the text contained within a specific element's paragraph

Is there a way to extract the text content from a <p> tag that is located within an <li> element? Sample HTML code: <ul> <li onclick="myfunction()"> <span></span> <p>This Text</p> </li> &l ...

Flag form field as invalid in AngularJS

Struggling to implement server-side form validation in an AngularJS app? Finding it tricky to invalidate a form field and show an error message? Here's the setup of my app: I have a model 'client' with a controller Accounts.controller(&ap ...

Hey there, I'm looking to use different CSS fonts on Windows and Mac for the same page on a web application. Can someone please guide me on how to accomplish this?

In order to tailor the font based on the operating system, the following criteria should be followed: For Windows: "Segoe UI" For Mac: "SF Pro" Attempts have been made using the code provided below, but it seems to load before the DOM and lacks persisten ...

Difficulty displaying data from PapaParse in VueJS despite successful retrieval in console

My first attempt at using PapaParse is running into some issues. I am successfully parsing a remote CSV file and storing the data, as confirmed by console.log. However, when I try to output it with a v-for loop, nothing seems to be working. To achieve thi ...

Implementation of Repetition Function

When working with the TypeScript example above, I encountered 2 errors. The first error was related to `i` in the second console.log due to the use of the 'let' keyword. The second error was regarding 'test' in the first line, stating i ...

Eliminate spacing in MaterialUi grids

As I work on a React project, I am faced with the task of displaying multiple cards with content on them. To achieve this layout, I have opted to use MaterialUi cards within Material UI grids. However, there seems to be an issue with excessive padding in t ...

Comparing throwing exceptions in Node.js and Gevent

During a recent tech gathering, I heard an interesting claim about the behavior of callbacks and exceptions in Node.js and Gevent. The person mentioned that if a callback throws an exception in Node.js, it can crash the entire process, whereas in Gevent, a ...

In Backbone.js, specialized events are dispatched to cater to unique needs

In search of a sleek JavaScript animation to have some balls gracefully moving within a canvas, I aim to implement collision detection using custom events managed through Backbone.js rather than resorting to an intricate nested loop to monitor interactions ...

Implementing watch functionality with array in Vuejs for bidirectional communication between parent and child components

Here is a simplified version of a parent component I created: // parent component <template> <layout v-for="(value, idx) in array" :pickUpLength="array.length" :idx="idx" :key="idx" > <button @click="addArray">a ...

Generating data within an express route (with the use of socket.io-client)

Recently, I made the decision to refactor my code in order to separate the front and back end, which were previously combined into one service. However, I am now facing an issue where I need the web server to emit data to the data server after validation. ...

The import statement in node.js must be inside a module, cannot be used outside

While I was in the midst of working on my project within the model.js file, I encountered a situation where I needed to import the model.js file into my Shareplace.js file. Unfortunately, upon attempting this, an error message appeared in the console of my ...

Updating content in AngularJS based on the sidebar can be achieved by following these steps:

Yesterday, I posed a question about how to implement multiple views with Angular in order to have a header and sidebar. After receiving some helpful insights, I was able to make progress on creating a header and sidebar for my AngularJS App. You can view ...

Trouble with NodeJS async/await - navigating through function arguments

Currently, I am attempting to perform web scraping using a particular library while implementing Node's async/await method in my code. Within the function named 'sayhi', I have created a variable 'page' and encountered an issue wh ...

Tips for creating a personalized URL for each user

Here is the updated code for routes.js and login.ejs: `module.exports = function(app, passport) { // ===================================== // HOME PAGE (with login links) ======== // ===================================== app.get('/&a ...