Three Js How to copy Object direction that it's facing - javascript

I'm currently making a 3d space fighter game for my school project, but I encounter a problem when I want to spawn a projectile according to my ship front face or direction it's facing.
I do find a way to spawn projectile according direction we are facing using vector in the following example
http://www.isaacsukin.com/news/2012/06/how-build-first-person-shooter-browser-threejs-and-webglhtml5-canvas
but I still does'nt undestand how this vector work. Can someone explain to me ?

I understand it is more an linear algebra question than programming. First you must fully understand, what Vector is, and what isn't.
Often mistake is, that a Vector is some coordinate in 3D space (x,y,z). This is no true and this thinking will not allow understand, how to correctly work with vectors in space and let's you ask questions like this one.
https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces
https://www.khanacademy.org/math/linear-algebra/vectors-and-spaces/vectors/v/vector-introduction-linear-algebra
If you need only to copy object rotation, you can use obj2.rotation.set(obj1.rotation.x,obj1.rotation.y,obj1.rotation.z)
If you want so put something to the space object facing, you can use object as parent:
var my_vect = new THREE.Object3D(); // create vector
obj1.add(my_vect); // add to your object
obj1.rotation.set(1,2,3); // rotate object
my_vect.position.translateX(1); // move vector 1 unit before the object
obj1.localToWorld( my_vect.position); // get global coords from local coords
actually my_vect.position.x,my_vect.position.y,my_vect.position.z are the numbers in your scene before the object respecting object orientation.

Related

three.js lookAt() : how to point some local axis which *isn't* the positive Z axis towards another object

I'm creating an app where a person (right now I'm using a cone-shape) is standing on some surface (right now I'm using a cylinder laid lengthwise) and I'd like their feet to orient toward some point (right now it's the center of the cylinder).
(edit: I just realized that my Z axis in this photo is pointing in the wrong direction; it should be pointing towards the camera, but the question remains unchanged.)
Here is a version of the code similar to what I'm trying to accomplish. https://codepen.io/liamcorbett/pen/YMWayJ (Use arrow keys to move the cone)
//...
person = CreatePerson();
person.mesh.up = new THREE.Vector3(0, 0, 1);
//
// ...
//
function updateObj(obj, aboutObj=false){
let mesh = obj.mesh;
if (aboutObj) {
mesh.lookAt(
aboutObj.mesh.position.x,
aboutObj.mesh.position.y,
mesh.position.z)
};
}
//
// ...
//
function animate() {
// ...
updateObj(person);
// ...
}
The code above gives me something similar to what I'm looking for, but the issue is that lookAt() seems to always point the local Positive Z-axis in some direction, and I'd much prefer that it point the local Negative Y-axis instead.
I'd prefer to not change the x,y,z axes of the model itself, as I feel that's going to be a pain to deal with when I'm applying other logic to the person object.
Is there a way to change which axis lookAt() uses? Or am I going to have to roll my own lookAt() function? Thanks ~
Is there a way to change which axis lookAt() uses?
No, the default local forward vector for 3D objects (excluding cameras) is (0, 0, 1). Unlike other engines, three.js does not allow to configure the forward vector, only the up vector. But this is not really helpful in your case.
You can try to transform the geometry in order to achieve a similar effect.
If you don't want to do this for some reasons and you still want to use Object3D.lookAt(), you have to compute a different target vector (so not the cylinder's center).
Even if the forward vector of the lookAt method can't be changed (as #Mugen87 said), you can still adjust the local rotation afterwards by knowing in advance the difference between the forward Z axis used, and the axis you consider your mesh to be "upward" (ex: a person standing up on the Y axis).
Basically, in your case, just add this line after the lookAt method :
mesh.rotateOnAxis( new THREE.Vector3(1,0,0), Math.PI * -0.5 );
And the cone will look up :)

Simulate an infinite number of objects

