Three.js - 如何更新 PlaneBufferGeometry?

Three.js - How to update a PlaneBufferGeometry?

我正在尝试为我的 Three.js 应用程序创建一个海洋。我从这个网站拿了例子: https://codepen.io/RemiRuc/pen/gJMwOe?fbclid=IwAR2caTQL-AOPE2Gv6x4rzSWBrOmAh2j-raqesOO0XbYQAuSG37imbMszSis

var params = {
  res : 32,
  speed : 8,
  amp : 2,
  wireframe : true,
  backgroundColor : 0x9c81e3,
  planeColor : 0x4a4a4a
}

var scene = new THREE.Scene();
scene.background = new THREE.Color(params.backgroundColor)
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 )
let canvas = document.getElementById("webgl")

var renderer = new THREE.WebGLRenderer({canvas:canvas, antialias: true})
renderer.setSize( window.innerWidth, window.innerHeight )

var simplex = new SimplexNoise()

var light = new THREE.AmbientLight( 0xcccccc ); // soft white light
scene.add( light );

var pointLight = new THREE.PointLight( 0xeeeeee, 1, 100 );
pointLight.position.set( 0, 20, -20 );
scene.add( pointLight );

let geometry, material, plane
createPlane()

camera.position.z = 5;
camera.position.y = 3;
camera.lookAt(new THREE.Vector3( 0, 3, 0 ))

var animate = function () {
  requestAnimationFrame( animate );

    for (var i = 0; i < geometry.vertices.length; i++) {
      var z = (i + Date.now() * params.speed/100000)
      geometry.vertices[i].z = simplex.noise4D(z,z,z,z) * params.amp
      plane.geometry.verticesNeedUpdate = true;
    }

  scene.background = new THREE.Color(params.backgroundColor)
  material.color = new THREE.Color(params.planeColor)
  material.wireframe = params.wireframe

  camera.rotation.y += 0.001
  renderer.render( scene, camera );
};

animate();

function createPlane(){
  geometry = new THREE.PlaneGeometry( 200, 200, params.res,params.res );
  material = new THREE.MeshLambertMaterial( {color: params.planeColor, side: THREE.DoubleSide, wireframe: params.wireframe} );
  plane = new THREE.Mesh( geometry, material );
  scene.add( plane );
  plane.rotation.x = Math.PI/2
}

/***RESIZE***/
window.addEventListener('resize', ()=>{
    document.querySelector('canvas').style.width = window.innerWidth + "px"
    document.querySelector('canvas').style.height = window.innerHeight + "px"

    renderer.setSize( window.innerWidth, window.innerHeight )

    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
})

var gui = new dat.GUI()

var controller = gui.add(params, "res", 0, 100).name("Plane resolution")
gui.add(params, "speed", 0, 500).name("Wave speed")
gui.add(params, "amp", 0, 20).name("Wave amplitude")
gui.add(params, "wireframe", 0, 20).name("Wireframe")
gui.addColor(params, "backgroundColor").name("Background color")
gui.addColor(params, "planeColor").name("Plane color")

controller.onChange(()=>{
  scene.remove(plane)
  createPlane()
})

问题是,我使用的是 PlaneBufferGeometry 而不是 PlaneGeometry,看起来有些不同

我在创建水面后 render 中的代码

for (var i = 0; i < waterGeometry.attributes.position.count; i++) {
    var z = (i + Date.now() * params.speed/100000);
    waterGeometry.attributes.position[i] = simplex.noise4D(z,z,z,z) * params.amp;
}
waterGeometry.attributes.position.needsUpdate = true;
waterPlaneMesh.attributes.position.needsUpdate = true;

我没有收到任何错误,但无论我做什么,我得到的只是一个平面线框平面几何图形,它不会移动或任何东西。我认为问题出在飞机的更新上?

这是一个示例,说明如何使用 SimplexNoise 库置换缓冲区几何体的顶点:

body {
  margin: 0;
  background-color: #000;
  color: #fff;
  font-family: Monospace;
  font-size: 13px;
  line-height: 24px;
  overscroll-behavior: none;
}
<script type="module">
import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
import { OrbitControls } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";
import SimplexNoise from "https://cdn.skypack.dev/simplex-noise";

let simplex = new SimplexNoise('seed');

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 2000);
camera.position.set(0, 0.5, 1).setLength(12);
let renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);

window.addEventListener("resize", onWindowResize);

//scene.add(new THREE.GridHelper())

let controls = new OrbitControls(camera, renderer.domElement);

let light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));

let v3 = new THREE.Vector3();
let v2 = new THREE.Vector2();

let g = new THREE.PlaneGeometry(200, 200, 100, 100);
g.rotateX(-Math.PI *0.5);
let m = new THREE.MeshLambertMaterial({color: "aqua", wireframe: false});
let o = new THREE.Mesh(g, m);
scene.add(o);

let clock = new THREE.Clock();

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
  let t = clock.getElapsedTime();
  
  for(let i = 0; i < g.attributes.position.count; i++){
    v2.fromBufferAttribute(g.attributes.uv, i).addScalar(t * 0.01).multiplyScalar(20);
    let h = simplex.noise3D(v2.x, v2.y, t * 0.1);
    g.attributes.position.setY(i, h);
  }
  g.computeVertexNormals();
  g.attributes.position.needsUpdate = true;
  
});

function onWindowResize() {

  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(innerWidth, innerHeight);

}

</script>