Basically, I'm trying to do 3D projection on a 2D canvas with simulation of depth. As a general rule, bodies that are further away are "shaded" more and smaller than bodies that are closer to the viewer. The only thing missing is having bodies that are further away always drawn behind bodies that are closer.
Sometimes, bodies that are further away are drawn behind closer bodies, but there are always small bodies that get drawn in front of larger ones, meaning that the ones that are further away sometimes appear in front of bodies that are supposed to be closer.
I try to solve it by sorting the bodies by the z-position. The bodies array is an array of objects with 0 containing an array of the body's position, 0 being x, 1 being y, 2 being z. I first have the position of the bodies updated according to rotations in the x, y, and z axes, stored into the np value of the body object, then do the sorting, and draw the bodies. I've tried changing how the array is sorted, changing the order of the loop, but still no cigar.
Just wondering if anyone can point me in the right direction to get this 3D "engine" behaving correctly. Any help is appreciated. Some quick notes: Rotations along the three axes are accomplished using the Q/A, W/S, and E/D keys, zooming in and out of the z-axis is accomplished using the R/F keys, and the default rotation about the z-axis can be accomplished using the P key. What I'm trying to do is located here:
http://jsbin.com/aholu/5/
You're sorting on the original xyz values instead of the transformed np values. I got it to look right by switching...
bodies.sort(function(a,b) {return a[0][2]-b[0][2]});
to
bodies.sort(function(a,b) {return a.np[1]-b.np[1]});
with change see http://home.comcast.net/~trochoid/mod5.html
I don't follow all of your code so this may not be a total solution. Specifically, I thought it'd be sorted on np[2] for the transformed z value, but np[1] gives correct looking results. I guess maybe you switch these coords. Also, it looks like you're transforming and projecting the z value and the code fix above sorts on this projected z value. It seems to work out ok but I've never projected the z value itself, just use the transformed z to project xy. Anyways, Looks good!
Trochoid. I had to access from a different computer and still haven't registered, so I have to add this as an answer instead of a comment.
If you notice, the axis of rotation for x and y are rotated when you rotate any other axis (eg. if you press W to rotate, then rotate a different axis, then press W again, you will notice that the helix in your code rotates the same way). T
his is not so with the z axis. No matter how you rotate the x and y axes, the z axis will always rotate "right-to-left" (eg. in default configuration, helix is spiraling along z-axis, or axis rotated using the E/D keys, but if you rotate the helix along any other axis, rotating using the E/D keys no longer spirals the helix).
I don't know why the behavior would be different in that axis, so I would like your assistance to get that rotation working properly. Thank you.
I am aware that this is not answering the original question, but depending on what you are trying to acchieve in general be aware that there is also 'parallax scrolling' (example) (esp. in CSS3 (example).
Related
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 :)
i'm using Three.js (without shaders, only with existing objects methods) in order to realize animations, but my question is very simple : i'm sure it's possible, but can you tell me (or help me) how should i combine several animations on a shape ? For example, rotating and translating a sphere.
When i'm doing :
three.sphere.rotation.y += 0.1;
three.sphere.translateZ += 1;
the sphere rotates but the translation vector is also rotating, so the translation has no effect.
I know a bit openGL and i already have used glPushMatrix and glPopMatrix functions, so do them exist in this framework ?
Cheers
Each three.js object3D has a position, rotation and scale; the rotation (always relative to its origin or "center") defines its own local axis coordinates (say, what the object sees as its own "front,up, right" directions) and when you call translateZ, the object is moved according to those local directions (not along the world -or parent- Z axis). If you want the later, do three.sphere.position.z += 1 instead.
The order of transformation is important. You get a different result if you translate first and then rotate than if you rotate first and then translate. Of course with a sphere it will be hard to see the rotation.
I'm new to three.js and 3d programming in general, so this may seem like a very simple question. Ideally, I hope the answer can help me understand the underlying principles.
I have an object that needs to "point" at another point (the origin, in this case, for simplicity), which can be done easily with the Object3D.lookAt(point) function. This points the Z axis of the object at the point nicely.
I also want to rotate my object, called looker, around its Z axis such that its X axis points generally towards another object, refObj. I know that the X axis can't point directly at the refObj unless that object happens form a right angle with the origin. I want the X axis of looker to lie on the plane created by origin, refObj and looker, as diagramed below:
The simplest way of doing the rotation would seem to be to modify looker.rotation.z, but I don't know how to calculate what the value should be.
In general, I would like an extended version of the lookAt function which takes a second coordinate to which the X axis would be oriented. Something like this:
function lookAtAndOrient(objectToAdjust, pointToLookAt, pointToOrientXTowards)
{
// First we look at the pointToLookAt
objectToAdjust.lookAt(pointToLookAt);
// Then we rotate the object
objectToAdjust.rotation.z = ??;
}
I have created a jsFiddle with the example diagramed above
What you are really saying is you want the y-axis of the object (the object's up-vector) to be orthogonal to the plane.
All you have to do is set the object's up-vector before you call lookAt( origin ).
You compute the desired up vector by taking a cross-product of two vectors you know lie in the plane.
three.js r.143
UPDATE: I found this enormously helpful article explaining canvas per-pixel collision detection.
I'm working on a collision system for a javascript game using HTML5 canvas. Each object has an image as a sprite and when a non-transparent pixel of any one object overlaps another, the collision code is triggered. But before anything else the objects need to be moved so that they are just touching each other and no longer triggering a collision. I need help calculating the overlap of any two objects in terms of x and y in order to move one accordingly. Here's what we know:
The coordinates of the collision point relative to each object
The positions of the objects (and therefore the distance between them)
The width and height of the objects
The velocity of the objects in the x and y directions (a vector)
Another note: the images for these objects are uneven shapes, no perfect circles, but the radius from the center to the collision point can be calculated.
EDIT: I haven't seen a lot of response, so I'll be more specific. In the image below, two objects are colliding. The overlap area is in red. How would you go about finding the lengths of the green lines?
I'm honestly clueless about HTML 5 and how you can make games in pure HTML 5. But you would also need to know a velocity (IE, their direction. This way you can send them backwards from where they came)
If it was in a standard programming language, one method would be to use a while loop (moving the sprite back until the collision == false). Another method would be a more complicated calculation of how far the intersection is and subtract individual x and y values so they are not collided.
EDIT:
Then the easiest way is like I said, to put the object thats moving in a while loop that moves it backwards 1 pixel in each axis until its collision tests false. Example:
int x1 = 500; //x location on screen
int y2 = 500; //y location
public boolean fixOffSetX(Sprite s) {
int x2 = s.getX();
int y2 = s.getY();
//not writing the whole thing
//enter a while loop until its not colliding anymore
while(collision is still true) {
x--; or x++;
//depending on direction
//(which is why you need to know velocity/direction of your sprites)
//do the same for the Y axis.
}
}
//This method will return if the 2 sprites collided, you do this one
public boolean collisionTest(Sprite s1, Sprite s2) {}
You should look at doing very basic collisions, since it is a VERY complicated part of programming
If this is still an issue, I've found information about the subject in an e-book called Foundation Game Design with HTML5 en Javascript. Here: link to relevant pages. Hope this helps anyone in the future.
I'm trying to wrap my head around using the Separating Axis Theorem in JavaScript to detect two squares colliding (one rotated, one not). As hard as I try, I can't figure out what this would look like in JavaScript, nor can I find any JavaScript examples. Please help, an explanation with plain numbers or JavaScript code would be most useful.
Update: After researching lots of geometry and math theories I've decided to roll out a simplified SAT implementation in a GitHub repo. You can find a working copy of SAT in JavaScript here: https://github.com/ashblue/canvas-sat
Transforming polygons
First you have to transform all points of your convex polygons (squares in this case) so they are all in the same space, by applying a rotation of angle.
For future support of scaling, translation, etc. I recommend doing this through matrix transforms. You'll have to code your own Matrix class or find some library that has this functionality already (I'm sure there are plenty of options).
Then you'll use code in the vain of:
var transform = new Matrix();
transform.appendRotation(alpha);
points = transform.transformPoints(points);
Where points is an array of Point objects or so.
Collision algorithm overview
So that's all before you get to any collision stuff. Regarding the collision algorithm, it's standard practice to try and separate 2 convex polygons (squares in your case) using the following steps:
For each polygon edge (edges of both polygon 0 and polygon 1):
Classify both polgyons as "in front", "spanning" or "behind" the edge.
If both polygons are on different sides (1 "in front" and 1 "behind"), there is no collision, and you can stop the algorithm (early exit).
If you get here, no edge was able to separate the polgyons: The polygons intersect/collide.
Note that conceptually, the "separating axis" is the axis perpendicular to the edge we're classifying the polygons with.
Classifying polygons with regards to an edge
In order to do this, we'll classify a polygon's points/vertices with regards to the edge. If all points are on one side, the polygon's on that side. Otherwise, the polygon's spanning the edge (partially on one side, partially on the other side).
To classify points, we first need to get the edge's normal:
// this code assumes p0 and p1 are instances of some Vector3D class
var p0 = edge[0]; // first point of edge
var p1 = edge[1]; // second point of edge
var v = p1.subtract(p0);
var normal = new Vector3D(0, 0, 1).crossProduct(v);
normal.normalize();
The above code uses the cross-product of the edge direction and the z-vector to get the normal. Ofcourse, you should pre-calculate this for each edge instead.
Note: The normal represents the separating axis from the SAT.
Next, we can classify an arbitrary point by first making it relative to the edge (subtracting an edge point), and using the dot-product with the normal:
// point is the point to classify as "in front" or "behind" the edge
var point = point.subtract(p0);
var distance = point.dotProduct(normal);
var inFront = distance >= 0;
Now, inFront is true if the point is in front or on the edge, and false otherwise.
Note that, when you loop over a polygon's points to classify the polygon, you can also exit early if you have at least 1 point in front and 1 behind, since then it's already determined that the polygon is spanning the edge (and not in front or behind).
So as you can see, you still have quite a bit of coding to do. Find some js library with Matrix and Vector3D classes or so and use that to implement the above. Represent your collision shapes (polygons) as sequences of Point and Edge instances.
Hopefully, this will get you started.