What is the process of updating a uniform in Three.js?

I had to revise my inquiry since I realized I was inquiring about the wrong thing previously.

What I actually wanted to know is, what's the process for updating a uniform in three.js?

Answer №1

Here is a solution that appears to be effective:

setMaterialProperty(yourMesh, 'yourUniform', whatever);

Answer №2

There are two methods available:

  • To update the uniform within the Shader Material itself

    OR

  • You can utilize mesh.material to access the ShaderMaterial and then make changes to the uniform

    Here is an example illustrating both cases:

       var delta = 0
       var customUniforms = {
        delta: { value: 0 },
        u_time: { value: Date.now() }
       };
    
        // Creating a shader material with custom Uniforms
        shaderMaterial = new THREE.ShaderMaterial({
          uniforms: customUniforms,
          vertexShader: document.getElementById("vertexShader2").textContent,
          fragmentShader: document.getElementById("fragmentShader2").textContent
        });
    
        // Setting up a Mesh object for shader rendering
        var geometry = new THREE.BoxBufferGeometry(10, 10, 10, 10, 10, 10);
        shaderMesh = new THREE.Mesh(geometry, shaderMaterial);
        this.scene.add(shaderMesh);
    

    In the animate loop

      animate = () => {
        delta += 0.1; 
    
              // Updating the uniform in Shader Material
              shaderMaterial.uniforms.delta.value = 0.5 + Math.sin(delta) * 0.0005;
    
              // Updating the uniform using mesh directly
         shaderMesh.material.uniforms.u_time.value = delta;
    
    }
    

Visit here for additional reference

https://i.sstatic.net/4nG28.png

Complete Example provided below:

<body>
    <div id="container"></div>
    <script src="js/three.min.js"></script>
    <script id="vertexShader" type="x-shader/x-vertex">
        void main() {
            gl_Position = vec4(position, 1.0 );
        }
    </script>
    <script id="fragmentShader" type="x-shader/x-fragment">
        uniform vec2 u_resolution;
        uniform float u_time;

        void main() {
            vec2 st = gl_FragCoord.xy/u_resolution.xy;
            gl_FragColor=vec4(st.x,st.y,0.0,1.0);
        }
    </script>
    <script>
        var container;
        var camera, scene, renderer;
        var uniforms;

        init();
        animate();

        function init() {
            container = document.getElementById('container');

            camera = new THREE.Camera();
            camera.position.z = 1;

            scene = new THREE.Scene();

            var geometry = new THREE.PlaneBufferGeometry(2, 2);

            uniforms = {
                u_time: { type: "f", value: 1.0 },
                u_resolution: { type: "v2", value: new THREE.Vector2() },
                u_mouse: { type: "v2", value: new THREE.Vector2() }
            };

            var material = new THREE.ShaderMaterial({
                uniforms: uniforms,
                vertexShader: document.getElementById('vertexShader').textContent,
                fragmentShader: document.getElementById('fragmentShader').textContent
            });

            var mesh = new THREE.Mesh(geometry, material);
            scene.add(mesh);

            renderer = new THREE.WebGLRenderer();
            renderer.setPixelRatio(window.devicePixelRatio);

            container.appendChild(renderer.domElement);

            onWindowResize();
            window.addEventListener('resize', onWindowResize, false);

            document.onmousemove = function(e){
              uniforms.u_mouse.value.x = e.pageX
              uniforms.u_mouse.value.y = e.pageY
            }
        }

        function onWindowResize(event) {
            renderer.setSize(window.innerWidth, window.innerHeight);
            uniforms.u_resolution.value.x = renderer.domElement.width;
            uniforms.u_resolution.value.y = renderer.domElement.height;
        }

        function animate() {
            requestAnimationFrame(animate);
            render();
        }

        function render() {
            uniforms.u_time.value += 0.05;
            renderer.render(scene, camera);
        }
    </script>
</body>

Answer №3

A simple illustration on how to update the shader uniform dynamically.

/* Vertex Shader */
<script type="x-shader/x-fragment" id="myShader">
    uniform float customUniform;
    uniform sampler2D customTexture;
    varying vec2 textureUV;
    varying vec2 vertexPosition;

    vertexPosition = uv * vec2(customUniform, customUniform); // Updated based on mouse movement

    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
