代码之家  ›  专栏  ›  技术社区  ›  Stéphane Laurent

依赖于参数的three.js场景

  •  1
  • Stéphane Laurent  · 技术社区  · 7 年前

    我不擅长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> 
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   Rabbid76    7 年前

    显然,这不是一个很好的继续进行的方法:场景是动画的,当一个人使用参数时动画会加速,我不知道为什么。

    每次你打电话 requestAnimFrame 计时器由启动 setTimeout .计时器调用 render ,再次启动计时器并重复该过程。 函数初始化 提供 由调用 Rendering(a) .
    但是自从 渲染(a) 是由 change 事件也一样,每次更改输入时都会启动一个新的计时器。更改输入的频率越高,同时运行的计时器就越多。这导致加速。

    要解决此问题,必须删除 提供 呼叫来自 渲染(a) .

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

    但是打电话 请求框架 启动时一次:

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