Dynamically update vertices & faces of a Mesh three js - three.js

Hey im creating a type go mountain in my scene and want to let the tops of it wiggle to specific values. Now im trying to access the vertices I've set before and specify them again over time trough the update function. How do I access them probably and recalculate the faces?
geom1.vertices = [
new THREE.Vector3( -1000, -300, 0 ),
new THREE.Vector3( -1000, 0, 0 ),
new THREE.Vector3( -20, 120, 0 ),
new THREE.Vector3( 60, 85, 0 ),
new THREE.Vector3( 140, 100, 0 ),
new THREE.Vector3( 1000, 0, 0 ),
new THREE.Vector3( 1000, -300, 0 ),
new THREE.Vector3( 0, -300 , 0 ),
];
geom1.faces = [
new THREE.Face3( 7, 0, 1 ),
new THREE.Face3( 7, 1, 2 ),
new THREE.Face3( 7, 2, 3 ),
new THREE.Face3( 7, 3, 4 ),
new THREE.Face3( 7, 4, 5 ),
new THREE.Face3( 7, 5, 6 ),
];
geom1.computeFaceNormals();
geom1.dynamic = true;
var material1 = new THREE.MeshBasicMaterial( {
color: 0x7dae81,
side: THREE.DoubleSide,
} );
hill1 = new THREE.Mesh( geom1, material1);
in the update function im doing this
geom1.vertices[2].y += 0.1;
geom1.verticesNeedUpdate;

You need to set
geometry.verticesNeedUpdate = true;
For more information, see verticesNeedUpdate in Three.js.
Also, Geometry does not have a dynamic property.
three.js r.85

Update answer for version:
Three.js r.114
let material = new THREE.MeshPhongMaterial ({
color: 0xffa94b,
opacity: 0.30,
side: THREE.DoubleSide,
depthWrite: true,
flatShading: true
});
let geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
v0.x, v0.y, v0.z,
v1.x, v1.y, v1.z,
v2.x, v2.y, v2.z,
v3.x, v3.y, v3.z,
etc...
]);
geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(
[0, 1, 2,
0, 2, 3,
0, 3, 1,
etc...]);
g_myMesh = new THREE.Mesh(geometry, material);
function update_vertices(mesh){
let numVertices = mesh.geometry.attributes.position.count;
for (let v = 0; v < numVertices; v++) {
let o = mesh.geometry.attributes.position;
// Update vertex position, do whatever:
let p = new THREE.Vector3(o.getX(v), o.getY(v)+25.0, o.getZ(v));
mesh.geometry.attributes.position.setXYZ(v, p.x, p.y, p.z);
}
// set to true each time you modify the positions:
mesh.geometry.attributes.position.needsUpdate = true;
mesh.geometry.computeVertexNormals();
}
function animationLoop(){
...
updateVertices(g_myMesh);
...
}

Related

Three.js assign array of materials to an indexed BufferGeometry

I have a BufferGeometry triangular prism; where I have specified the 6 vertices and then added indexes to create the 8 faces (2 triangle faces per square plane).
I have then setup 5 groups, so that each side of the prism is a group.
And it works here when I have a single material assigned to the whole object: https://jsfiddle.net/30ez17dw/1/
However I want to be able to assign an array of materials, so that each side (group) has it's own materials. But when I do this the object disappears:
https://jsfiddle.net/30ez17dw/2/
How can I fix my code to make the array of materials work?
You have not specified your groups correctly. Try it like so:
var camera, scene, renderer;
init();
animate();
function init() {
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 10);
camera.position.z = 5;
camera.position.y = 2;
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
var geometry = new THREE.BufferGeometry();
const y = 0.866025404;
const y2 = 0.5;
const h = 1;
const vertices = new Float32Array([
-y2, 0, 0,
y2, 0, 0,
0, 0, y,
-y2, h, 0,
y2, h, 0,
0, h, y,
]);
const indices = [
0, 1, 2, // Top
5, 4, 3, // Bottom
3, 1, 0, // Back
1, 3, 4, // Back
0, 2, 3, // Left
5, 3, 2, // Left
4, 2, 1, // Right
2, 4, 5, // Right
];
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setIndex(indices);
geometry.computeVertexNormals();
geometry.clearGroups();
geometry.addGroup(0, 3, 0);
geometry.addGroup(3, 6, 1);
geometry.addGroup(6, 12, 2);
geometry.addGroup(12, 18, 3);
geometry.addGroup(18, 24, 4);
var material = [
new THREE.MeshBasicMaterial({
color: 0x00ff00
}),
new THREE.MeshBasicMaterial({
color: 0xff0000
}),
new THREE.MeshBasicMaterial({
color: 0x0000ff,
}),
new THREE.MeshBasicMaterial({
color: 0xffff00
}),
new THREE.MeshBasicMaterial({
color: 0x00ffff
})
];
var mesh = new THREE.Mesh(geometry, material); // , side: THREE.DoubleSide
scene.add(mesh);
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild(renderer.domElement);
}
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three#0.132.0/build/three.min.js"></script>
The indices you pass to addGroup() are meant to be consecutive.

Single color for each line in three.js