On this example we can move inside a field of spheres but into certain limits. I want to be able to move infinitely among them. How can I do that ?
The trick is to reuse the spheres that are behind the camera and put them in front of it. Look at how it is done in this example. Here the programmer knows that the user will continue in the same direction so he removes the trees that come at a certain position.
If you use something like the example you quoted, you cannot know which direction the user will take. And so, you can use the same trick, but have to code it an other way. The most obvious is to check the distances with all the spheres regularly, if the user moves. If one sphere is too far behind the camera, you mirror it so it faces the camera, behind the fog.
'Regularly' can mean two things depending on your real number of spheres in your scene :
If you have a small scene and few spheres you can check those distances in your render loop. Neither cheap nor useful, 60 per seconds, but that can be the first coding step
Then the best way would be to use a web worker : you send the positions of the camera and those of the spheres, you let the worker compute all the stuff in its thread, and send instructions back : 'move those spheres to those positions'. Every seconds is more reasonable in the threejs example, but up to you to decide that depending on your scene.
NOTE : if you have a lot of spheres, or any meshes you use instead, like more than 20-30, having a mesh for each of them will slower performances. With few trees on the examples i linked it is ok, but with more objects and/or a heavier scene,
think about merging them all in a single geometry. You can check which sphere is where by deducing from the vertices indices, or adding an attribute that defines each sphere.
this will also impact the worker delay : it will have more to compute so it will need more time.
NOTE 2 : Note 1 would of course delete the level of details that the example aims to illustrate :) (Unless you also implement your own while checking the distances of the spheres....)
If you want to have an illusion of infinite world then you could:
Break your world space into regions (for example cubes).
Detect which region you are currently in.
Make sure you have objects (spheres) in neighbour regions. If some of regions are empty - fix it.
Clear regions which are not needed anymore.
For this you might want to have some class like this:
Class Region {
bool isEmpty = true;
Vector3 center;
float radius; // or 'range'
Array<Sphere> = null; // storage of your objects
// constructors / destructor
generateObjects(params); // perlin noise might be helpful there
removeObjects();
}
and do something like this periodically:
void updateRegions() {
computeClosestGridCoord(myPosition); // which is center of your current region
lookForNeighbourRegions(regionsArray); // and add new Region if needed
deleteOldRegionsStuff(regionsArray);
}

Three.JS: Get position of rotated object

In Three.JS, I am capable of rotating an object about its origin. If I were to do this with a line, for instance, the line rotates, but the positions of its vertices are not updated with their new locations. Is there some way to apply the rotation matrix to the position of the vertices to find the new position of the point? Say I rotate a line with points at (0,0,0) and (0,100,100) by 45° on the x, 20° on the y, and 100° on the z. How would I go about finding the actual position of the vertices with respect to the entire scene.
Thanks
yes, 'entire scene' means world position.
THREE.Vector3() has a applyMatrix4() method,
you can do the same things that the shader does so in order to project a vertex into world space you would do this
yourPoint.applyMatrix4(yourObject.matrixWorld);
to project that into camera space you can apply this next
yourPoint.applyMatrix4(camera.matrixWorld);
to get an actual screen position in -1 to 1
yourPoint.applyMatrix4(camera.projectionMatrix);
you would access your point like this
var yourPoint = yourObject.geometry.vertices[0]; //first vertex
also, rather than doing this three times, you can just combine the matrices. Didnt test this, but something along the lines of this. Might go the other way:
var neededPVMmatrix = new THREE.Matrix4().multiplyMatrices(yourObject.matrixWorld, camera.matrixWorld);
neededPVMmatrix.multiplyMatrices(neededPVMmatrix, camera.projectionMatrix);
if you need a good tutorial on what this does under the hood i recommend this
Alteredq posted everything there is to know about three.js matrices here
edit
One thing to note though, if you want just the rotation, not the translation, you need to use the upper 3x3 portion which is the rotation matrix, of the models world matrix. This might be slightly more complicated. I forgot what three.js gives you, but i think the normalMatrix would do the trick, or perhaps you can convert your THREE.Vector3() to THREE.Vector4(), and set .w to 0, this will prevent any translation from being applied.
edit2
if you want to move the line point in your example, instead of applying it to the particle, apply it to
var yourVertexWorldPosition = new THREE.Vector3().clone(geo.vertices[1]); //this is your second line point, to whatever you set it in your init function
yourVertexWorldPosition.applyMatrix4();//this transforms the new vector into world space based on the matrix you provide (line.matrixWorld)

