What is the process for setting up a particle system to resemble a spherical cap?

For my Three.js project, I am working on creating a snowfall with particles inside a snowball made of sphereGeometry - a traditional Christmas snowball. The particles have been generated using THREE.BufferGeometry(), and each has been assigned an initial position in terms of x, y, z coordinates.

I'm wondering if there is a way to ensure that these particles are only visible within the sphere. Currently, I've attempted to address this by making particles outside the sphere the same color as the background, but it's not ideal.

Is there a method to make the particles outside the sphere invisible, perhaps by setting them as transparent?

Alternatively, how can I initialize the particles as a spherical cap? Any suggestions would be appreciated!

This is how I'm setting up the positions for the particles (in a parallelepiped style):

for(i=0; i<n; i++){
    init_pos_y[i] = 50 + (Math.random()-0.5)*20;
    init_pos_x[i] = (Math.random()-0.5)*100;
    init_pos_z[i] = (Math.random()-0.5)*100;
    acceleration[i] = Math.random()*1;

Within the Vertex Shader, here's how I'm handling the particle movement and color assignment (with opacity changes based on their location inside or outside the sphere):

void main(){

    vec3 p = position; 
    p.x = initial_position_x;
    p.z = initial_position_z;

    if (initial_position_y - time * acceleration > -32.8 + min_level){  
        p.y = initial_position_y - time * acceleration;
    }
    else{
        p.y = -33.8 + min_level;
    }
    float opacity;

    if (p.x*p.x + p.y*p.y + p.z*p.z > 2490.0){ 
        opacity = 0.40;
        vColor = vec4( customColor, opacity );              
    }
    else{
        opacity = 1.0;
        vColor = vec4( customColor2, opacity );
    }

    gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);            
    vUv = projectionMatrix * vec4(p, 1.0);
    gl_PointSize = 3.0*acceleration;
}

Answer №1

To begin, arrange your points in a cylindrical formation (randomly inside a circle and at varying heights). You can achieve this using the setInCircle() function.

Next, make necessary modifications to the shader code. I recommend utilizing .onBeforeCompile() to ensure you can alter specific parts while maintaining all other material functionalities.

In the shader, update the y-value by adding the distance (time * speed), then divide it by 10 using the mod() function. This will create a cyclical movement from top to bottom within the range of 5 to -5.

