Strategies for managing large numbers within WebGL GLSL shader programs

What is the best approach to handle large numbers like the one provided in GLSL?

I have a shader that requires Date.now() as a uniform, which is defined as:

The Date.now() method returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC. — MDN

For example, 1514678400000 represents the last day of the year.

When I pass this value to my ShaderMaterial, it doesn't seem to work as expected unless I significantly scale down the value.

Specifically, I notice a difference in behavior when trying to map the last 2500 milliseconds to a value between 0–1:

JavaScript: ( Date.now() % 2500 ) / 2500

GLSL: mod( time, 2500.0 ) / 2500.0

I would prefer to perform these calculations on the GPU, but I'm unsure of the correct approach. Can anyone provide guidance on this?

Below is a simple scene demonstrating the issue:

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 )
const renderer = new THREE.WebGLRenderer()

renderer.setSize( window.innerWidth, window.innerHeight )
camera.position.z = 0.5

document.body.appendChild( renderer.domElement )

const checkbox = document.getElementById( "toggle" )

const geo = new THREE.PlaneGeometry( 1, 1 )
const mat = new THREE.ShaderMaterial({
  vertexShader: `
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
  `,
  fragmentShader: `
    uniform bool check;
    uniform float time;
    
    const float TAU = 6.2831;
    
    void main() {
      float fColor;
      
      check 
        ? fColor = ( sin( ( time * TAU ) ) + 1.0 ) / 2.0
        : fColor = ( sin( ( ( mod( time, 2500.0 ) / 2500.0 ) * TAU ) ) + 1.0 ) / 2.0;
        
      gl_FragColor = vec4( 1.0, fColor, 1.0, 1.0 );
    }
  `,
  uniforms: {
    "check": { value: false },
    "time": { value: 1.0 },
  },
})

const plane = new THREE.Mesh( geo, mat )
scene.add( plane )

const animate = function() {
  requestAnimationFrame( animate )

  if ( checkbox.checked ) {
    plane.material.uniforms.check.value = true
    plane.material.uniforms.time.value = ( Date.now() % 2500 ) / 2500
  } else {
    plane.material.uniforms.check.value = false
    plane.material.uniforms.time.value = Date.now()
  }

  renderer.render( scene, camera )
}

animate()
body {
  margin: 0;
}

canvas {
  width: 100%;
  height: 100%;
}

#config {
  position: absolute;
  color: #fff;
  cursor: pointer;
  user-select: none;
  font: bold 1em/1.5 sans-serif;
  padding: 1em;
}

#config label,
#config input {
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.js"></script>
<div id="config">
  <input id="toggle" type="checkbox">
  <label for="toggle">Use JavaScript</label>
</div>

Answer №1

In my shader, I am utilizing Date.now()

When Date.now() is used in shaders, it can result in unpredictability, especially when trigonometric functions like sin() and cos() are involved. This is due to passing milliseconds as a large integer number. To resolve this issue, it is recommended to divide the milliseconds by 1000 to convert them into float numbers, essentially transforming milliseconds into seconds.

One approach is to perform the division as mentioned above. Alternatively, you can make use of THREE.Clock() along with its .getDelta() method. Below is a code snippet demonstrating this:

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 )
const renderer = new THREE.WebGLRenderer()

renderer.setSize( window.innerWidth, window.innerHeight )
camera.position.z = 0.5

document.body.appendChild( renderer.domElement )

const geo = new THREE.PlaneGeometry( 1, 1 )
const mat = new THREE.ShaderMaterial({
  vertexShader: `
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
    }
  `,
  fragmentShader: `
    uniform bool check;
    uniform float time;
    
    const float TAU = 6.2831;

    void main() {
      float fColor;
      
      fColor = ( sin( ( time * TAU ) ) + 1.0 ) / 2.0;
        
      gl_FragColor = vec4( 1.0, fColor, 1.0, 1.0 );
    }
  `,
  uniforms: {
    "check": { value: false },
    "time": { value: 1.0 },
  },
})

const plane = new THREE.Mesh( geo, mat )
scene.add( plane )

var clock = new THREE.Clock();
var time = 0;

const animate = function() {
  requestAnimationFrame( animate )
  
  time += clock.getDelta();

  plane.material.uniforms.time.value = time * 0.4; // make it 2.5 times slower

  renderer.render( scene, camera )
}

animate()
body {
  margin: 0;
}

canvas {
  width: 100%;
  height: 100%;
}

#config {
  position: absolute;
  color: #fff;
  cursor: pointer;
  user-select: none;
  font: bold 1em/1.5 sans-serif;
  padding: 1em;
}

#config label,
#config input {
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.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

Unable to retrieve JSON data from a PHP file hosted on the server

I have a server-side database with a table called "customers" and a column named "names". My goal is to send a request to the server asking for the first two records in the "customers" table. However, when I execute the program, the browser does not displa ...

A div containing a form, with the form being visually integrated within the div