Merging an entire Object3D/Mesh hierarchy together

I am working on a project that is dynamically generating trees. It's currently only in an early prototype stages, and so the branches and leaves are just simple cubes. The tree is made up of a hierarchy of the cubes, nested with the rotations and scaling down of the branches. I need to be able to add more branches/leaves to the tree, but can convert it to a static tree just for rendering purposes.
I am running into a problem when the tree gets too large, rendering many cubes slowing the program down.
After doing a lot of research, I discovered the THREE.GeometryUtils.merge() function, that would merge all the branches in my tree into one object that can be rendered/transformed much faster than before. However the problem I am encountering is the merge doesn't take into account all of the parent transforms, merging only it's vertices.
The basic code I am trying to get working is as follows. I have played around with applying the matrix to the geometry and a few other things, but have not got anything working properly yet.
var newGeo = new THREE.Geometry();
var newTree = tree.clone(); //Clones the tree so the original does not get altered
newTree.traverse(function(child){
if(child.parent){
child.applyMatrix( child.parent.matrixWorld);
}
THREE.GeometryUtils.merge(newGeo, child);
});
I have created a simple jsFiddle program for it:
http://jsfiddle.net/JeYhF/2/
The left object is 4 meshes parented inside each other and the right object is the mesh combination. As you can see, each component of the combination has its own transforms applied (translation in y axis by 11 units and rotation in z axis by PI/4), but they are not affected by the parent transforms.
The function in question is the MergeTree() function. This program would only work in chrome for me.
Any advice for how to solve this problem would be very much appreciated.
Thanks
The problem was the matrix world was not calculated before the merging. So the transforms were all just the identity matrix.
newTree.traverse(function(child){
if(child.parent){
child.updateMatrixWorld();
child.applyMatrix(child.parent.matrixWorld);
}
THREE.GeometryUtils.merge(newGeo, child);
});

three.js Object3D local location, versus global location

So originally I wanted my little 'ship' to have turrets that track a target. This is the jfiddle for it. http://jsfiddle.net/czGZF/2/ When they track, they act odd. I noticed that it thinks that the turret is slighly next to it (at the origin), by this peice of code.
turret_a.position.y = .25;
turret_a.position.z = 2;
However, I had done that so it could be a relative position for when i called (below) to add it to the 'base ship'
ship = new THREE.Object3D();
ship.add( ship_base );
ship.add( turret_a ) ;
When i changed the position of turret_a after it had been added to the ship, and after the ship was added to the scene, the turret tracked mostly how i wanted it to look.
I guess my question is, Why is the lookAt() function using its old location of that, and not the location of where it currently is on its parent object to determine the rotation angles that it needs to be at?
If you look at the code for Object3D.lookA(), you will see
// This routine does not support objects with rotated and/or translated parent(s)
Your code works if the parent ship is located at the origin and is not rotated.
Updated fiddle: http://jsfiddle.net/czGZF/4/
three.js r.59
From the API, the lookAt() method for Camera objects is defined to use world position, as you've discovered. This seems to be relatively common way to handle things.
I'm not that familiar with the three.js API in particular, but it appears that if you want to get the global position of ball, you can use the following:
var targetPos = ball.position.clone();
ball.localToWorld(targetPos);
Hopefully that gets you closer to your goal. Unfortunately, the fiddle you have seems to be (very) non-deterministic, so I can't quickly get a 100% solution for you.

Categories

Resources