Lastly, verify if the length of the transformed vector is less than or equal to the specified radius. Send the result as a varying variable to the fragment shader, where you can discard a pixel if the value is below 0.5.

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.setScalar(10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

scene.add(new THREE.GridHelper(10, 10));

var pts = [];
var radius = 5;
var pointsCount = 5000;

for (i = 0; i < pointsCount; i++) {
  let v2 = setInCircle().multiplyScalar(radius);
  let v3 = new THREE.Vector3(v2.x, THREE.Math.randFloat(-radius, radius), v2.y);
  pts.push(v3);
}

var geom = new THREE.BufferGeometry().setFromPoints(pts);
var uniforms = {
  speed: {
    value: 1
  },
  time: {
    value: 0
  },
  radius: {
    value: radius
  }
}
var mat = new THREE.PointsMaterial({
  color: "magenta",
  size: 0.05
});
mat.onBeforeCompile = shader => {
  shader.uniforms.speed = uniforms.speed;
  shader.uniforms.time = uniforms.time;
  shader.uniforms.radius = uniforms.radius;
  shader.vertexShader = `
    uniform float speed;
    uniform float time;
    uniform float radius;
    varying float vVisible;
  ` + shader.vertexShader;
  
  shader.vertexShader = shader.vertexShader.replace(
    `#include <begin_vertex>`,
    `#include <begin_vertex>
    transformed.y = mod((transformed.y - speed * time) - 5., 10.) - 5.;
    vVisible = length(transformed) <= radius ? 1.: 0.;
  `
  );
  shader.fragmentShader = `
    varying float vVisible;
  ` + shader.fragmentShader;
  
  shader.fragmentShader = shader.fragmentShader.replace(
    `void main() {`,
    `void main() {
      if (vVisible < 0.5) discard;
    `
  );

}
var points = new THREE.Points(geom, mat);
scene.add(points);

function setInCircle() {
  let v = new THREE.Vector2();
  v.set(
    THREE.Math.randFloat(-1, 1),
    THREE.Math.randFloat(-1, 1)
  )
  return v.length() <= 1 ? v : setInCircle();
}

var clock = new THREE.Clock();

renderer.setAnimationLoop(() => {
  uniforms.time.value = clock.getElapsedTime();
  renderer.render(scene, camera)
});
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://threejs.org/build/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></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

Generate a new tree structure using the identifiers of list items within an unorganized list

Attempting to convert the id's of li's in a nested unordered list into valid JSON. For example, consider the following list. To be clear, the goal is not to create the UL list itself, but rather the JSON from the li id's <ul class="lis ...

Ways to retrieve the current state within a function after invoking the setState method

I'm currently working on a function to store the blogPost object in a document within my Firestore database. The process I have in mind is as follows: Click on the SAVE button and initiate the savePost() function The savePost() function should then ...

How can I develop a "mock" media player using javascript?

Let me explain my setup. Currently, I have two HTML5 audio elements, which I'll refer to as Master and Slave. Both of these elements load the same media file, but the Slave has its audio muted by default. Each player can control the other (pause, p ...

What methods can be used to strategically incorporate gray into both the left and right sides of a page design?

I'm currently working on an asp.net MVC layout page and I'm trying to create a layout where the left side and right side are gray. However, I'm not sure how to achieve this using HTML, CSS, or Bootstrap. I specifically need to know how to ...

Confirming CakePHP Deletion: A Delicious Decision

I'm having an issue with the CakePHP delete JavaScript confirmation dialog. Here is the code I am using: <td><?php echo $this->Html->link('Delete', array('controller' => & ...

Add the text received from the Ajax request to an array specifically designed for AmCharts

Hello, I'm new to JavaScript and seeking assistance. My goal is to create a chart with real-time data from my MCU, but I'm unsure about pushing a string into an array. Currently, the Array (chart.dataProvider) in this code remains undefined. var ...

Create a simple carousel using only vanilla JavaScript, without relying on any external plugins

Currently, I am working on implementing a carousel using plain JavaScript without the use of any plugins. My goal is to have previous and next buttons that will control the sliding images. var firstval = 0; function ...

Encountering a problem with a multi-condition query in MongoDB using Golang

I have a record structured like this - { "_id" : "580eef0e4dcc220df897a9cb", "brandId" : 15, "category" : "air_conditioner", "properties" : [ { "propertyName" : "A123", "propertyValue" : "A123 678" ...

JavaScript and modifying the attributes of the nth child

I'm working on a navigation bar that changes the "background-image" of menu items using the nth-of-type CSS selector. Now, I need to figure out how to dynamically change the picture of the "background-image" when hovering over a specific menu item usi ...

What is the process for making changes to a document in Mongoose?

My goal is to allow users to update existing mongoose documents using a form with method-override package. Despite trying various solutions found on Stackoverflow, I have not been able to resolve my issue. The desired functionality is for the user to view ...

TPL operating on a List that is stocked with merchandise

I am facing an issue with the following code snippet: {[displayDate(dateRelease);]} Every model available in the store comes with a "dateRelease" property. I want to retrieve that date and format it using my displayDate() function before displaying it. ...

Unable to generate dynamic HTML through AJAX request

I made an Ajax API call and received the response in JSON format. I need to create dynamic HTML to display each value in HTML elements. I tried getting the response from the API but couldn't generate the HTML. Can someone assist me with this? Also, I ...

What is the best method for incorporating startbootstrap into a react component?

Seeking assistance with incorporating a StartBootstrap template into my React component. The template can be found at this link. Here is the envisioned page layout: https://i.sstatic.net/bpQyE4Ur.png To ensure proper rendering of the template, I have org ...

Ways to truncate text and include a "Read More" button within a v-for loop

The text in the "card-text" class is being retrieved from a Json file, but it's too long. I want to shorten the text and include a "Read More" button that expands the text when clicked on, but only for the specific card that was clicked. Is there a wa ...

What is the method for sending an AJAX request with a dynamically looping ID number parameter in the URL

I am looking to make multiple AJAX calls with a loop parameter named [id] in the URL, starting from request.php?id=1 and ending at id=9. I want to send each call after a 3-second delay. As a JavaScript beginner, I'm unsure of where to begin implementi ...

Is it possible for me to transform this data into JSON format and submit it using a form POST instead of using ajax

On the final step of my 7-step form, all the data input by the user on previous pages is displayed. Using jQuery, this information is dynamically added to each <td class="table_info_ans">. https://i.sstatic.net/NcuZX.png I need to convert this data ...

Using the Rails framework, a basic "remote: true" request does not produce a JavaScript response

In my Rails app, I have set up an iframe to display static HTML files from the same domain. Inside the iframe, I added a link with the remote attribute in hopes of making an in-place AJAX call to create a new nested resource. Here is the code snippet: --- ...

The child directive has the ability to interact with every parent directive

I am attempting to create a slider using angularJS. Within this slider, I have implemented a child directive with event listeners. Whenever the main event (mousedown) is triggered, it invokes a function from the parent directive through a controller and up ...

What types of data are best suited for storage in localStorage?

During the development of my social app with Vue.js and Vuex store, I am contemplating on the best practices for storing parameters in the browser's localStorage. Currently, I retain the 'token' in localStorage, but should I also store &apos ...

JavaScript code that loads a copied mesh object using three.js

Currently using three.js version r59, encountering difficulties when attempting to duplicate a loaded model. The goal is to create multiple models through looping, with the plan to apply textures at a later stage. for (var i=0; i<5-1; i++){ va ...