Hi everyone, this is my first post here and I've tried to search extensively before asking this question. I've attempted to use the following examples without success: jquery submit form and then show results in an existing div Form submit ...

Setting a unique identifier for a newly created element in JavaScript and the DOM

Is there a way to assign an element ID to a newly created element using JavaScript DOM? The code I've written generates a table that is displayed when a button is clicked. I'm looking to give this table a unique ID so it can have a distinct sty ...

Error 404: Jquery Fancy Box Not Found

Help needed with JQuery FancyBox: I encountered a 404 error when trying to enlarge small images. Here is the code that I used: <a class="fancybox-buttons" data-fancybox-group="button" href="images/gallery/1_b.png" style="margin-right:100px;"><im ...

Next.js allows for dynamic page routing using the `useState` hook to redirect users

In my Next.js project, I am using the useState hook to render different components based on the button a user clicks. The main page, called account.js in the application, contains the following code: // Importing react and getting components import React f ...

Activating Button within Featherlight Modal

This is a follow up question from Featherlight hide div on Close After successfully resolving the issue with opening the lightbox, I have encountered another problem. I have added a submit button that should trigger an on('submit', function) whe ...

Validation in Ajax Response

When receiving an object from my API call, I want to perform error checking before displaying the JSON data in my view. function response(oResponse) { if (oResponse && oResponse != null && typeof oResponse === "object" && oResponse.response ...

Switch app engines in real-time based on the URL path with express framework

How can I dynamically set App Engine based on the URL? In my application, I have two render engines available: serverSideRenderEngine & browserRenderEngine If the URL is /home, the app.engine should be set as serverSideRenderEngine If the URL is /l ...

Angular update row and save data to an array

When comparing the data of an edited row with the row just below it, I encounter a specific scenario. In a table containing 5 rows, as I edit records from top to bottom using the provided code snippet, I am able to store the values in an array. The most re ...

Utilizing the Public Directory in Vite Compilation

One issue I encountered in my project with Vite version 2.9.7 is related to the handling of images stored in the public folder within the project's root directory. To import these images, I utilized Vite's import.meta.glob function, like so: imp ...

Learn how to incorporate an image into your Codepen project using Dropbox and Javascript, along with a step-by-step guide on having the picture's name announced when shown on the screen

Hey there, I'm in need of some assistance. I have a Codepen page where I am working on displaying 4 random shapes (Square, Triangle, Circle, and Cross) one at a time, with the computer speaking the name of each shape when clicked. I want to pull these ...

How to extract specific dates from a date range in Javascript

If I give you a date range such as October 5, 2016 to December 5, 2016, and tell you that October 5 was a Wednesday, can you help me find all the Wednesdays until December 5th, 2016? Is there a way to accomplish this using Javascript or AngularJS? ...

Getting information from PHP through AJAX for transmission to a separate PHP script

Hi everyone, I'm facing a bit of a challenge with my project. Here's the situation: I've got a PHP file that interacts with a database and displays the query results. Then, there's an HTML file that uses AJAX to show these results dyna ...

Adding retrieved ejs elements

Aim: I am struggling with a button that triggers a function to fetch more items from my Mongoose DataBase and display them in a table row dynamically. I am using the get method to retrieve data from the server side. Despite referring to advice from this po ...

Adding flair to a fresh element and then removing it upon its inception

I'm working with a JavaScript code that creates a new element when a button is clicked. I have a question about it. Here's the JavaScript code snippet: var comment = document.querySelector("#AddComment"); var req = new XMLHttpRequest(); if(comm ...

Hiding or removing DOM elements with ng-bootstrap pagination

I am in the process of incorporating pagination into my project using ng-bootstrap pagination. In my HTML, I am combining an ngFor loop with the slice pipe to filter elements for display. <tr *ngFor="let bankAccount of bankingAccounts | slice: (p ...

Learn how to dynamically incorporate multiple Bootstrap collapse elements in PHP

I've encountered an issue with my code that contains both HTML and PHP. The problem arises when there are multiple elements in a collapse, as only the first element works properly. This is due to the fact that each element has the same id named "colla ...

When using JSON.stringify, the output is null. However, when using document.write, the data

I am currently working on a plugin for crawljax that involves executing some JavaScript code, similar to the following: String result = browser.executeJavaScript(script).toString(); The script code is as follows: function getElementPosition(id) { var el ...

Move the camera in Three.js along a path between two vectors

I created a basic scene and came across a tutorial at to help me move the camera: var timer = new Date().getTime() * 0.0005; camera.position.x = Math.floor(Math.cos( timer ) * 200); camera.position.z = Math.floor(Math.sin( timer ) * 200); However, I n ...

Using jQuery, you can easily insert a <span> tag around selected text and then save this modification permanently in a local HTML file

I have compiled notes in an HTML file stored on my local computer, with the intention of keeping it solely for personal use. For instance, I have a snippet like this: <p> this is an example text</p> My goal is to highlight the word "example" ...