Archive: 3D dinamic movements


23rd November 2002 21:35 UTC

3D dinamic movements
I finaly decided to try and learn how to make 'reall' 3D dynamic movements.
This is my very first try:
init:
sp=0.1

frame:

kx=kx+tx*sp;ky=ky+ty*sp;kz=kz+tz*sp;
sx=sin(kx);sy=sin(ky);sz=sin(kz);
cx=cos(kx);cy=cos(ky);cz=cos(kz);
kx2=kx2+tx2*sp;ky2=ky2+ty2*sp;kz2=kz2+tz2*sp;
sx2=sin(kx2);sy2=sin(ky2);sz2=sin(kz2);
cx2=cos(kx2);cy2=cos(ky2);cz2=cos(kz2);

beat:
tx=rand(201)/100-1;ty=rand(201)/100-1;tz=rand(201)/100-1;
tx2=rand(201)/100-1;ty2=rand(201)/100-1;tz2=rand(201)/100-1;

pixel:

x1=x;y1=y;z1=1;
y2=y1*cx-z1*sx;z2=y1*sx+z1*cx;
x2=z2*sy+x1*cy;z3=z2*cy-x1*sy;
x3=x2*cz-y2*sz;y3=y2*cz+x2*sz;

k1=above(x3,y3)*z3;
k2=above(y3,z3)*x3;
k3=above(z3,x3)*y3;
k=min(min(k1,k2),k3);
x1=if(equal(k,k1),x3,if(equal(k,k2),y3,z3));
y1=if(equal(k,k1),y3,if(equal(k,k2),z3,x3));
z1=if(equal(k,k1),z3,if(equal(k,k2),x3,y3));

y2=y1*cx2-z1*sx2;z2=y1*sx2+z1*cx2;
x2=z2*sy2+x1*cy2;z3=z2*cy2-x1*sy2;
x3=x2*cz2-y2*sz2;y3=y2*cz2+x2*sz2;
z=1/(1+z3/1.5);x=x*z;y=y*z;alpha=1/z

Based on looking at other peoples code and my expirience on coding 3D scopes I figured this is what I schould do:

1. Make a single plane move around in 3D.
2. Make some condition (k1,k2,k3,k) that will cutt this xy plane and make different parts of it be xy,yz or xz.
3. Rottate the whole thing in 3D.

Now I know did something wrong here becouse it looks like crap.
Could someone tell me where I had gone wrong? Could someone explain how to define condition so that xy,yz and xz planes are placed where I want them to be?


23rd November 2002 21:55 UTC

First, what you are doing is raytracing... for every point on the DM grid, you trace a line from the camera ******ds and see where it intersects with some piece of 3D geometry.
The situation is like this:


_-
_-|
_- | /¯¯¯\
eye*_...|..x obj ) x = intersection
-_ | \___/
-|
¯-
^
projection
plane

Imagine that the DM grid is in the projection plane, with the eye behind it. By connecting the eye with every point on the DM grid, you get a viewing 'pyramid' of rays. A ray is uniquely described by its point of origin, and a vector that points in the direction of the ray.

If the eye is at (0,0,0) and the projection plane is the plane z=1, then all the rays start at the origin, and have vector:
(x,y,1). For most raytracing calculations such as lighting, this vector has to be normalized (length=1), but we don't need that for regular 3D DMs.

We call the direction vector of the ray (dx,dy,dz). The origin is (ox,oy,oz). So the points on the ray can be written as (k*dx+ox, k*dy+oy, k*dz+oz) where k is a real number. To find the intersection point of the ray with an object, you fill in these coordinates in the equation of the shape, and then solve for 'k'. Then you fill in 'k' in your ray equation to get the intersection point's coordinates.

