【问题标题】:Strategy for animating a large mesh in three.js?在three.js中为大型网格设置动画的策略?
【发布时间】:2015-01-07 01:04:21
【问题描述】:

我对 three.js 相对较新,但对 OpenGL 不熟悉(虽然已经有一段时间了 :-)。我正在通过一堆示例来熟悉three.js。我决定移植一些 NeHe 演示。大多数都很容易(尽管有教育意义)。然而,演示 11 本质上是创建一个大型 (45x45) GL_Quads 网格(在旧的 OpenGL 中)并将纹理映射到每组顶点。然后在每个动画帧上,更改网格的 Z 值并重新创建网格以使其产生波纹。

在带有 C++ 或 Java 的 OpenGL 1.x 中,没什么大不了的。简单地重新创建顶点和纹理映射效果很好。在three.js 中很容易编码(将每组顶点更改为一对三角形面,但性能很糟糕。

我在 three.js 网站 (http://threejs.org/examples/webgl_animation_cloth.html) 上看到了挥动布的演示,看起来它直接使用着色器来完成工作。所以我的问题是,我是否遗漏了一些东西(比如有一种有效的方法可以在不下降到着色器级别的情况下做到这一点)或者是时候让我了解更多关于着色器的信息了?

【问题讨论】:

    标签: three.js jquery-animate shader mesh


    【解决方案1】:

    我为你整理的 js 中的动态顶点更新...

    它在我的机器上运行得很好...这与您尝试实现的相似吗?

    完全在 GPU 上构建地形是可行的,但相当复杂,对于大多数涉及地形的情况,您仍然需要在 CPU 端拥有实际的网格来与其交互/执行碰撞等,因此您最终会同时实现 GPU 和 CPU 版本。

    另一种方法是像本例一样在 CPU 上生成几何图形,然后使用自定义着色器根据网格中的信息执行纹理和光照。

    var renderer = new THREE.WebGLRenderer();
    var w = 300;
    var h = 200;
    renderer.setSize(w, h);
    document.body.appendChild(renderer.domElement);
    
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(
      45, // Field of view
      w / h, // Aspect ratio
      0.1, // Near
      10000 // Far
    );
    camera.position.set(15, 10, 15);
    camera.lookAt(scene.position);
    controls = new THREE.OrbitControls(camera, renderer.domElement);
    
    var light = new THREE.PointLight(0x808080);
    light.position.set(20, 20, 20);
    scene.add(light);
    var light1 = new THREE.AmbientLight(0x808080);
    light1.position.set(20, 20, 20);
    scene.add(light1);
    var light2 = new THREE.PointLight(0x800000);
    light2.position.set(-20, 20, -20);
    scene.add(light2);
    var light3 = new THREE.PointLight(0x0000FF);
    light3.position.set(-20, -20, -20);
    scene.add(light3);
    
    
    var material = new THREE.MeshPhongMaterial({
      color: 0x808080
    });
    var planeGeom = new THREE.PlaneGeometry(10, 10, 45, 45);
    
    var mesh = new THREE.Mesh(planeGeom, material);
    scene.add(mesh);
    renderer.setClearColor(0xdddddd, 1);
    
    
    (function animate() {
      var t0 = performance.now() * 0.01;
      var t1 = t0 * 0.7;
      requestAnimationFrame(animate);
      controls.update();
    
      var sinm = (v, m) => {
        return Math.sin(v) * m
      }
      var noisefn = (x, y) => {
        return sinm((x * 0.2) + (y * 0.7) + t0, 1) + sinm((x * 0.9) + (y * 1.2) + t1, 0.3) + sinm((x * -0.9) + (y * 2.2) + t1, 0.4)
      }
      for (var i = 0; i < planeGeom.vertices.length; i++) {
        var v = planeGeom.vertices[i];
        v.z = noisefn(v.x, v.y);
      }
      planeGeom.verticesNeedUpdate = true;
      planeGeom.computeFaceNormals();
      planeGeom.computeVertexNormals();
    
      renderer.render(scene, camera);
    })();
    <script src="https://threejs.org/build/three.min.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/master/examples/js/controls/OrbitControls.js"></script>

    【讨论】:

      【解决方案2】:

      在这种情况下,我可以用 ParametricGeometry 解决我的问题,因为形状及其方差非常简单。更复杂的表面(如真实的 3D 地形)可能需要学习着色器。听起来很有趣,但我想我会先走路再跑。

      更新:使用 ParametricGeometry 可以工作,而且速度更快,但性能仍然很差。所以我会看看其他解决方案,比如下降到着色器级别。

      【讨论】:

      【解决方案3】:

      是的,您应该为此使用着色器。

      如果它不需要从代码中全部动态,但您可以使用预制数据,我认为使用变形目标和现有的着色器来显示它们会很好。

      但是对于像水这样可以扔石头的完全动态的东西,我认为你需要自己的(类似的)着色器。希望通过示例等很容易,如果可以的话,请在完成时分享:)

      【讨论】:

        猜你喜欢
        • 2018-08-21
        • 1970-01-01
        • 2013-08-25
        • 1970-01-01
        • 2017-03-29
        • 1970-01-01
        • 1970-01-01
        • 2019-05-07
        • 2013-05-23
        相关资源
        最近更新 更多