Free Direction Tunnel
Free Direction Tunnel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
by BlackAxe / KoLOr 1997
In the latest demos (in almost every demo from Assembly97) you see those
funny free-directional tunnels, namely tunnels where you can move how you
want and perform complex camera movements.
Many people in iRC asked me how to do such a tunnel, so instead of wasting
phone costs and explaining it online i decided to write this little tute.
In fact, this effect is kinda easy to do, but unlike normal, old, silly
tubes it doesn't work with those silly lookup tables (darn, I hate lookup
tables :-)), but in fact it's realtime raytraycing. Realtime Raytraycing??
Isn't that slow? No, there are some tricks to make it possible in realtime.
Well, let's start with a little introduction to raytraycing.
Origin + t*Direction
where Origin is the vector of the camera, and Direction a normalized direction
vector. t is a float that indicates a position on the ray. Now for shooting
a ray through a pixel, we do the following, if we consider the camera to be
at (0,0,-256)
Origin.x = 0;
Origin.y = 0;
Origin.z = -128;
void Vector::Normalize()
{
float len = sqrt(x*x + y*y + z*z);
x /= len;
y /= len;
z /= len;
}
Now you have your ray, and you need to check for intersections. For that, you
need to find t (of course, because you know the rest :-)). Then you have
Intersection = Origin + t*Direction
how funny :-)
[Intersection is a vector ofcourse]
a*t^2 + b*t + c = 0
where:
a = Direction.x^2 + Direction.y^2
b = 2*(Origin.x*Direction.x + Origin.y*Direction.y)
c = Origin.x^2 + Origin.y^2 - r^2
Now we need to solve this equation. From your math course you should now how
to solve quadratic equations:
we first have to calculate the discriminent delta
delta = b^2 - 4*a*c
Now if delta < 0, there are no real solutions, only complex ones, if this
case happens, there's no Intersection and we can draw a background colour.
If delta = 0, there's ONE intersection, that is calculated as follows
-b
t = -----
2*a
-b - sqrt(delta)
t1 = ----------------
2*a
-b + sqrt(delta)
t2 = ----------------
2*a
Now you have your intersection between the ray and the cylinder :-)
Intersection = Origin + t*Direction
One thing rests: we need to texturemap the tunnel. This is easy to, we just
apply cylindric mapping to the Intersection point.
we just do:
u = abs(Intersection.z)*0.2;
v = abs(atan2(Intersection.y, Intersection.x)*256/PI);
that's it :-) you can combine that with depth cue too, i.e. taking the Z into
account to get a shade-level, but i leave that to you.
That's already it. If you do that for each pixel, you get a nice tunnel :-)
float t,t1,t2;
// there are 2 solutions, get the nearest ... this case should never happen
t1 = (-b + sqrt(delta))/(2*a);
t2 = (-b - sqrt(delta))/(2*a);
t = min(t1, t2); // min here
// do the mapping
u = (int)(fabs(Intersection.z)*0.2);
v = (int)(fabs(atan2(Intersection.y, Intersection.x)*256/PI));
}
Again, i call that for 40x25 and interpolate between the (u,v) set.
As you can see, i used OOP massively, e.g for Vectors and Matrices.
OOP really helps you alot, you should try it.
If you take an 80x50 grid (4x4 interpolation) you might get better results, but
this works fine for me.
That's pretty much it, now go ahead and code yourself a killer-tunnel.
If you want to see this tunnel in action, get our Evoke97 demo (1st place)
the archive is called KWISSEN.ZIP and you should find it on cdrom.com.
6.) Greets
~~~~~~~~~~
Greets fly to (no order):
Tomh, Climax, Shiva, Fontex, Raytrayza, Noize, LordChaos, Red13, kb, DrYes,
Siriuz, Crest, Gaffer, Trickster, Houlq, Screamager, LoneWolf, Magic, Unreal,
Aap, Cirion, Kyp, Assign, and the rest i have forgotten in some way.