Retrieving information from the shader

I am currently delving into the realm of leveraging GPU capabilities for threejs and webgl applications. My approach involves closely analyzing code to uncover patterns, methodologies, and seeking explanations on certain code segments.

During my quest for knowledge, I stumbled upon this intriguing example: One million particles. It appears to be a straightforward demonstration involving calculations performed in shaders with results displayed.

Here is what I have deduced so far: - Data for particle velocity and position are stored in textures that are sent to shaders for processing and then retrieved back for updates

  • Particles seem to spawn randomly on a plane within the bounds of the texture size?

    for (var i = 0; i < 1000000; i++) {

    particles.vertices.push(new THREE.Vector3((i % texSize)/texSize,
    

    Math.floor(i/texSize)/texSize , 0)) ; }

  • I am puzzled by the lack of apparent particle position updates. How does the data from shaders get retrieved and applied to each particle?

    Is the function 'pick()' used solely to relay mouse positions and determine particle movement direction?

  • Why utilize two buffers and have eight shaders (which consist of four pairs of fragment and vector shaders)? Wouldn't one shader dedicated to calculating velocity and position suffice?

  • How exactly does the shader modify the texture? It seems to only read from it rather than write to it?

Any insights or explanations on these queries would be greatly appreciated!

Answer №1

Deciphering the Unthinkable:

This post delves into the fascinating process of computing results predominantly on the GPU using WebGL/Three.js - all achieved despite utilizing the integrated graphics of an Intel i7 4770k, which may seem less than ideal.


Overview:

The ingenious concept revolves around keeping all operations within the confines of the GPU: Each particle's state is represented by a single pixel color value in a texture. With one million particles, two 1024x1024 pixel textures are employed - one for storing current positions and another for velocities.

Surprisingly, nothing prohibits repurposing RGB color values in a texture to store entirely different data within the 0 to 255 range. Essentially, each texture pixel provides 32 bits (R + G + B + alpha) of space in GPU memory for any desired information. (Additional texture pixels can be utilized if more data per particle/object needs to be stored).

Their approach involves multiple shaders executed sequentially. A careful analysis of the source code reveals the distinct steps in their processing pipeline:

  1. Randomize particles (excluded from this explanation) ('randShader')
  2. Determining velocity for each particle based on its proximity to the mouse location ('velShader')
  3. Adjusting each particle's position according to its velocity ('posShader')
  4. Rendering to the screen ('dispShader')**

.


Step 2: Calculating Velocity per Particle:

A rendering process is initiated on a million points, generating output saved as a texture. Within the vertex shader, every fragment is assigned two additional varyings labeled "vUv", responsible for indicating the x and y pixel coordinates within the textures involved in the process.

The subsequent step takes place in the fragment shader, where output (as RGB values into the framebuffer, later converted into a texture buffer solely within GPU memory) occurs. Examining the id="velFrag" fragment shader unveils an input variable named uniform vec3 targetPos;. These uniforms are easily set by the CPU each frame since they are shared among all instances and do not entail extensive memory transfers. (pertaining to the mouse coordinates, likely within the -1.00f to +1.00f range - the mouse coordinates are updated intermittently, thereby reducing CPU usage).

What transpires here? This shader calculates the distance between the particle and the mouse coordinates, subsequently adjusting the particle's velocity based on this calculation - the velocity also encompasses details regarding the particle's flight trajectory. Nota bene: This velocity adjustment enables particles to gain momentum, persist in motion, and potentially overshoot the mouse position depending on the gray value.

.


Step 3: Updating Positions for Each Particle:

At this stage, every particle possesses a velocity and previous position. These values are processed to determine a new position, which is then recorded as a texture - specifically, the positionTexture. Until the entire frame is rendered (into the default framebuffer) and designated as the new texture, the prior positionTexture remains undisturbed, facilitating easy retrieval:

In the id="posFrag" fragment shader, data is read from both textures (posTexture and velTexture), subsequently incorporated to derive a new position. The resulting x and y position coordinates are outputted as the colors of that texture (in the form of red and green values).

.


Step 4: Showcase Time (=output)

To showcase the outcomes, presumably another million points/vertices are processed with the positionTexture serving as input. Subsequently, the vertex shader assigns the position of each point, retrieving the RGB value from the texture at the specified x,y coordinates passed as vertex attributes.

// From <script type="x-shader/x-vertex" id="dispVert">
vec3 mvPosition = texture2D(posTex, vec2(x, y)).rgb;
gl_PointSize = 1.0;
gl_Position = projectionMatrix * modelViewMatrix * vec4(mvPosition,1.0);

Within the display fragment shader, merely setting a color suffices (note the minimal alpha level allowing up to 20 particles to collectively illuminate a pixel).

// From <script type="x-shader/x-fragment" id="dispFrag">
gl_FragColor = vec4(vec3(0.5, 1.0, 0.1), 0.05);

.


I trust this elucidates the inner workings of this intriguing demo :-) It is worth noting that I am not the creator of this demonstration. However, it is fascinating how this response evolved into a particularly detailed exploration - navigate through the key points swiftly for a concise overview.

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

How to organize and reuse code efficiently with Node.js, EJS, and front-end JavaScript?

