在three.js中制作大网格动画的策略?

时间:2014-11-10 16:44:39

标签: three.js jquery-animate shader mesh

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

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

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

3 个答案:

答案 0 :(得分: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>

答案 1 :(得分:0)

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

更新:使用ParametricGeometry工作,速度更快,但性能仍然很差。因此,我将查看其他解决方案,例如降级到着色器级别。

答案 2 :(得分:0)

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

如果它不需要全部来自代码的动态,但你可以使用预先制作的数据,使用变形目标和已经存在的着色器来显示那些可以正常工作我认为。

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