Creating a dynamic Three.js scene based on a variable

Having limited knowledge in html/javascript, I decided to start with three.js. My scene relies on a parameter that users can manipulate.

Below is a simple example of the scene setup. It showcases a parametric surface that adjusts based on a user-controlled parameter a, using an input type="number".

However, there seems to be an issue: when users interact with the parameter, the animation speeds up unexpectedly. I'm unsure why this occurs. How can I improve the coding approach for this scene?

<html>

<head>
  <title>Dupin cyclide</title>
  <style>
    canvas {
      width: 100%;
      height: 100%
    }
  </style>
</head>

<body>

  <script src="http://threejs.org/build/three.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

  <label for="a">a: </label>
  <input id="a" type="number" step="0.1" min="0.5" value="0.9"/>
  <script> // change event -----------------------------------------------------
    $("#a").on("change", function(){
      Rendering(this.value);
    })
  </script>

  <script> // cyclide parametrization ------------------------------------------
    function fcyclide(a, c, mu) {
      var b = Math.sqrt(a * a - c * c);
      return function (u, v, vector) {
        var uu = 2 * u * Math.PI; var vv = 2 * v * Math.PI;
        var cosu = Math.cos(uu); var cosv = Math.cos(vv);
        var h = a - c * cosu * cosv;
        var x = (mu * (c - a * cosu * cosv) + b * b * cosu) / h;
        var y = (b * Math.sin(uu) * (a - mu * cosv)) / h;
        var z = b * Math.sin(vv) * (c * cosu - mu) / h;
        vector.x = x; vector.y = y; vector.z = z;
      }
    }
  </script>

  <script> // add cyclide to object --------------------------------------------
    function addCyclide(object, a) {
      var geom = new THREE.ParametricGeometry(
        fcyclide(a, 0.34, 0.56), 40, 40);
      var material = new THREE.MeshNormalMaterial();
      var mesh = new THREE.Mesh(geom, material);
      object.add(mesh);
    }
  </script>

  <script> // three.js --------------------------------------------------------- 
    var scene = new THREE.Scene();
    var aspect = window.innerWidth / window.innerHeight;
    var camera = new THREE.PerspectiveCamera(70, aspect, 1, 10000);
    camera.position.z = 4;
    scene.add(camera);

    var renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    var object = new THREE.Object3D()
    scene.add(object);

    window.requestAnimFrame = (function () {
      return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        function (callback) {
          window.setTimeout(callback, 1000 / 60);
        };
    })();

    function render() {
      renderer.render(scene, camera);
      object.rotation.x += 0.001; object.rotation.y += 0.001;
      requestAnimFrame(render);
    }
  </script>

  <script> // Rendering function -----------------------------------------------
    function Rendering(a) {
      object.children.splice(0); // clear scene
      addCyclide(object, a);
      render();
    }
  </script>

  <script> // Render the scene -------------------------------------------------
    Rendering(0.9);
  </script>

</body>

</html> 

Answer №1

It seems that the current approach is not ideal: the scene animates and the animation speeds up when manipulating the parameter, though the reason behind this behavior remains unclear.

Whenever you invoke requestAnimFrame, a timer is initiated by setTimeout. This timer triggers the execution of render, which in turn restarts the timer, leading to repetitiveness in the process. Initially, the function render is called by Rendering(a).
However, as Rendering(a) is also invoked by the change event, a new timer starts each time the input undergoes a change. The frequency of input changes directly correlates with the number of timers running concurrently, causing the acceleration in animation speed.

To address this issue, it is crucial to eliminate the call to render from Rendering(a).

function Rendering(a)
{
    object.children.splice(0);
    addCyclide(object, a);
}

Instead, ensure only one call to requestAnimFrame at the beginning:

Rendering(0.9);
requestAnimFrame(render);

The example below illustrates how the suggestion in the response rectifies the original code in your question:

$("#a").on("change", function(){
    Rendering(this.value);
})
   // Rest of the JavaScript code goes here... 
<script src="http://threejs.org/build/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<label for="a">a: </label>
<input id="a" type="number" step="0.1" min="0.5" value="0.9"/>

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

What is the best way to implement a decorator for a class method variable within a NestJS framework?