Now, to achieve rotation, we simply rotate the viewing pyramid around the eye. This gives you realistic camera behaviour, because the objects in the world don't move, only the camera. Note that you need different order of rotations: first around the z-axis, then x-axis, then y-axis. To visualise why, follow the following movements... it's easiest if you're sitting on a rotating chair:
- look straight forward
- Z: tilt your head sideways (as if reading a smiley)
- X: look up while tilted
- Y: now rotate yourself left/right (easy on a rotating chair)

This is the only correct way because we're rotating around the worlds X,Y,Z axes and not local X,Y,Z axes. For example if we were to first rotate left 90° (Y), the world's X would lie in front of us.

Now we will raytrace the plane x+y = 1

We fill in general expression for a point on the ray and isolate 'k':

x + y = 1
<=> k*dx+ox + k*dy+oy = 1
<=> (dx + dy)*k = 1 - ox - oy
<=> k = 1 - ox - oy*
dx + dy

Now we have the intersection point at:
(k*dx+ox, k*dy+oy, k*dz+oz)

You can calculate the texture coordinates (x,y) from these. Note that, because only the camera moves, not the object, you never have to adjust your calculated coordinates.

23rd November 2002 22:31 UTC

Nice, UCD, can I use that post in my AVS resources pack?


23rd November 2002 23:55 UTC

Thanx a lot Unconed that was really helpfull :)
Ok so to see if I understood all of this:
(ox,oy,oz) are the coordinates of the camera and the starting points for the rays.
(dx,dy,dz) define the ray vector (something like numbers next to i and j in my 2D highschool vector math) and are used to define the object.
Than I just rotate the camera, calculate k and (x,y,z) by the given formulas and project that to 2D. :)


24th November 2002 20:50 UTC

Cool I did it. :)
Now all I need to know is how to make 2 or more planes cut each other at some angle and how to make some parts of planes seethrough and some not and I can make some cerious 3D presets. :)


25th November 2002 01:27 UTC

In order to have several shapes, you can either have multiple DM's and blend them together, or if your objects are solid, you can calculate multiple k's and use some function on them (usually the smallest positive 'k').

You can use alpha to make parts transparent or dark (fog).


25th November 2002 04:57 UTC

Major milestone: I actually get it now and have used it successfully! :) w00t! To celebrate, I'll show the preset in which I used it (it's the sequel to Hall of Sound from NDD2). Not bad, eh?


25th November 2002 05:22 UTC

Oh there's one thing I forgot to mention... the calculation can result in a negative 'k', which means the intersection point lies behind the camera. You should usually discard these points, unless they are what you need.

For example, if you raytrace the plane x=1 with the camera at (0,0,0), you will get an imaginary plane x=-1. However, if the camera moves closer to the real plane, the imaginary plane will come closer too.


_ _ _ _ _ _ x _ _ _ _ _ _ _ _ _ _ imaginary plane
/
/
/
eye *
. \
. \
_. \_ real plane
¯¯¯¯x¯¯¯¯¯¯¯x¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯




By the way uNDefineD: your code is slightly incorrect... you have:

x=x1/(1+z1); y=y1/(1+z1);

This is wrong, because your intersection points (x1,y1) are already your texture coordinates. Of course in this case, because you are raytracing the plane z=1, you're just doing x=x1/2;y=y1/2. You don't need to do any perspective projecting, just use some kind of mapping (planar, spherical, cylindrical) to texture your object.

25th November 2002 05:40 UTC

Negative values for k are only used with refraction and reflection, where imaginary images and real images can form simultaneously.

Undefined:
Instead of


dx1=x;dy1=y;dz1=1;
dx2=dx1; dy2=dy1*xs+dz1*xc; dz2=dy1*xc-dz1*xs;
dx3=dx2*ys+dz2*yc; dy3=dy2; dz3=dx2*yc-dz2*ys;
dx4=dx3*zs+dy3*zc; dy4=dx3*zc-dy3*zs; dz4=dz3;


use


