javascript - Three.js场景依赖一个参数

标签 javascript three.js

我不精通 html/javascript,我从 three.js 开始。我做了一个场景,它取决于一个可以由用户控制的参数。

下面的代码是此类场景的完整最小示例。它呈现一个参数化表面,该表面取决于参数 a,用户可以使用 input type="number" 更改该参数。

显然,这不是一个好的处理方式:场景是动画的,当使用参数播放时动画会加速,我不知道为什么。编写这样的场景有什么好的方法?

<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> 

最佳答案

Apparently this is not a good way to proceed: the scene is animated and the animation accelerates when one plays with the parameter, I don't know why.

每次调用 requestAnimFrame 时,setTimeout 都会启动一个计时器。计时器调用 render,它再次启动计时器并重复该过程。 render 函数最初由 Rendering(a) 调用。
但是由于 Rendering(a) 也是由 change 事件调用的,因此每次输入更改时都会启动一个新的计时器。您更改输入的频率越高,同时运行的计时器就越多。这会导致加速。

要解决此问题,您必须从 Rendering(a) 中删除 render 调用。

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

但是在启动时调用一次requestAnimFrame:

Rendering(0.9);
requestAnimFrame(render);

请参阅示例,其中答案的建议应用于您问题的原始代码:

$("#a").on("change", function(){
    Rendering(this.value);
})

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;
    }
}

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);
}

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.onresize = resize;

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);
}

function resize() {
    var aspect = window.innerWidth / window.innerHeight;
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = aspect;
    camera.updateProjectionMatrix();
}

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

Rendering(0.9);
requestAnimFrame(render);
<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"/>

关于javascript - Three.js场景依赖一个参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51121645/

相关文章:

javascript - Threejs 阴影不渲染

javascript - 你能重置一个变量来存储调用包含闭包的函数的结果吗?

Three.js SplineCurve3 无圆边,或 LineCurve3 替代品

javascript - Three.js 立方体,每个面都有不同的纹理。如何隐藏边/顶点

javascript - 从 Three.js 中的 .dae 获取所有节点名称

javascript - 如何使用javascript从url字符串中提取url文件扩展名

javascript - 操作无法使用 REST 进行,但可以以其他方式进行

javascript - 为什么这个 setTimeout 根本不触发?

javascript - 边框间距不起作用

javascript - 查找网格中的所有四边形