import {isNotEmpty} from "class-validator"; export Service { create(createdto) { const {name,age} = createdto; @isNotEmpty() name //applying a decorator to ensure name is not null or undefined } } As the decorator is designed for ...

Converting a PHP array to a JavaScript array causes an issue of undefined variable when attempting to access a PHP array that has

I've been searching through other questions without finding the answer, so I'm reaching out for help with my specific issue. My problem is transferring a php array to a javascript array. In my code editor (phpStorm), I'm getting an error st ...

Error Message: "Angular Mocks and Jasmine encountered an issue: 'fn' is not a function, instead got Object"

I'm encountering a problem when it comes to unit testing in Angular using Angular-Mocks, Jasmine, and CoffeeScript. The issue lies within this code snippet: 'use strict' describe 'sample suite', -> beforeEach inject(($ro ...

Creating a link button using JavaScript

I have integrated a Setmore code on my website to facilitate appointment booking, which triggers a popup similar to what you would see on a hotel reservation site. <script id="setmore_script" type="text/javascript" src="https://my.setmore.com/js/iframe ...

Retrieve the keys stored within a complex array of objects

I am searching for a function that can transform my data, specifically an array of objects with nested objects. The function should only include keys with immediate string/number/boolean values and exclude keys with object/array values. For example: [ { ...

In Node.js, when performing a nested query, the response will only display data from the last table. If the starting

const serverConnection = require('./../config'); const request = require("request"); module.exports.summarizeTravel = function (request, response, callback) { const userId = request.body.id; const startDate = request.body.start_date; ...

I consistently encounter the error message 'XRWebGLLayer is not defined no-undef' while implementing three.js within react.js to develop a WebXR application

Trying to implement WebXR with Three.js in a React project, encountering the error: 'XRWebGLLayer' is not defined no-undef for baseLayer: new XRWebGLLayer(session, gl) The code works fine in vanilla JavaScript but fails to compile in React. ...

Utilizing v-model dynamically to showcase the outcomes of a specific property within a v-for iteration

As I iterate over an array using v-for, the number of items in this array varies each time. Currently, I am able to input values into the fields and have them correctly update the data property associated with them. However, there are two issues that need ...

Different Option for Ribbon in three-dimensional graphics

Can someone provide a simple example of a ribbon in threejs? I've looked at examples here and here, but the first one uses THREE.Ribbon which is no longer available, and the second one seems overly complicated for creating a single ribbon in threejs ...

Exploring the focus() method of refs in Vue 3

I'm struggling to comprehend why my straightforward test case keeps failing. As I delve into the world of testing in Vue, I've created a simple test where the element.focus() is triggered onMount(() => /* see implementation ...

Steps to resolve the error "Cannot POST /index.html" in Nginx, Express, and NodeJS

While setting up my MERN project on the production server, I encountered an issue. In order to manually type in URLs (like myproject.com/dashboard), I added the line try_files $uri /index.html; to the server section of my Nginx configuration file as recomm ...

Retrieve the output of a JavaScript function and submit it as extra form data

I am working on a JavaScript function that looks like this: <script type="text/javascript"> function doSomething() { var s = 'some data' return s; } </script> and @using (Html.BeginForm(new { data_to_send = ...

Implementing the loading of a Struts 2 action with jquery in javascript

Looking to refresh a specific div using JavaScript with jQuery to target the div and a Struts action that loads the content. Can anyone offer advice on how to achieve this? The challenge lies in utilizing JavaScript and jQuery for this task. Best regards ...

Is indexed coloring available for vertices in three.js?

I have recently started exploring the world of three.js and I am aware that there is a way to color vertices in three.js. However, I am currently researching whether it is possible to implement indexed colors for vertices in three.js or WebGL. Specifically ...

In Firefox, using $().focus to target a textarea does not yield the intended results

Here is the problem recreated: http://jsfiddle.net/Rc52x/5/ In Chrome, when you click on Click here!, the textarea gains focus and allows typing. However, in Firefox (version 3.6.15), clicking on it does not give focus to the textarea and typing has no e ...

Is it possible to use jQuery validate for remote parsing with two fields in a single call

Currently, I am facing an issue while trying to parse two values using jQuery's validate plugin to compare with an SQL database. The DateReceived value is successfully parsed, but the CentreID value always appears as null. Below is the code snippet I ...

Struggling to display my array data retrieved from the database on my Angular 5 page

I hope everyone is doing well. I am currently facing a problem with retrieving data from Firebase. I have an array within an array and I want to display it in my view, but I am encountering difficulties. Let me share my code and explain what I am trying to ...

Create a polling feature using a Grease Monkey script

I am looking for a way to run a Tamper Monkey script on a Facebook page that regularly checks a database for new data and performs certain actions. I have attempted to implement polling using AJAX, and below is the code I used: (function poll() { setT ...

How to use jquery and ajax to retrieve an array of data and show it on the screen

I am facing an issue with my ajax request. Actually, I am unsure of how to fetch multiple records. I attempted the following: $rqt = "SELECT a,b,c from table"; $res = mysql_query($rqt); while ($data = mysql_fetch_assoc($res)): $objet = $d ...

`How can I effectively manage errors within an ASP.NET HTTP handler?`

I wrote an Httphandler in asp.net that is responsible for returning a file. Within the code, I have implemented Response.AddHeader("Content-Disposition", "attachment; filename=somefile.ext"); to ensure that the page URL remains unchanged. However, when an ...