dx=x;dy=y;dz=1;
tdy=dy*xs+dz*xc; tdz=dy*xc-dz*xs;
tdx=dx*ys+tdz*yc; dz=dx*yc-tdz*ys;
dx=tdx*zs+tdy*zc; dy=tdx*zc-tdy*zs;


It's cleaner and only uses 3 extra variables for the matrix.

25th November 2002 06:31 UTC

Taken on board. Thanks Zev. :)

UC: Sorry but would you mind telling me what the hell that means?


25th November 2002 07:19 UTC

I feel so ignored :cry: ;)


25th November 2002 11:17 UTC

Weeee.. I made a road crossing 3D dm. It was done before but I made it this time and I like it. :)
Is there a way to blend the adges? I tried whith alpha=if(bor(bor(equal(k1,k2),equal(k2,k3)),equal(k1,k3)),0,alpha); but it didnt work..


25th November 2002 12:37 UTC

nixa: Unfortunately, you can't do that using alpha, in fact you'll be hard pressed to do it at all. You can either do it using an SSC setup (if complexity permits), or you just deal with it. Personally I learn to ignore it, because it's not like you're always staring at the edges. (I, for example, usually find myself staring at the code and saying to myself, "How the hell does he do it..." :)) EDIT: You could set the grid size to say, 128x128, but it's out of the question unless it's on a bloody good system.

BTW, the second example was really great. I found that you can get interesting effects by switching max() and min() around in the k= statement.


25th November 2002 16:54 UTC

Yeah, my experience with BOR is that it's a shitty excuse for a shitty excuse for a function. For every frame, once BOR is satisfyed ONCE, it returns 1 for the rest of the frame....

BTW, if you're wondering why I feel so ignored (which you should be, but you're not...I feel so ignored :cry: ), UnConeD, can I use that post in my AVS resources pack?


25th November 2002 19:20 UTC

I thought of this during my geography class today and its a resoult of me not being interested about south american climate. Replace the alpha blend in dm of raytracing 2 preset whith it.

a1=min(max(2/sqrt(x*x+y*y),0),1);
a2=below(abs(k1/k2-1),0.1)+below(abs(k2/k3-1),0.1)+below(abs(k3/k1-1),0.1);
alpha=if(a2,0,a1);

Anyway this does blend the edges but the problem is that it also blends the ones that dont show. I am sure someone could think of a way to go around that..


25th November 2002 22:14 UTC

UC, don't worry, I think I've got it figured out. The intersection points are (x1,y1) and the texture coords are whatever goes into x= and y=, right? So since I'm not raytracing multiple values for k, all I need is the IPs, not an if() statement. So here's the updated version, along with a dynamic origin point.


26th November 2002 04:55 UTC

The most effective method I can think of, is to track the last point's texture co-ords and see if the current point's co-ords are more than (some certain threshold, like 2) units away, if they are, alpha blend the point out. This should help 'hide' ugly edges. Also, another method is to use a projection texture mapping system, ask UnConeD how to do this :D:D he seems proficient in doing that ;).


26th November 2002 16:23 UTC

Atero: I didn't reply because you already know the answer :P


26th November 2002 17:57 UTC

Well, I just don't feel comfortable using someone elses material without asking them...one of those things I REALLY hate when people do it to me. Which is why I asked :)


20th January 2003 23:44 UTC

(this is some stuff I just wrote up for nixa, I guess I might as well post it here for everyone... the attachment shows the situation).

The goal here is to create a sphere with a tunnel in it. Or mathematically, a sphere with a cylinder subtracted from it.


The equation for a sphere around the origin is:

x^2 + y^2 + z^2 = R^2

with R being the radius

To raytrace, we replace each component x,y,z with the equation for the ray (k*dx+ox,k*dy+oy,k*dz+oz):

(k*dx+ox)^2 + (k*dy+oy)^2 + (k*dz+oz)^2 = R^2

Now you work out the brackets and separate everything by 'k':

