I've created a sphere and the centre of the sphere is located at 0,0,0.
The radius of the sphere is 9.
I've created a cube that is positioned above the surface/faces of the sphere.
When I click on the cube and then proceed to click on any point on the surface of the sphere my cube will rotate it's relative position to the point clicked on the sphere (to look in the direction of the point so to say) and then it will move along the surface of the sphere towards the point clicked. The rotation and movement all happen within a render loop.
What I want to do is cast a Ray from a point relative to the cubes position but at a greater distance to the centre of the sphere. So for instance if the distance to any given point on any given face of my sphere is ~8.8 - 9 (of course the vertices would be at a distance of 9 and the centre of any face would be ~8.8 - 8.9) The distance of my cube from the centre of the sphere is 9.1. I want to cast a ray from about a distance of 12 towards the centre of my sphere.
So, if my cube is located at 0,0,9.1 then I want to cast a ray who's origin would be 0,0,12 and who's destination would be 0,0,0. Then only target the sphere as the object to intersect, determine the distance to any given point along any given face and then set the distance of the cube to 12 - someDistance. That way it would seem as though the cube is actually moving along the surface of the sphere. And if I modify the features of the sphere, the cube would appear to move along the contours of the surface.
Here is my code which is located inside of a looping render function.
Unfortunately it turns up nothing.
var direction = new THREE.Vector3(0,0,0);
var origin = new THREE.Vector3(object_cubi[x-1].posiX, object_cubi[x-1].posiY, object_cubi[x-1].posiZ);
origin.normalize();
origin.x *= 12;
origin.y *= 12;
origin.z *= 12;
var disRay = new THREE.Raycaster();
disRay.ray.set(origin, direction);
var rayIntersect = disRay.intersectObjects( targetList );
document.getElementById("test7").value = rayIntersect.length;
rayIntersect.length is always 0.
What am I missing?
To select the cube and pick a point on the surface I had to use raycaster and that code works fine. However it does incorporate projector().
all I needed to do was cast the ray from the centre of the sphere and make the material of the sphere double sided.
material.side = THREE.DoubleSide;
Now my cube moves along the contours of my sphere.
Related
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.
I am trying to plot an scene where there is an Earth that rotates independently from the camera. In this planet I plot random bezier curves just like in this example: https://pubnub.github.io/webgl-visualization/
Therefore, I add my bezier line as:
var origin = latLonToVector3(lat_source, lon_source, earth_radius);
var destination = latLonToVector3(lat_destination, lon_destination, earth_radius);
var bezierline = bezierCurveBetween(origin, destination);
earth.add(bezierline);
so that the plotted line rotates along with the Earth. Then, I managed to load a 3D model of a plane and make it follow the bezier curve as it is being drawn. So far so good. Finally, I would like to rotate the plane so that its belly is always following a tangent line to the bezier curve. To that end, I computed the tangent vectors for every two points of the line as:
var tangent_vectors = [];
for (var i = 0; i < pnts.length - 1; i++) {
var aux = new THREE.Vector3();
aux.subVectors(pnts[i+1], pnts[i]);
tangent_vectors[i] = aux.normalize();
}
return tangent_vectors;
Just to check that these vectors are ok, I used a THREE.ArrowHelper to see if they are tangent to every segment of the curve and indeed they are. Since I add them to the scene with earth.add( arrowHelper ); they also rotate with the planet and are consistent. I repeat this process over and over as the planet rotates by plotting and erasing the same bezier curve (same origin and destination).
However, the 3D Model behaves fine for the first bezier curve but as the planet rotates and a new bezier curve is plotted at the same place (with the same origin and destination coordinates) I can see that the plane is still following (plane.lookAt(tangent_vectors[point_index]);) the tangent lines of the original bezier curve (even though I am recomputing the tangent lines).
I think that the problem is that latitudes and longitudes (lat_source, lon_source, etc) are fixed in the real life reference framework. This causes that origin and destination variables always return the same values even though the planet is rotating. Then, the new bezier curves have essentially the same points but since I add these points using earth.add(bezier_line); Three.js internally takes care of rotating them to position them in the new rotation and this is not done with my tangent vectors.
I think this is the problem, but I do not know how to solve it. I guess I need to also rotate the tangent vectos of the curve according to the new rotation but I can't find how to do it.
Thanks for your help
I have created the TubeBufferGeometry. The code is following:
var curve = new THREE.CatmullRomCurve3( pointArray, false, "centripetal");
var geometry = new THREE.TubeBufferGeometry( curve, pointArray.length, tubeRadius, radiusSegments, closed );
To get the interested point, I used the Raycaster.intersectObject(), I can get the following results.
distance – distance between the origin of the ray and the intersection
point – point of intersection, in world coordinates
face – intersected face
faceIndex – index of the intersected face
object – the intersected object
uv - U,V coordinates at point of intersection
Now I can get the intersected point position in TubeBufferGeometry when moving the mouse.
How can I find the nearest point in the pointArray to the intersected point?
Should I convert the coordination of the intersected point into world vector?
Many thanks.
I have a scene in Three.js (r67) with a camera that is controlled by OrbitControls.
If I now select an arbitrary point (Vector3) in the scene, what would be the best way to bring this point (programmatically) to the nearest camera position just by rotating the camera?
Example Scenario
In the below picture the left side is the starting point. The camera rotates around the green sphere (like OrbitControls) where the center of the camera is the center of the sphere. I now like to automatically rotate the camera around the sphere (doing the minimum amount of moves) so that the red box is nearest to the camera (like on the right side).
Independntly to the method of selecting the point in the scene, there's several understanding to what you mean by "bringing camera just by rotating".
I suppose, You want to rotate the camera in the way, to make the selected point in the center of the screen.
This is simple:
camera.lookAt(your_point_in_scene);
You could do this more complicated. Firstly, find the current pointing vector. By default camera looks in direction Vector(0,0,1). When we rotate it in the same rotation as a camera, we will have camera direction:
var vec = new THREE.Vector3(0,0,1);
vec.applyQuaternion(camera.rotation._quaternion);
Now we must determine angle to rotate our camera, and axis, around which we would rotate.
Axis of rotation could be found as a cross product of camera direction and vector from camera to object. Angel could be extracted from dot product:
var object_dir = object_world_point.clone().sub(camera.position);
var axis = vec.clone().crossProduct(object_dir);
var angle = Math.acos( vec.clone().dot(object_dir) / vec.length() / object_dir.length());
Having angle and axis, we could rotate camera:
camera.rotateOnAxis(axis, angle);
Or, if you want to make it smooth:
// before animation started
var total_rotation = 0,
rotateon,
avel = 0.01; // 0.01 radian per second
if(total_rotation < angle){
rotateon = avel * time_delta;
camera.rotateOnAxis(axis, angle);
total_rotation += rotateon;
}
Well that's not hard Oo
You have a center/target point for the camera. You calculate the difference from the target position to the point position and normalize that vector to the length of the camera-centerpoint-distance (i.e. something like pointdistance.multiplyScalar(cameradistance.length() / pointdistance.length()) ).
And that's it. If I understood your question correctly. All you do is "extend" the point's positioni onto your "camera movement dome" and then you have the ideal new camera position. The camera's rotation is done automatic since you always target the center point.
Aaand if you want to smoothen the camera movement a bit you can just interpolate the angle (not the positions directly) with e.g. an exponential function, whatever you prefer.
Hi Dear please follow this
Independntly to the method of selecting the point in the scene, there's several understanding to what you mean by "bringing camera just by rotating".
I suppose, You want to rotate the camera in the way, to make the selected point in the center of the screen.
This is simple:
camera.lookAt(your_point_in_scene);
You could do this more complicated. Firstly, find the current pointing vector. By default camera looks in direction Vector(0,0,1). When we rotate it in the same rotation as a camera, we will have camera direction:
var vec = new THREE.Vector3(0,0,1);
vec.applyQuaternion(camera.rotation._quaternion);
Now we must determine angle to rotate our camera, and axis, around which we would rotate.
Axis of rotation could be found as a cross product of camera direction and vector from camera to object.
Angle could be extracted from dot product:
var object_dir = object_world_point.clone().sub(camera.position);
var axis = vec.clone().crossProduct(object_dir);
var angle = Math.acos( vec.clone().dot(object_dir) / vec.length() / object_dir.length());
I'm trying to have a plane face away from the camera with same orientation so it's aligned in the viewport.
I have a plane in front of the camera, perfectly aligned to the cameras viewport, and I want to flip it in front of the camera, along the objects Y axis, regardless of camera orientation.
The following will orient my plane to face at the camera and works for any orientation:
target.rotation.copy(camera.rotation);
The following will then flip the plane along the plane's Y axis:
target.rotation.y += Math.PI;
All good so far? Except when the camera rotation has a funky tilt to it, let's say it's looking up and to the left, tilted slightly to the right, the plane's flip is tilted, but not the same way as the camera, leaving me with a plane tilted either to the left or right...
I've tried several things such as:
target.rotation.z -= camera.rotation.z;
Nothing... Thanks for your help.
So the problem I was running into was when the camera was in negative z coordinates. This causes the flip on the Y axis to get messed up.
So basically you would do something like this:
var target = new THREE.Object3D();
//position
target.position.copy(s.camera.position);
target.position.add(THREE.Utils.cameraLookDir(s.camera).multiplyScalar(300));
//rotation
target.rotation.copy(s.camera.rotation);
target.rotation.y += PI;
target.rotation.z = -s.camera.rotation.z;
if (s.camera.position.z < 0) {
target.rotation.z = s.camera.rotation.z;
}
EDIT:
Add the following to appropriate spots in your program.
camera.rotation.eulerOrder = 'XZY';
target.rotation.eulerOrder = 'XZY';
Seems to solve previously encountered tilt issues! (see below)
RESOLVED:
Flipped planes tilted the wrong way in some instances, for example when in negative z coords and also the y rotation is not equal to 0, example: point in space hovering and looking at 0, 0, 0.
This is the solution I was looking for when I found this page (taken from this answer):
mesh.lookAt( camera.position );
The local z-axis of the mesh should then point toward the camera.