Rotating Box3 together with the model in ThreeJS - three.js

I have the following question.
There is a model, through the setFromObject method I get Box3 (screenshot - http://prntscr.com/12787py). Next, I rotate the model and get a new Box3 (screenshot - http://prntscr.com/12789fy).
Is it possible after rotating the model to get Box3 with the same rotation, as if Box3 was rotating with the model?

Box3 is a mathematical representation of a box. As such, it is represented with only two Vector3 properties (max and min) that represent two opposing corners of the box. The values of these do not represent a box in full 3D space, but rather an axis-aligned box.
It looks like you're using BoundingBoxHelper. This creates a wireframe box that is world-aligned. This means it will compute its shape based on the transformed positions of the geometry vertices, and so it may change shape as your mesh is rotated.
To create a shape-tight wireframe box that rotates with your object, you will need to create one directly from your geometry, and ensure the same transformation is applied to both shapes.
// your shape
const shapeGeo = new BoxGeometry( 10, 10, 10 )
shapeGeo.computeBoundingBox() // <----------- DO THIS BEFORE ADDING IT TO THE SCENE!
const shapeMat = new MeshPhongMaterial( { color: 'red' } )
const shapeMsh = new Mesh( shapeGeo, shapeMat )
// your wireframe
const bboxMin = shapeGeo.boundingBox.min
const bboxMax = shapeGeo.boundingBox.max
const wireGeo = new BufferGeometry()
wireGeo.setAttribute( 'position' , new BufferAttribute( new Float32Array( [
bboxMin.x, bboxMin.y, bboxMin.z,
bboxMin.x, bboxMin.y, bboxMax.z,
bboxMin.x, bboxMax.y, bboxMax.z,
bboxMin.x, bboxMax.y, bboxMin.z,
bboxMax.x, bboxMin.y, bboxMin.z,
bboxMax.x, bboxMin.y, bboxMax.z,
bboxMax.x, bboxMax.y, bboxMax.z,
bboxMax.x, bboxMax.y, bboxMin.z,
] ), 3, false ) )
wireGeo.setIndex( new BufferAttribute( new Uint8Array( [
0, 1, 1, 2, 2, 3, 3, 0,
4, 5, 5, 6, 6, 7, 7, 4,
0, 4, 1, 5, 2, 6, 3, 7
] ), 1, false ) )
const wireMat = new LineBasicMaterial( { color: 'yellow' } )
const wireBox = new LineSegments( wireGeo, wireMat )
Now, here's where things take what might seem like an odd twist. Once you have your wire box, you can simply add it to your shape, and future changes to your shape will be passed on to your wire box:
scene.add( shapeMsh )
shapeMsh.add( wireBox )
This works because transformations are passed on to children*, and a Mesh is really just an extension of Object3D, so a Mesh can have children just like any other Object3D derivative.
* as long as you don't disable automatic matrix updates

Related

Animate every point of a line to another line with three.js

I want to implement an animation.
The animation should be a line move to another line. There will be some deformation in the process of the line moving
There is a correspondence between the points of the two lines.
How to implements it with three.js?
I try to use the tween.js.It works.
const material = new THREE.LineBasicMaterial({ color: 0x0000ff })
const geometry = new THREE.BufferGeometry().setAttribute('position',
new THREE.Float32BufferAttribute([-2, 0, 0, -0.5, 0, -0.5, 0, 0, -2], 3))
const line = new THREE.Line(geometry, material)
var position2 = new Float32Array([5, 0, 0, 1, 1, 1, 0, 0, 5])
setupObjectPositionTween(line, geometry.attributes.position.array, position2,
10000, 0, TWEEN.Easing.Linear.None) // duration, delay, easing
scene.add(line)
function setupObjectPositionTween(object, source, target, duration, delay, easing) {
new TWEEN.Tween(source)
.to(target, duration)
.delay(delay)
.easing(easing)
.onUpdate(function () {
// console.log(object,source,target)
object.geometry.attributes.position.array = source
object.geometry.attributes.position.needsUpdate=true
})
.start()
}
and in the render function
TWEEN.update()
I suggest you implement the animation of the green line with morph targets. Meaning the green line represents your default geometry whereas the blue line represents a morph target (also known as blend shape). You can then animate the transformation from green to blue by modulating the morphTargetInfluences parameter from 0 to 1.
Morph targets are part of the geometry data and defined in the BufferGeometry.morphAttributes property. Since multiple meshes can share the same geometry, the morphTargetInfluences property belongs to 3D objects like a mesh.
I suggest you study how the official example webgl_morphtargets is implemented. You can apply the same principles on lines.

Removing edges from WireframeGeometry in three.js

I am experimenting with THREE.js and am trying to implement a WireframeGeometry for a plane and remove the diagonal lines so that it looks like a grid of squares instead of a grid of squares with diagonal lines running through them.
Is it possible ot remove individual lines from a wireframe geometry that comes with THREE.js?
let matLine, wireframe
let geo = new THREE.PlaneGeometry( 80, 80, 80, 80 )
const geometry = new WireframeGeometry2( geo )
matLine = new LineMaterial( {
color: 0x4080ff,
linewidth: 6, // in pixels
//resolution: // to be set by renderer, eventually
dashed: false
} )
wireframe = new Wireframe( geometry, matLine )
wireframe.computeLineDistances()
wireframe.scale.set( 1, 1, 1 )
wireframe.rotation.x = Math.PI / 2
scene.add( wireframe )
Three.js faces are triangles and WireframeGeometry draws lines on the edges of faces. It's not possible to make a grid of squares with WireframeGeometry.
If you only need the grid for a Plane, you could use GridHelper:
https://threejs.org/docs/index.html?q=grid#api/en/helpers/GridHelper
But it works for only a plane and not other geometry.

How to create a simple three dimensional coordinate display?

I have a series of data that simply represents X/Y/Z coordinates, and would like to display them on screen. I am aware of the existence of three.js, but the examples I have waded through so far seem to be for far more complex animations and whatnot, and have not managed to find an ELI5 tutorial of set of documentation to get me going.
Note that I am not married to three.js, but it does seem like the best tool for the job.
I'm not looking for someone to do it for me, just some links to some basic documentation would be so very appreciated!
Straightforward, conceptually consists of making sphere's and setting their position to your coordinates.
1) Have coordinate data
const coordData = [
{x: 9, y: 2, z: 6},
{x: 3, y: 7, z: 4},
...
]
2) Create Geometry, Material and Group
const pointGeom = new THREE.SphereBufferGeometry( 5, 32, 32 ),
pointMat = new THREE.MeshBasicMaterial({ color: 0xffff00 }),
pointGroup = new THREE.Group();
3) Loop over coordinate data and create a point (sphere) for each using above const's
for (var i = coordData.length - 1; i >= 0; i--) {
const coord = coordData[i],
point = new THREE.Mesh( pointGeom, pointMat );
point.position.set( coord.x, coord.y, coord.z );
pointGroup.add(point);
}
4) Add Group to your scene
scene.add(pointGroup);
I ended up coming up with a great answer through the plot.ly library. This page was pretty much perfect for what I wanted to do.
https://plot.ly/javascript/3d-point-clustering/