(dx^2 + dy^2 + dz^2)*k^2 + 2*(dx*ox+dy*oy+dz*oz)*k + (ox^2 + oy^2 + oz^2 - R^2) = 0

This is a quadratic (second power) equation in 'k', which we can write shorthard as:

ak^2 + bk + c = 0

We know from math that the solution can be found from the discriminant:
D = b^2 - 4*a*c

so that:

k = (-b - sqrt(D)) / (2*a)
k = (-b + sqrt(D)) / (2*a)


Because this is a quadratic equation, there are two solutions.
This is logical, because when you draw a line through a sphere, it has to intersect in two points, or none (or two identical points when it's tangent).
In the second case, 'd' will be negative, so its squareroot will not exist. This means that the ray does not intersect the sphere (this is only possible if we are outside the sphere).
The best approach is to use sqrt(abs(d)) and set alpha to 0 when d < 0. This results in the least amount of ugly edges around the sphere.

Once you've found 'k', you can find the intersection point from one of the k's:

px = k*dx + ox;
py = k*dy + oy;
pz = k*dz + oz;

(px,py,pz)

Depending on which k you choose, you will have the point at the back or at the front of the sphere.

To find the correct (x,y) pair to map onto the sphere, you can use:


x = atan2(pz,px)/(2*pi); (pi is 3.1415...)
y = asin(py/R)*2/pi; (R is the radius of the sphere)


Things to note:
- The sphere is always around the origin, it is only the camera/ray that moves
- If the camera is inside the sphere, one of the k's will be negative (behind the camera) and should not be used

------------

Now to make your tunnel, here's how I would do it...

Because the sphere and cylinder (tunnel) have front and backsides, a simple k=min(k1,k2) won't do (where k1 and k2 are the k's found by raytracing the sphere and cylinder).

So I suggest you raytrace the sphere first and calculate the px,pz coordinates of the intersection point (the cylinder lies on the y-axis). You then check sqrt(sqr(px)+sqr(pz)). If it it smaller than the radius of the cylinder, you re-raytrace this point, but with the cylinder equation.
The idea is like taking an apple and removing the hard center (which you don't eat) without cutting it into pieces.

Finally, you will need to make sure the tunnel is only as long as the sphere:

 
. . <- if the points on the sphere lie within this cylinder, retrace them
|-----|
. .
_. ._ ___________
/ | | \ |
/ | | \ |
| | | | |
| | | | |
\ | | / | if the resulting cylinder point is outside
\_| |_/ ___________| the sphere (check the y coordinate), then you set alpha to 0.
. .
. .
. .
. .


Attachment shows:
1) the situation as it is (no combinations)
2) min operation on k1,k2
3) max operation on k1,k2
--
4) raytracing a sphere
5) retracing only the points inside the cylinder's volume (notice the rightmost red point has shifted into the shaft, now in the correct position)

20th January 2003 23:57 UTC

Very good explanation UnConeD. I actually somewhat understand the process now. One small mistake though. A ray can go through none, one, or two points on the sphere. It will only go through one point when the ray is tangent to the sphere. This isn't a special case, though, because the two points that you find out will just be the same.


21st January 2003 01:20 UTC

anub: thanks, I updated it (and fixed a typo)... I knew about d == 0, but I didn't include it because it doesn't matter much in AVS anyway.


22nd January 2003 20:48 UTC

I tried to make the tunnel inside a sphere preset acording to Unconeds instructions but had some problems. I figured out how to make a cylinder and a sphere whith same ox,oy,oz and how to make them viseable at all time (see sphere or tunnel preset) but i had problems whith intersection. I limited and inverted(it schould show the inner side) the cylinder in 2nd preset.


22nd January 2003 23:56 UTC

I fixed the problem, it was just a typo. I used k variable before it was calculated. Silly me :)


23rd January 2003 00:29 UTC

that sucks. I hate when I do something stupid like that. It can take forever figuring it out too.