Three.js - get terrain height (position.y) of the mesh at specific position.x,z - without mouse and raycaster? - three.js

Let's say I have a sort of rather simple terrain from Blender exported as GLB object, which is a Group and contains a Mesh with BufferGeometry. I have another GLB object which is a model of vehicle. How can I read proper position.y at specific x,z locations (idealy 4 locations for setting car position and rotation) without moving mouse and using raycaster? I need to know what is elevation and height at specific region. Any simple clue without game-physics engine on top of ThreeJS?

Just use a Raycaster. I don't know why you don't want to use it, it's the easiest way to find an intersection without a physics engine and without tons of math.
Simply use Raycaster.set() to point straight down from your XZ coords and see where it intersects the terrain:
var ray = new THREE.Raycaster();
var rayPos = new THREE.Vector3();
// Use y = 100 to ensure ray starts above terran
rayPos.set(x, 100, z);
var rayDir = new THREE.Vector3(0, -1, 0); // Ray points down
// Set ray from pos, pointing down
ray.set(rayPos, rayDir);
// Check where it intersects terrain Mesh
let intersect = ray.intersectObject(terrainMesh);
console.log(intersect);
See here for the intersect object. It includes the point in space where the intersection takes place.

Related

THREEjs create an intersection plane for a raycast with negative origin

I have a THREEJS scene with an object that 'looks at my mouse'. This works fine and I am using a raycast to get the mouse position like so:
this.intersectionPlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 10);
this.raycaster = new THREE.Raycaster();
this.mouse = new THREE.Vector2();
this.pointOfIntersection = new THREE.Vector3();
On the mouse-move event I lookAt the pointOfIntersection vector and the object rotates. This works really well.
onDocumentMouseMove = (event) => {
event.preventDefault();
this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
this.raycaster.setFromCamera(this.mouse, this.camera);
this.raycaster.ray.intersectPlane(this.intersectionPlane, this.pointOfIntersection);
let v3 = new THREE.Vector3(this.pointOfIntersection.x*0.05, this.pointOfIntersection.y*0.05, this.pointOfIntersection.z);
if(this.pebbleLogo){
this.pebbleLogo.lookAt(v3);
// console.log(v3);
}
if(this.videoWall){
this.videoWall.lookAt(v3);
}
}
BUT, I want to do the same thing with another object that lives at a z-depth of -20 and the camera flies through to this position. At this point, it also flies through the intersectionPlane and the raycast no longer works.
The intersectionPlane is not added to the scene so it doesn't have a position that I can move so how do I make sure that it stays with the camera?
I can see that the plane has two properties:
normal - (optional) a unit length Vector3 defining the normal of the plane. Default is (1, 0, 0).
constant - (optional) the signed distance from the origin to the plane. Default is 0.
I have been able to move the Plane using a translate but this is not ideal as I need the plane to be in a constant position in relation to the camera (just in front of it). I tried to make the plane a child of the camera but it didn't seem to make any difference to its position.
Any help appreciated.
When you perform renderer.render(scene, cam), the engine updates the transformation matrices of all objects that need to be rendered. However, since your camera and plane are not descendants of the scene, you'll have to manually update these matrices. The plane doesn't know that it's parent camera has moved, so you might need to perform plane.updateMatrix(). You can read about manually updating transformation matrices in the docs.
I think since only the parent moves, you might need to use updateMatrixWorld() or updateWorldMatrix() instead. But one of these 3 options should work.
Edit
Upon re-reading your code, it looks like you're using a purely Mathematical THREE.Plane object. This is not an Object3D, which means it cannot be added as a child of anything, so it doesn't behave as a regular object.
My answer assumed you were using a Mesh with PlaneGeometry, which is an Object3D, and it can be added as a child of the camera.

THREE.js raycaster intersectObject method returns no intersection when checking if point is inside mesh

I want to check whether a point is inside a mesh or not. To do so, I use a raycaster, set it to the point's origin and if the ray intersects the mesh only once, it must be inside. Unfortunately, the intersectObject always returns no intersection, even in cases I know that the point is located inside the mesh.
The point's origin is given in world coordinates and the mesh's matrixWorld is up to date too. Also, I set the mesh.material.side to THREE.DoubleSide, so that the intersection from inside should be detected. I tried setting the recursive attribute to true as well, but as expected, this didn't have any effect (since the mesh is a box geometry). The mesh is coming from the Autodesk Forge viewer interface.
Here is my code:
mesh.material.side = THREE.DoubleSide;
const raycaster = new THREE.Raycaster();
let vertex = new THREE.Vector3();
vertex.fromArray(positions, positionIndex);
vertex.applyMatrix4(matrixWorld);
const rayDirection = new THREE.Vector3(1, 1, 1).normalize();
raycaster.set(vertex, rayDirection);
const intersects = raycaster.intersectObject(mesh);
if (intersects.length % 2 === 1) {
isPointInside = true;
}
The vertex looks like this (and it obviosly lies inside of the bounding box):
The mesh is a box shaped room with the following bounding box:
The mesh looks like this:
The geometry of the mesh holds the vertices in the vb. After applying the world matrix, the mesh vertices are correct in world space. Here is a part of the vb list:
Why does the raycaster not return any intersection? Is the matrixWorld of the mesh taken into account when computing the intersections?
Thanks for any kind of help!
Note that Forge Viewer is based on three.js version R71, and it had to modify/reimplement some parts of the library to handle large and complex models (especially architecture and infrastructure designs), so THREE.Mesh objects might have a slightly different structure. In that case I'd suggest to raycast using Forge Viewer's own mechanisms, e.g., using viewer.impl.rayIntersect(ray, ignoreTransparent, dbIds, modelIds, intersections);.