three.js set objects in local coordinate system of another object

I was wondering if it is possible to place 3d objects within a local coordinate system of another object in three.js. so the placed objects should be relative to the "origin" object.
for example: i scan an image with the device camera (with expo AR) and want to place objects which got a fixed distance to the image. I think these positions are relative to the camera, isn't it?
this.scene.add(chair)
chair.position.set( 1, 0, -5);
this.scene.add(chair2)
chair2.position.set( 1, 0 , -3);
I think what you're looking for is the THREE.Group object. It lets you nest elements in a group, so if you change the coordinates of the group, its children move with it. For instance:
// Create parent, set its pos to 0, 5, 0
var parent = new THREE.Group();
scene.add(parent);
parent.position.set(0, 5, 0);
// create child, and add to parent
var chair1 = new THREE.Mesh(geom, mat);
parent.add(chair1);
chair1.position.set(1, 0, 0);
// create child, and add to parent
var chair2 = new THREE.Mesh(geom, mat);
parent.add(chair2);
chair2.position.set(0, 1, 0);
chair1 will be at [1, 5, 0] in global coordinates, but [1, 0, 0] in local space.
chair2 will be at [0, 6, 0] in global coordinates, but [0, 1, 0] in local space.

Create a geometry with N equal sized faces

Using Three.JS, what is the easiest way to make an n-sided geometry with an arbitray number of equal sized faces?
For example you can make a cube using the BoxGeometry, and a octahedron using the OctahedronGeometry, but what about everything in between?
The 5 Platonic Solids can be rendered like so:
var geometry = new THREE.BoxGeometry( 10, 10, 10 );
var geometry = new THREE.TetrahedronGeometry( 10, 0 );
var geometry = new THREE.OctahedronGeometry( 10, 0 );
var geometry = new THREE.IcosahedronGeometry( 10, 0 );
var geometry = new THREE.DodecahedronGeometry( 10, 0 );
There is also the BufferGeometry version of these 5 classes.
For the material, use shading: THREE.FlatShading for the best look.
three.js r.85

Resources