I have a problem. In Three.js, I want to rotate a sphere (Earth) around axis tilted by 23.5 degs. I found sphere.rotation.x, sphere.rotation.y and sphere.rotation.z, but when I combine them in the correct ratio, the sphere's rotation is quite weird - it has no permanent rotation axis. I think I need a function like sphere.rotation.vector(1,0,-1). Does anyone know how this function is called and how the correct syntax is?
Many thanks for answers!
You do not have to understand how Euler angles or quaternions work to do what you want. You can use
Object3D.rotateOnAxis( axis, angle );
Object3D.rotateOnWorldAxis( axis, angle );
Make sure axis is a unit vector (has length 1), and angle is in radians.
Object3D.rotateOnAxis( axis, angle ) rotates on an axis in object space.
Object3D.rotateOnWorldAxis( axis, angle ) rotates on an axis in world space.
three.js r.104
You need to use quaternions for this. This video explains what quaternions are and how they are used in 3D graphics.
You can construct a quaternion like this:
quaternion = new THREE.Quaternion().setFromAxisAngle( axisOfRotation, angleOfRotation );
Then you apply it to your object by:
object.rotation.set( new THREE.Euler().setFromQuaternion( quaternion ) );
You can also achieve this by using object hierarchies. For example, you can make an Object3D() instance and tilt it by 23.5 degs, then create a sphere (Earth) and add it to the tilted object. The sphere will then rotate around the tilted Y axis. Quaternions however, are the best tool for solving this.
var quaternion = new THREE.Quaternion();
var object = scene.getObjectByName('xxx');
function render(){
quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0).normalize(), 0.005);
object.position.applyQuaternion(quaternion);
}
three.js version is 86, see full example on codepen.
You can rotate your sphere using th 'ObjectControls' module for ThreeJS that allows you to rotate a single OBJECT (or a Group), and not the SCENE.
Include the libary:
then
var controls = new THREE.ObjectControls(camera, renderer.domElement, yourMesh);
You can find here a live demo here: https://albertopiras.github.io/threeJS-object-controls/
Here is the repo: https://github.com/albertopiras/threeJS-object-controls.
Hope this helps
Related
I'm trying to convert Go Pro gyro data to Three.js coordinates so that I can project the footage onto the inside of a sphere, rotate the sphere and have 3D stabilisation.
The camera is orientated as such, and the order of the coordinates is Z,X,Y
I'm attempting to apply this vector to rotate the sphere, something like this
this._nextVec3.set(this._next[0],this._next[1],this._next[2])
this.el.object3D.rotation.setFromVector3(this._nextVec3)
But I can't get the rotation to match the rotation of the camera, and I assume it's something to do with the left/right hand configuration?
Can anyone help?
First of all, make sure you specify the correct rotation.order attribute. Since you said it's ZXY, then it should be a simple
this.el.object3D.rotation.order = "ZXY";
Secondly, check out the Three.js axes, taken from the editor:
As you can see, the WebGL axes are different than the GoPro. I think you'll have to flip the X-axis, and swap the Z and Y. So maybe something like:
let xRot = this._next[0];
let yRot = this._next[1];
let zRot = this._next[2];
this.el.object3D.rotation.set(-xRot, zRot, yRot);
I am trying to get a 3D object to follow a 3D path so that it always faces the direction in which it is traveling. I try to do this by doing:
fishObject.quaternion.setFromAxisAngle(axis, radians)
where radians is the angle between an up vector and the direction of travel
In the following pen, the axes are depicted for clarity. The blue line is the axis, the purple one is just up, and the moving red line is the direction the fish should be facing (tangent). They all move in the right way, but when I set the quaternion, the rotation of the object does not seem to follow its axis
There is a bit of clutter in the pen (to build the fish), but all I am looking at is line 281 and its arguments:
fishObject.quaternion.setFromAxisAngle(axis, radians)
I am just new to this. Should be simple to someone familiar with 3D rotation.
https://codepen.io/nth-chile/pen/ELQqqb
Thanks, and please let me know if I can be more clear.
One way to get a tangent frame that is well-behaved is use the lookAt() method.
var axes = new THREE.AxesHelper( 10 );
scene.add( axes );
. . .
// then, in the render loop
pt = swimPath.spline.getPoint( t );
tangent = swimPath.spline.getTangent( t );
axes.position.copy( pt );
axes.lookAt( pt.add( tangent ) );
Now, make sure your "fish" is oriented so it faces the local positive-z axis by default. It is not, in your case, so you will have to apply a rotation. Add the object as a child of the tangent frame.
fishObject.rotation.set( 0, - Math.PI / 2, 0 );
axes.add( fishObject );
three.js r.92
I'm trying to rotate a mesh loaded into an Object3D using OBJMTLLoader.
var obj = new THREE.Object3D();
// loading and stuff
obj.rotation.y += 0.1; //inside the update function
This works as it should, but only for y and z axes. Using the same code, but for the x axis yields the same result as rotating it around the z axis, but clockwise instead of counterclockwise.
Unfortunately, I need to rotate it around the x axis.
var xAxis = new THREE.Vector3(1,0,0);
obj.rotateOnAxis( xAxis, 0.1 );
This does rotate the object around the x axis.
However, I want to tween the rotation of the object, so I need a way to explicitly change the angle an object is rotated by, instead of rotating it for a specific amount.
Any ideas why obj.rotation.y and obj.rotation.z work properly, but obj.rotation.x doesn't?
Upon loading the mesh (before trying to rotate it around the x axis), I rotated it by 90 degrees around the y axis. Because of the default Euler order (which is XYZ), the local axes no longer corresponded to the world axes.
obj.eulerOrder = 'YXZ';
Using the above line of code before rotating the mesh around the y axis solved the problem.
A pretty good explanation of Euler order can be found here.
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.
Well, the title pretty much states it. I want to be able to draw a curve on a surface in Web GL. So for example, I'd like to draw a parabola on the surface of a sphere.
x = cos(theta)sin(phi); y = sin(theta)sin(phi); z = cos(phi).
If you make theta = theta(t) and phi = phi(t), you can draw curves on the surface.
I guess lines on shapes is what I need. Anyone know if that's possible in Web GL?
A parabola is the set of point of the plane that have the same distance from a line and a point (called focus). The point here is what do you mean by "line" on a sphere. Remember that a parabola extends to infinity, bu you can't do that on a sphere, unless you define some particular metric on it.
Anyway, you gave use a parametrization of the sphere, in terms on theta and phi. That's good. If you want to define a curve on the surface, you should have a bind between theta and phi, for example
phi = theta ^ 2
would draw something that could be defined as a "parabola" in some way, i.e. the projection on the sphere, given by the parametrization, of its representation on a plane.
Are you looking for help with how to do this in WebGL? In this case, take a look at this example
http://dl.dropbox.com/u/17612367/OpenGL%20to%20WebGL/example%202.3.1%20-%20line%20graph/code/index.html
you would basically load the positions into a vector and draw it using drawArrays with LINELOOP or something... See this cheatsheet for arguments or google the drawArrays function for more info:
http://www.nihilogic.dk/labs/webgl_cheat_sheet/WebGL_Cheat_Sheet.pdf
Good Luck!