Three.js lookat seems to be flipped - javascript

I have a demo of what I mean here: Test Site or (Backup)
For some reason, even though the mouse vector is correct my object is rotated by 90 degrees always in favor of the positive Y axis. The only call that this could be going wrong, as far as I can tell, in is the call: ship.mesh.lookAt(mouse);, I call this every time the screen is animated.
Can anyone tell me what to do to fix this and why it is doing it?

object.lookAt( position ) orients the object so that the object's local positive z-axis points toward the desired position.
Your "ship's" front points in the direction of the local positive y-axis.
EDIT:
To re-orient your geometry, apply a matrix right after the geometry is created, like so:
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI / 2 ) );

Related

three.js: finding nearest point of a Mesh to mouse cursor

Imagine this three.js scene, set up with an OrthographicCamera and OrbitControls:
When the user drags the yellow disc (meant to represent the Sun), the disc needs to move along its yellow circle in response to this action. Here's the scene from another angle, so you can see the full yellow circle:
So, my event handler must determine which point on this circle is closest to the current cursor position. This yellow circle is a THREE.Mesh, by the way.
I'm using THREE.Raycaster to determine some mouseover events, using its intersectObjects() function, but it's not clear to me how to find the nearest point of a single object with this Raycaster. I'm guessing there is some simple math I can do after translating the mouse's position to world co-ordinates. Can someone help me with this? Is Three.js's Raycaster useful here? If not, how do I determine the nearest point of this mesh?
The full source code is here, if it's helpful: https://github.com/ccnmtl/astro-interactives/blob/master/sun-motion-simulator/src/HorizonView.jsx Search for this.sunDeclination, which corresponds to the yellow circle's Mesh object.
For a working demo, go here: https://ccnmtl.github.io/astro-interactives/sun-motion-simulator/
For reference, the sun should behave like this: https://cse.unl.edu/~astrodev/flashdev2/sunMotions/sunMotions068.html (requires Flash)
The simplest version:
get a point on disk
make a projection in the plane of the circle
knowing the radius of the circle, calculate the multiplier for multiplying the vector by the scalar
var point = res.point.clone();
point.z = 0; // Project on circle plane
var scale = circleRadius / point.length();
point.multiplyScalar(circleRadius / point.length())
[ https://jsfiddle.net/c4m3o7ht/ ]
The raycaster returns all objects hit by the ray.. all of the hit points in worldspace.. (which you can convert to/from model space via object3d.worldToLocal and localToWorld)
It returns the hit distances.. which you can sort by whatever heuristic you need...
What I usually do is cast on mouseDown.. record the object and point.. then on mouseMove get the same objects hit point, and apply my edit operation using the difference between those 2 points.
Is this what you're talking about?

updating an object's geometry when camera is moving causes glitches - three.js

I have a problem updating a vertex of a line in three.js
So, I want to have a line in my scene, that its start is always at the (0,0,0) and its end is always in a specific position of the users screen (in x,y coordinates).
What I do to achieve that (and I almost succeed) is to have an invisible plane looking always to the camera and also have its position always a little bit in front of the camera. The reason I do that is because I want the line to seem like "going towards" the user's screen. So I "send" a raycaster from the desired screen position (in x,y) and I check in which point of the plane it intersect and that's my 3D point in three.js scene. Then I update one of the 2 vertices of the line.
The problem
What I do works fine, the line end is where I want to be, but something in updating the camera and the vertex is not synchronized and causes some noticeable glitches. When I move the camera, the line do not update itself quickly and smoothly, and as a result I see the line in other position before I see it in the calculated and desireable one.
Please take a look at this jsfiddle I created to emulate the problem.
What can I do to avoid these glitches?
Thanks
code i use in render function :
var cameToCenterScaled = camera.position.clone();
cameToCenterScaled.setLength(cameToCenterScaled.length()*0.9);
plane.position.set(cameToCenterScaled.x, cameToCenterScaled.y, cameToCenterScaled.z);
plane.lookAt(camera.position);
// define in pixels where in screen we want the line to end
var notePos = findNotePoint(120,30);
linemesh.geometry.vertices[ 1 ].set(notePos.x, notePos.y, notePos.z) ;
linemesh.geometry.verticesNeedUpdate = true;
when you raycast you set the raycaster from camera, you have to make sure the camera matrices are updated
simply add
camera.updateMatrixWorld();
before you call
raycaster.setFromCamera( new THREE.Vector2( x_, y_ ) , camera );
and the line will behave as you described

How does Three.js store direction?

i'm writing a server for a game me and my friends are making. I want to keep the direction a certain player is looking at in a 3D plane in a variable. I was considering having it an object with two variables of radians, i.e vertical angle and horizontal angle. But my friend told me to store it the way Three.js stores it because it would make his life easier. Could anybody help me out here?
You should brush up on Math for Game Developers series: https://www.youtube.com/watch?v=sKCF8A3XGxQ&list=PLW3Zl3wyJwWOpdhYedlD-yCB7WQoHf-My&index=1
Specifically, using vectors. You should store the orientation / facing angle of your characters or entities as a Vector3, or a 3 dimensional vector. In THREE.js, that's new THREE.Vector3( x, y, z )
To get the direction of object A to object B, relative to A you would do:
var direction = posB.clone().sub( posA )
This clones position B so we don't mess it up by subtraction, and then immediately subtract it by A.
However you'll notice how the vector now has some length. This is often undesirable in calculations, for example if you wanted to multiply this direction by something else say, a thrust force. In this case, we need to normalize the vector:
direction.normalize()
Now you can do fun stuff like:
posA.add( direction.clone().multiplyScalar( 10.0 ) );
This will move posA in the direction towards posB, 10 units of space.

How do I 'wrap' a plane over a sphere with three.js?

I am relatively new to three.js and am trying to position and manipulate a plane object to have the effect of laying over the surface of a sphere object (or any for that matter), so that the plane takes the form of the object surface. The intention is to be able to move the plane on the surface later on.
I position the plane in front of the sphere and index through the plane's vertices casting a ray towards the sphere to detect the intersection with the sphere. I then try to change the z position of said vertices, but it does not achieve the desired result. Can anyone give me some guidance on how to get this working, or indeed suggest another method?
This is how I attempt to change the vertices (with an offset of 1 to be visible 'on' the sphere surface);
planeMesh.geometry.vertices[vertexIndex].z = collisionResults[0].distance - 1;
Making sure to set the following before rendering;
planeMesh.geometry.verticesNeedUpdate = true;
planeMesh.geometry.normalsNeedUpdate = true;
I have a fiddle that shows where I am, here I cast my rays in z and I do not get intersections (collisions) with the sphere, and cannot change the plane in the manner I wish.
http://jsfiddle.net/stokewoggle/vuezL/
You can rotate the camera around the scene with the left and right arrows (in chrome anyway) to see the shape of the plane. I have made the sphere see through as I find it useful to see the plane better.
EDIT: Updated fiddle and corrected description mistake.
Sorry for the delay, but it took me a couple of days to figure this one out. The reason why the collisions were not working was because (like we had suspected) the planeMesh vertices are in local space, which is essentially the same as starting in the center of the sphere and not what you're expecting. At first, I thought a quick-fix would be to apply the worldMatrix like stemkoski did on his github three.js collision example I linked to, but that didn't end up working either because the plane itself is defined in x and y coordinates, up and down, left and right - but no z information (depth) is made locally when you create a flat 2D planeMesh.
What ended up working is manually setting the z component of each vertex of the plane. You had originaly wanted the plane to be at z = 201, so I just moved that code inside the loop that goes through each vertex and I manually set each vertex to z = 201; Now, all the ray start-positions were correct (globally) and having a ray direction of (0,0,-1) resulted in correct collisions.
var localVertex = planeMesh.geometry.vertices[vertexIndex].clone();
localVertex.z = 201;
One more thing was in order to make the plane-wrap absolutely perfect in shape, instead of using (0,0,-1) as each ray direction, I manually calculated each ray direction by subtracting each vertex from the sphere's center position location and normalizing the resulting vector. Now, the collisionResult intersection point will be even better.
var directionVector = new THREE.Vector3();
directionVector.subVectors(sphereMesh.position, localVertex);
directionVector.normalize();
var ray = new THREE.Raycaster(localVertex, directionVector);
Here is a working example:
http://jsfiddle.net/FLyaY/1/
As you can see, the planeMesh fits snugly on the sphere, kind of like a patch or a band-aid. :)
Hope this helps. Thanks for posting the question on three.js's github page - I wouldn't have seen it here. At first I thought it was a bug in THREE.Raycaster but in the end it was just user (mine) error. I learned a lot about collision code from working on this problem and I will be using it later down the line in my own 3D game projects. You can check out one of my games at: https://github.com/erichlof/SpacePong3D
Best of luck to you!
-Erich
Your ray start position is not good. Probably due to vertex coordinates being local to the plane. You start the raycast from inside the sphere so it never hits anything.
I changed the ray start position like this as a test and get 726 collisions:
var rayStart = new THREE.Vector3(0, 0, 500);
var ray = new THREE.Raycaster(rayStart, new THREE.Vector3(0, 0, -1));
Forked jsfiddle: http://jsfiddle.net/H5YSL/
I think you need to transform the vertex coordinates to world coordinates to get the position correctly. That should be easy to figure out from docs and examples.