</script>

/* Setting the uniform */
var myCustomUniform;
var customTexture = new THREE.ImageUtils.loadTexture('./data/textures/customTexture.jpg');
uniforms = {
    customUniform: { type: "f", value: myCustomUniform },
    customTexture: { type: "t", value: customTexture },
};

customMaterial = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: document.getElementById('myShader').textContent,
    fragmentShader: document.getElementById('fragmentShader').textContent,
    wireframe: false,
    side: THREE.FrontSide
});

document.addEventListener('mousemove', updateUniformOnMouseMove, false);

function updateUniformOnMouseMove(event) {
    uniforms.customUniform.value += 0.01; // Update the custom uniform value
    uniforms.customUniform.needsUpdate = true;
}

...

Answer №4

I found a great solution for my specific needs:

const material = new THREE.ShaderMaterial({
    uniforms: {
        customVec3Uniform: { value: new THREE.Vector3(1,1,1) }
    },
    vertexShader: document.getElementById('vertexShader').textContent,
    fragmentShader: document.getElementById('fragmentShader').textContent,
});

If you need to update the uniform values at runtime (source):

material.uniforms.customVec3Uniform.value = new THREE.Vector3(2,2,2);
// mat.needsUpdate = true; // my example works without 'needsUpdate'

Answer №5

Alternative Method for Modifying Three.js Materials

If you are making changes to a material that goes beyond using THREE.ShaderMaterial, such as THREE.MeshStandardMaterial with modifications to its fragment shader, the process will be slightly different.

To adjust the shader's uniforms without needing recompilation, it is necessary to keep a reference to the shader within the onBeforeCompile callback, allowing access to the uniforms through this stored reference.

Using Typescript Class:

Begin by connecting to the THREE.Material's onBeforeCompile function and transferring relevant values (in this case, a uniforms dictionary created in the constructor) into the shader's uniforms. It is crucial as shader compilation occurs before initial use. Maintain a reference to the shader within your class for easy access. Proceed with any additional adjustments to the fragment shader using these uniforms as required.

private _uniforms: { [uniform: string]: ShaderUniform } = {};
private _shader?:THREE.Shader;

this._material.onBeforeCompile = (shader) => {
    let prepend = "";
    //transfer any pre-compilation changes and add them to the fragment shader 
    Object.entries(this._uniforms).forEach(([key, info]) => {
       prepend += `uniform ${info.type} ${key};\n`
       shader.uniforms[key] = {value: info.value};
    });
    //add the prepended shaders and other modifications to the fragment shader using basic string substitutions 
    shader.fragmentShader = prepend + shader.fragmentShader;
    //keep a reference to the shader
    this._shader = shader;
}

If the shader has not been compiled yet, retrieve or set the property from the stored uniforms, otherwise utilize the shader's own uniform value, available only post-compilation.

public getUniform(name:string) : any {
    return this._shader ? this._shader.uniforms[name].value : this._uniforms[name].value;
}

public setUniform(name:string, value:any) {
   if (this._shader) {
       return this._shader.uniforms[name].value = value
   } else {
       this._uniforms[name].value = value;
   }
}

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

The production build of Angular 2 with special effects amplification

I am currently working on an Angular 2 Beta 8 app that I need to bundle and minify for production deployment. Despite configuring the system to generate a Single File eXecutable (SFX) bundle, I am encountering issues with creating a minified version of the ...

Show the information obtained from the dropdown menu selection

Upon selecting a different item from the drop-down list, I want the specific data related to that field from the MySQL database to be displayed. Currently, I am able to retrieve the value of the selected item in the dropdown menu but encountering difficul ...

Retrieve the offspring with the greatest level of depth within a parental relationship

