Updating a PlaneBufferGeometry in Three.js - Tips and Tricks

I'm currently working on implementing an ocean effect in my Three.js project. I found a helpful example on this website: 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()
})

However, I encountered a problem when using PlaneBufferGeometry instead of PlaneGeometry, which seems to have caused some differences in the rendering.

In my code within the render function 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;

Although there are no visible errors, all I see is a flat wireframe plane geometry that remains static without any movement. I suspect the issue lies in how I am updating the plane?

Answer №1

Here is a demonstration showcasing how to manipulate the vertices of a buffer geometry using the SimplexNoise library: https://i.sstatic.net/QEkiW.png

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/my-three-library";
import { OrbitControls } from "https://cdn.skypack.dev/orbit-controls-library/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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Struggling to grasp the concept of DOM Event Listeners

Hello, I have a question regarding some JavaScript code that I am struggling with. function login() { var lgin = document.getElementById("logIn"); lgin.style.display = "block"; lgin.style.position = "fixed"; lgin.style.width = "100%"; ...

Tips for swapping out text with a hyperlink using JavaScript

I need to create hyperlinks for certain words in my posts. I found a code snippet that does this: document.body.innerHTML = document.body.innerHTML.replace('Ronaldo', '<a href="www.ronaldo.com">Ronaldo</a>'); Whil ...

Error: Attempting to access a property 'notesObjectInService' that is undefined on the object

I'm currently facing an issue where my controller is unable to load an object from a service called notesFactory. The console.log(typeof notesFactory) statement returns 'undefined', causing notesObjectInService to trigger an exception. Desp ...

Unprocessed Promise Rejection Alert: The function res.status is not recognized as a valid function (NEXT JS)

When I console.log(response), I see the result in the terminal. However, when I use res.status(200).json(response), I encounter an error in my Next.js project: Not Found in the browser. router.get("/api/backendData", async (req, res) => { dbConne ...

Numerous JQuery AJAX form submissions leading to individual outcomes

I have implemented a script on my page that handles form submissions for multiple forms by calling a specific action. Here is the script: $(function () { $('form').submit(function () { if ($(this).valid()) { $.ajax({ ...

The callback function is unable to access this within the $.post method

Hey there, I'm new to JavaScript/jQuery and I could use some help. I have an object prototype called Page that contains an array and a function for making an AJAX POST request and processing the response. Here's a snippet of the code: function P ...

What is the best way to extract the date and pricing information directly from an interactive graph using Python?

My attempt to gather data from a graph using web scraping with the Selenium library was unsuccessful. The graph can be found at this link. from selenium import webdriver driver = webdriver.Chrome() driver.get('https://www.mtgprice.com/sets/Ravnica_All ...

The React component is failing to display updated data from the Redux store

I've been working with React and Redux, trying to update my counter value in the React view. I can successfully log the latest state of my Redux store, but the changes are not reflecting in my React view. const counter = (state = 0, action) => { ...

What is the best way to obtain the id of an HTML element that is generated within jQuery code?

Typically, data is retrieved in HTML by storing the html in the html file. In my case, however, I create the html element inside jQuery. So, how do I call out the div id? How can I replace document.getElementByID ("edit").innerHTML=.... when the element i ...

Using JavaScript to obtain the coordinates of a click event from a programmatically triggered click on an HTML element

Is there a way to programmatically simulate a click event on an HTML DOM element and still retrieve the screenX/screenY and clientX/clientY coordinates successfully? When manually clicking the element, the coordinates are visible in the console, but when t ...

Filtering a list in AngularJS based on a property of an object with a filter applied on it

I am facing an issue with filtering a list of objects based on their properties using the filter filter. The problem arises when certain object properties have filters applied to them that alter their displayed format (such as the formatDate filter in the ...

Is it possible to trigger the execution of two functions simultaneously by using onClick in JavaScript?

I currently possess: one = () => { //perform a task } two = () => { //execute an action } <div> <button onClick={/*this.one, this.two (it doesn't function)*/}>Go</button> </div> Is there a way to invoke two f ...

Is it necessary to include a back button when navigating through paginated tables?

Within my AngularJS application, I have implemented pagination on the user list page. This allows me to retrieve ten users at a time from the server, with each click loading another set of ten users on a new page. The user details are presented in a tabl ...

Error: The method specified in $validator.methods[method] does not exist

Having trouble solving a problem, despite looking at examples and reading posts about the method. The error I'm encountering is: TypeError: $.validator.methods[method] is undefined Below that, it shows: result = $.validator.methods[method].call( t ...

Creating a button that integrates an image within a single div element

Currently, I understand the code: $('#leftDev').css("background-image", "url(img/1.png) "); will set the entire background of my leftDiv to display "1.png". However, I would like to position this image as a regular picture within the div and no ...

Tips for telling the difference between typescript Index signatures and JavaScript computed property names

ngOnChanges(changes: {[paramName: string]: SimpleChange}): void { console.log('Any modifications involved', changes); } I'm scratching my head over the purpose of 'changes: {[propName: string]: SimpleChange}'. Can someone cl ...

Only display entries with no content

When attempting to filter data from a search, all results are being displayed on the submit button even when entering 1, 2, or 3. Here is my code below. Please let me know if I am making a mistake somewhere. ...

Automate the process of modifying specific data in tables through Javascript

I've been attempting to replicate the appearance of a stock-exchange board, but I'm encountering difficulties in updating text automatically without interrupting another. My attempts so far: var textPositive = ["2.0%", "1.7%" ...

The "flickering" effect of the div is like a dance, moving gracefully between fade outs and

I am encountering a similar issue as described in this thread: same problem (fiddle: original fiddle). However, I am still learning JavaScript and struggling to apply the solution provided because my HTML code is slightly different. Can someone please assi ...

What could be causing my node.js to fail in producing a true result within the return statement?

I've encountered an issue with VS code where the return true command is not displaying anything in my terminal, while console.log(map[arr2[j]]) successfully returns true. I'm unsure if this problem lies with node or my terminal. How can I ensure ...