Three.js - Rotation not respecting local orientation

I'm using a large array of objects built around a center point in a scene, and need to manipulate them all around their local axis. They are all facing the origin using a blank object and lookAt(), then I used this method to align the other axes correctly. Getting the initial rotation this way worked great, unfortunately when I try to rotate these objects on the fly with object.rotation.x = <amount>, it does not respect the local axis of the object.
The confusing part is, it's not even using the global axis, the axis it's using almost seems entirely arbitrary. I set up a JSFiddle to demonstrate this here. As you can see on line 129, looker.rotation.z works correctly, it rotates along the Z axis properly, but if it's changed to X or Y, it doesn't rotate along local or global axes. If anyone could demystify what is happening to cause this, that would be great.
What is happening is that you want to add some rotation to the current orientation, and setting the variable looker.rotation.z means other thing.
At the end, to calculate the rotation matrix of the looker, there will be something like (pseudocode: the functions are not these, but you get the idea):
this.matrix.multiply( makeXRotationMatrix(this.rotation.x) )
this.matrix.multiply( makeYRotationMatrix(this.rotation.y) )
this.matrix.multiply( makeZRotationMatrix(this.rotation.z) )
DrawGeometry(this.geom, this.matrix)
and composition of rotations are not intuitive. This is why it doesn't seem to follow any axis system.
If you want to apply a rotation in some axis to the existing matrix, it can be made with the functions rotateX (angle), rotateY (angle), rotateZ (angle), and rotateOnAxis (axis, angle). axis can be a THREE.Vector3.
Changing directly looker.rotation.z works because it is the nearest rotation to the geometry, and it will not be affected by the other rotations (remember that transformation matrices apply in inverse order, e.g. T*R*G is Rotating the Geometry, and then, Translating it).
Summary
In this case I suggest not to use the line:
looker.rotation.z += 0.05;
Use
looker.rotateZ (0.05);
or
looker.rotateX (0.05);
instead. Hope this helps :)

Categories