Search code examples
javascriptthree.jsplane

Three.js - How to update a PlaneBufferGeometry?


I'm trying to create an ocean for my Three.js application. I took the example from this site: 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()
})

Issue is, I'm using PlaneBufferGeometry instead of PlaneGeometry, and it seems there are some differences

My code in render after creating the waterPlane

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;

I'm not getting any errors, but no matter what I do, all I get is a flat wireframe plane geometry that doesn't move or anything. I think issue is in the updating of the plane?


Solution

  • This is an example of how you can displace vertices of a buffer geometry, using that SimplexNoise library: enter image description here

    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 { createNoise3D } from "https://cdn.skypack.dev/simplex-noise";
    
    let simplex = createNoise3D();
    
    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(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>