Is it possible to draw a line in three.js with a single color attribute, something similar to x3d's indexedLineSet than defining a color per vertex?
let material = new THREE.LineBasicMaterial( {
color: 0xff0000,
vertexColors: THREE.VertexColors
} );
You can achieve this with LineSegments and the respective geometry object. There is no line material option that could replace such a color definition.
var geometry = new THREE.BufferGeometry();
var vertices = [];
var colors = [];
// geometry data for three line segments with different colors
vertices.push( 0, 0, 0 );
vertices.push( 1, 0, 0 );
vertices.push( 1, 0, 0 );
vertices.push( 1, 1, 0 );
vertices.push( 1, 1, 0 );
vertices.push( 0, 1, 0 );
colors.push( 1, 0, 0 );
colors.push( 1, 0, 0 );
colors.push( 0, 1, 0 );
colors.push( 0, 1, 0 );
colors.push( 0, 0, 1 );
colors.push( 0, 0, 1 );
geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
geometry.addAttribute( 'color', new THREE.Float32BufferAttribute( colors, 3 ) );
var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } );
var lines = new THREE.LineSegments( geometry, material );
scene.add( lines );
https://jsfiddle.net/fLgvcka7/
three.js R109

Why do I see only half of crate?

I don't understand why I only see half of crate. I recall that it happened to me before, with other graphics pipelines.
Here is the fiddle link: https://jsfiddle.net/20azohgc/10/
Here is the code:
//Basic THREE setup:
const canvas = document.getElementById("canvasThree");
const scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45, 1, 1, 500);
camera.position.set( 0, 0, 100 );
camera.lookAt( new THREE.Vector3( 0, 0, 0 ));
camera.position.set( 0, 0, 100 )
camera.lookAt( new THREE.Vector3( 0, 0, 0 ) )
const renderer = new THREE.WebGLRenderer({ canvas });
const light = new THREE.PointLight(0xFFFFFF);
light.position.set(0, 1, 2);
scene.add(light);
var texture = new THREE.TextureLoader().load( "https://raw.githubusercontent.com/mrdoob/three.js/master/examples/textures/crate.gif" );
var material = new THREE.MeshBasicMaterial({ color: "white", map: texture });
const pos = new Float32Array([0, 0, 0, 0, 10, 0, 10, 10, 0, 0, 0, 0, 10, 0, 0, 10, 10, 0]);
const nrm = new Float32Array([0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
const tex = new Float32Array([0,0, 1,0, 1,1, 0,0, 0,1, 1,1]);
const geo = new THREE.BufferGeometry();
geo.addAttribute("position", new THREE.BufferAttribute(pos, 3));
geo.addAttribute("normal", new THREE.BufferAttribute(nrm, 3));
geo.addAttribute("uv", new THREE.BufferAttribute(tex, 2));
//This is a drawing group, each square is 6 indices (2 triangles with 3 vertices each).
geo.addGroup(0 ,6,0);
const mesh = new THREE.Mesh(geo, [material]);
mesh.position.set(-2,-0.5,0);
scene.add(mesh);
function update(){
scene.rotation.y = 0.25 * Math.cos(performance.now() * 0.001)
renderer.render(scene, camera);
requestAnimationFrame(update);
}
update();

Is it possible to hide parts of an aframe entity?

Is there something equivalent to CSS's overflow: hidden in aframe? For example, can I constrain an entire to be within a bounding and have everything that is bigger than the box geometry to be hidden/invisible?
There is clipping planes: https://threejs.org/examples/webgl_clipping.html
https://github.com/mrdoob/three.js/blob/master/examples/webgl_clipping.html
// ***** Clipping planes: *****
var localPlane = new THREE.Plane( new THREE.Vector3( 0, - 1, 0 ), 0.8 );
var globalPlane = new THREE.Plane( new THREE.Vector3( - 1, 0, 0 ), 0.1 );
// Geometry
var material = new THREE.MeshPhongMaterial( {
color: 0x80ee10,
shininess: 100,
side: THREE.DoubleSide,
// ***** Clipping setup (material): *****
clippingPlanes: [ localPlane ],
clipShadows: true
} );
var geometry = new THREE.TorusKnotBufferGeometry( 0.4, 0.08, 95, 20 );
object = new THREE.Mesh( geometry, material );

three js geometry merge matrix

var ShipGeometry = new THREE.Geometry();
var ShipModule1geo = new THREE.SphereGeometry( 150.0, 40, 30 );
ShipGeometry.merge(ShipModule1geo); // this works
var ShipModule2geo = new THREE.BoxGeometry( 5.0, 5.0, 600, 1, 1, 1 );
var matrix = new THREE.Matrix4().makeTranslation(0,0,450);
ShipGeometry.merge(ShipModule2geo,matrix); // this works too
var ShipModule3geo = new THREE.CylinderGeometry( 150, 150, 20, 32 );
var matrix = new THREE.Matrix4().makeTranslation(0, 0, 850).makeRotationZ(Math.PI/2);
ShipGeometry.merge(ShipModule3geo,matrix); // only rotation is applyed
shipMesh = new THREE.Mesh( ShipGeometry, ShipMaterial );
....
My question, why is applyed only makeTranslation(0, 0, 850), not makeRotationZ(Math.PI/2) in last case?
How to apply both before merging?
You can apply both matrices like this:
var matrix = new THREE.Matrix4();
matrix.multiply( new THREE.Matrix4().makeTranslation(0, 0, 850) );
matrix.multiply( new THREE.Matrix4().makeRotationZ(Math.PI/2) );

Resources