Consider the following tree structure: -root | | |-child1 | |-innerChild1 | |-innerChild2 | |-child2 I am looking to create a JavaScript function that can determine the depth of an element within the tree. For example: var depth = getInnerDepth( ...

How can Navbar values in a React application be dynamically updated depending on the user's login status?

As someone new to React, I am exploring the correct approach to building a Navbar that dynamically displays different links based on a user's login status. When a user logs in, a cookie loggedIn=true is set. In my Navbar component, I utilize window.se ...

Unable to proceed due to lint errors; after conducting research, the issue still remains

I'm still getting the hang of tslint and typescript. The error I'm encountering has me stumped. Can someone guide me on resolving it? I've searched extensively but haven't been able to find a solution. Sharing my code snippet below. (n ...

Unable to utilize console.log and alert functions within the Next.js application

I'm currently facing a problem in my Next.js application where the console.log and alert functions are not functioning as intended. Despite checking the code, browser settings, and environment thoroughly, pinpointing the root cause of the issue remain ...

Tips for utilizing promises to create automated waiting for a function's completion in node.js/javascript

When I instantiate a module, it triggers numerous asynchronous functions. var freader = new filesreader(); // <-- this triggers multiple async functions var IMG_ARRAY = freader.get_IMG_ARRAY(); // <-- i retrieve the array where content is store ...

Resetting a Material UI search filter TextField back to its initial state after clearing it

Unleashing the power of ReactJS alongside Material UI has been a journey of ups and downs for me. While I managed to create a versatile search filter component for my data tables that worked like a charm, I now find myself at a crossroads. My new goal is t ...

Issue with activation of onClick event in case/switch statement

Currently working on a JavaScript project to recreate the Fallout terminal game, with one of the main aspects being comparing words selected by the user to those chosen by the computer. The concept of this hacking game is reminiscent of the board game Mas ...

What is the best way to send the entire image to an API route in Next.js so that I can save it using FS and then upload it to Cloudinary?

I have a form here that utilizes React Hook Form. I'm wondering what I need to pass to the API endpoint via fetch in order to write an image to disk using fs, retrieve its location, and then send that location to Cloudinary. In the body of the fetch ...

Dropdown selection not getting updated when modifying DropdownSection component

My Link dropdown triggers a DropdownSection component that includes an array of options. If I switch to a different Link, I want the default option in the DropdownSection to be set to the second option from the linkOptions array, skipping the initial "No ...

Attempting to figure out how to make Bootstrap pagination function properly

I am trying to implement Bootstrap's pagination feature into my project. While I was able to find the HTML code for it on the official Bootstrap page, I am struggling to make the content change dynamically when I move to the next page. Can anyone pro ...

What is the method for selecting a specific side of a BoxGeometry in THREE.js?

I am seeking a way to retrieve the coordinates of a specific side of a BoxGeometry in order to programmatically click on it. For example, accessing the top side of the BoxGeometry as opposed to the left or right side. While I am able to obtain the object ...

The tooltip feature is functioning properly on the button, but unfortunately it is not working

I am incorporating Tooltips into my project, utilizing Vue 3 and Bootstrap 5. In the script section, I have included the following: <script> import { Tooltip } from "bootstrap/dist/js/bootstrap.esm.min.js"; export default { mounte ...

The mysterious case of jQuery DOM alterations vanishing from sight in the view

I have a quick inquiry. I've been exploring jQuery lately and discovered the ability to dynamically add HTML elements to the DOM using code like $('').append('<p>Test</p>'); However, what surprised me is that these ap ...

Steps for implementing a datepicker in a dynamically generated element

Snippet of jQuery code that adds an element to a container $(container).append( '<label class="control-label col-md-3">Join Duration</label>' + '<div class="col-md-4">' + '<input type="text" name="join_dura ...

Here's a guide on executing both GET and POST requests using a single form

Currently, I am developing a web application which involves using a GET request to display checkboxes in a form. The selected data from the checkboxes needs to be sent back to the server using a POST request. However, I'm facing an issue with performi ...

What is the process for updating selenium-webdriver if it is not globally installed on my system?

After installing selenium-webdriver with the command npm install selenium-webdriver (without the -g option), I found that the usual instruction of running webdriver-manager update did not work since it was installed locally. What is the correct way to upd ...

Ways to identify if one object is positioned above another

So, here's the scenario: I'm trying to figure out how to detect when one element is positioned on top of another. Specifically, I'm dealing with SVG elements: <circle r="210.56" fill="#1ABCDB" id="01" priority="4" cx="658" cy="386">& ...

What is the best way to populate multiple fields in vue.js using Google Autocomplete?

I'm currently working on implementing google autocomplete to populate various fields with a single selection in a vue.js file. Where can I access the address_components from? The vue-google-autocomplete component is sourced from: https://github.com/ol ...