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?
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?
Here is a solution that appears to be effective:
setMaterialProperty(yourMesh, 'yourUniform', whatever);
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>
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;
}
...
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'
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;
}
}
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 ...
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 ...
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( ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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 ...
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">& ...
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 ...