Rotate around World Axis

I tried to rotate an object arount the Worlds-Y-Axis, with
myObject.rotateOnWorldAxis(new THREE.Vector3(0,1,0),THREE.Math.degToRad(1));
but the result was, that the object is only rotated in object space.
To be sure that I used the correct method I looked into the documentation and found that there are three methods to rotate an object:
.RotateY(rad) // rotate in Local Space
.rotateOnAxis(axis,rad) // rotation in Object Space
.rotateOnWorldAxis(axis,rad) // rotation in World Space
It seems that I used the correct method.
Is this a bug or an understanding problem on my side?
Here is a JSFiddle which illustrates my problem (the blue cube should rotate around the world axis).
Here is a second Fiddle where thy cyan cube is a child of another object.
It looks to me like your real question isn't regarding world space or object space rotations, cause those are working as expected in your examples.
You probably meant, how to change the point of rotation of an object. If that is the case, you have two options, you can either translate all your geometry vertices in respect to a pivot point of rotation. That way, your pivot will be centered at (0,0,0) and your vertices will rotate in respect to that.
mesh.geometry.translate( x, y, z );
Or you can make your object a child of a different Object3D (pivot), position your original mesh similarly to what was described above and rotate your pivot mesh.
var cube = new THREE.Mesh( geometry, material );
var pivot = new THREE.Object3D();
cube.position.set( 0, 12, 30 ); // offset from center
pivot.add( cube );
scene.add( pivot );
//...
pivot.rotation.y += Math.PI/2;
JSFiddle

How can I rotate around the center of an object in three.js?

I am dynamically adding a number of different objects of various sizes into a scene (one per click) and scaling and positioning them. Now I want to be able to rotate the objects around the Y axis at their center. I have added a boundingBox and an axesHelper, but the latter is showing up in the bottom corner of the objects. Reading this answer, which is similar to mine, it seems like this might be because of an offset. I can find the center of the object fine with this:
var box3 = new THREE.Box3();
var boundingBox = new THREE.BoxHelper( mesh, 0xffff00 );
scene.add( boundingBox );
box3.setFromObject( boundingBox );
center = box3.getCenter( boundingBox.position );
console.log( "center: ", center );
But when I try to reset the center to this position, following this answer, my object shoots way off into space.
box3.center(mesh.position);
mesh.position.multiplyScalar( -1 );
And I’m not really clear (even after reading the documentation) what “multiplyScalar” does/means. By playing with that number, I can get the object closer to the desired position, but the object still doesn't rotate around its center, and the AxesHelper is still at the original location.
Your object is not rotating around its center. Likely, your object's geometry is offset from the origin.
If you are dealing with a single Mesh or Line, you can center the object's geometry by calling
geometry.center();
This method will translate the vertices of the geometry so the geometry's bounding box is centered at the origin.
three.js r.97

Three.js - change camera POV on click

Some project background:
I have a Sprite particle field that is randomly generated. The camera is located at position 0, 0, 0. The particle field is all around the camera. I'm using Raycaster to be able to select the particle that is clicked on and change it's color. Once clicked I would like the camera to focus on this particle. I'm also attempting to use Tween to glide the particle into view.
I've attempted several different methods and none of them work. They are described here:
A traditional lookAt method that used Raycaster to pick up the intersect point from clicking.
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(mouse, this.camera);
var intersects = raycaster.intersectObjects( this.starfield.children );
this.camera.lookAt(intersects[0].object.position)
A distanceTo method where the distance between the camera and the intersect coordinates is used to move the camera. This only moves the camera along the z plane. It wont actually change its POV.
var cameraPosition = new THREE.Vector3(this.camera.position.x, this.camera.position.y, this.camera.position.z);
var intersectPosition = new THREE.Vector3(intersects[0].object.position.x, intersects[0].object.position.y , intersects[0].object.position.z );
var zoomPos = intersectPosition.distanceTo( cameraPosition );
const newCameraPosition = cameraPosition.addVectors(this.camera.position, vector.setLength(zoomPos));
I calculated the angle of rotation for each X, Y, and Z axis via tan and cos equations. I then attempted to rotate the camera by those degrees. I even tried converting them to radians to see if that would make a difference with the rotation method. It didnt :(
I don't know what else to do. At this stage I'm completely open to a different approach as long as I get this camera working. I'm very stuck,
any help would be greatly appreciated!
Instead of using
intersects[0].object.position
try using
intersects[0].point
.point is the world space position of the hit.
.objectis the object the triangle belongs to. .object.position is just the origin of that object, in this case the particle system. The particle positions themselves are relative to this origin.

Resources