It seems that I may have chosen the wrong platform by posting this question on the 'Software Engineering' exchange: Currently, my focus is on learning the MEAN stack (I have yet to dive into Angular, so for now I am using pure vanilla JS for the ...

Is your custom login form in Web2py not submitting properly?

My attempt to customize the login form for web2py has hit a roadblock. Despite adding the necessary fields and submit button, nothing seems to be happening. Here's what the code in the form's view looks like: {{include 'web2py_ajax.html&apo ...

Is it possible to verify the authenticity of published npm packages by utilizing hashes/checksums?

As I prepare to release an npm package on behalf of my organization, let's call it Organization A, I want our clients to have a means of verifying that the package they are using was indeed released by us. One method to accomplish this is by computing ...

AngularJS: Batch processing for saving multiple students simultaneously

I have been working on saving information about students, and I've written the code below. However, I'm unsure how to proceed from here. Any additional information or resources related to this topic would be greatly appreciated. <div ng-contr ...

"Troubleshooting: Why is the external JavaScript not loading on my WordPress

I've been working on my first WordPress theme and I ran into an issue while trying to load external JavaScript. Instead of loading on the page, it's loading in the wp-admin area. Here is a snippet from my functions.php file: wp_enqueue_script(& ...

Unable to load the requested resource: net::ERR_FAILED

I am facing an issue while trying to write React code. When using Chrome, I encountered the following warning: Access to XMLHttpRequest at 'file:///D:/programe/code/Vscode/ReactDemo/HelloWorld/test.js' from origin 'null' has been block ...

Resource file for locating the mappings

As a beginner in sourcemapping, I have been tasked with saving the sourcemap in an external file. However, up to this point, I have only been able to concatenate the sourcemap to the minified .js file. What changes should I make to my approach? Am I miss ...

Extensions for selecting and making Datatable responsive

Currently, I am working on integrating a Datatable into my products table. My goal is for it to be both responsive and include the select extension (checkbox for each column). I have successfully implemented both features. However, I noticed that when the ...

Stop observing IntersectionObserver within the React.useEffect function

I'm attempting to retrieve the top and bottom measurements from multiple elements using the IntersectionObserver. However, once I have the measurements, I'm unsure how to stop observing the elements. The issue is that each element has a position ...

Customizing button styles with JQuery: A step-by-step guide

Hey, I'm working on implementing a button on my webpage and here's the code: <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" rel="stylesheet" type="text/css"/> <script src="http://ajax.googleapis ...

Issue with Webpack - npm run start and build operation not functioning?

Although I typically use create-react-app for my React projects, I decided to create one without it. However, I am encountering issues with the webpack configuration as I am not very familiar with it: This is how my package.json file looks like: { " ...

What is the best way to make my submit button display a message according to my switch statements in JavaScript?

function displayMessage() { var message; var firstName= alert( switch(firstName) { case "Cherry": message="Thank You Cherry!! Your order should arrive 20 days from February 4, 2017"; break; case "Micheal": ...

Exclude the key-value pair for any objects where the value is null

Is there a way to omit one key-value pair if the value is null in the TypeScript code snippet below, which creates a new record in the Firestore database? firestore.doc(`users/${user.uid}`).set({ email: user.email, name: user.displayName, phone: ...

How can we send state updates directly to a conditionally rendered React component?

I am currently developing a React application with a tab section that displays specific components upon clicking on a tab. Initially, I have my parent component: class Interface extends Component { constructor(props) { super(props); ...

Achieve a seamless redirection to the 404 component in Angular without altering the browser URL, while ensuring that the browsing

Whenever my backend sends a 404 error (indicating that the URL is valid, but the requested resource is not found, such as http://localhost:4200/post/title-not-exist), I need Angular to automatically redirect to my NotFoundComponent without altering the URL ...

What could be the reason behind the absence of this.props.onLayout in my React Native component?

In my React Native app, I have the below class implemented with Typescript: class Component1 extends React.Component<IntroProps, {}> { constructor(props){ super(props) console.log(props.onLayout) } ... } The documentation for the View ...

Storing and securing passwords in Node/Express using hashing and salting techniques

Utilizing the Crypto module within Node's standard library is a necessity. I have established a POST route dedicated to handling a registration form: app.post('/superadmin/add-account', function(req, res) { // Creating shorthand variable ...

The specified type '{}' cannot be assigned to type 'ReactNode'

Can someone help me figure out why I am getting this error in Vercel but not locally? Error: 'FontAwesomeIcon' cannot be used as a JSX component. ./components/Services/ServiceContainer.tsx:25:6 12:01:54.967 Type error: 'FontAwesomeIcon&a ...

Converting nested arrays to objects via JSON transformation

I am faced with a nested JSON array structure like this: Parent: { Child1: [ {name:'grandchild1', value:'abc', checked:true}, {name:'grandchild2', value:'pqr', checked:false} ], Ch ...

Enhance the annotation of JS types for arguments with default values

Currently, I am working within a code base that predominantly uses JS files, rather than TS. However, I have decided to incorporate tsc for type validation. In TypeScript, one method of inferring types for arguments is based on default values. For example ...