View Full Version : Raytracing steps

14-02-2007, 08:35 AM
Hi ,

I have done a simple raytracing engine in Delphi,
works well, until I have more than one light and set reflections
on. I think I have problem in steps order...

There is just for Each Pixel shot a ray
for x 0 to 640 do
for y 0 to 480 do
raytrace ( ray , aColor )

in Raytrace procedure is

for i 0 to LightsCount do begin
1. define shadow ray and shadow value (to variable called "shd")
2. diffuse shading (simply draw a pixel in intersection point of aColor * shd)
3. phong shading

4. reflection ( I find reflection vector and call recursively Raytrace procedure )

Is it right order ? find shadow / diffuse / phong / reflection / refractions etc.
When I have two lights, without reflection set ON, it's ok,
but when I have two lights, with reflections, reflections are not seen...

Is here anybody that has some experience with raytracing ?

thanks a lot.

14-02-2007, 02:11 PM
I don't have any raytracing experience what so ever, but your order looks a bit off to me. Not so much in the order you render, but how your doing it.

Seems you should calculate ALL light and shadow sources then render. Otherwise your 1st render of the light/shadow source gets removed when you render the 2nd light.

Of course, I could be way off, as I have little idea of what your actually doing :)

14-02-2007, 04:54 PM
Here is my raytrace function that I made a while ago, it handles multiple lights fine (sometimes theres some shadows messed up, but I think thats the optimisations that I've done.) *EDIT* yea, I found that the BBIntersect function is not working like it should in the shadow detection routine. I've modified the code below.

BTW: a warning to anyone posting code, it was mangling my code when I posted it using the [ pascal ] tags (leaving out lines and whole segments of code), only after lots of trial and error did I figure out that the < and > signs were interfering with the HTML rendering, disable HTML in this post to fix it.

Function Tscene.Raytrace(Ray: TRay;TraceDepth: integer; var HitPrim, ChangeIndicator: Integer): vector;
Var I, J, TempHit, TempCh: integer;
Dist, TempD, Dott: single;
R: TRay;
Pos, N: Vector;
Shad, Diff, Spec: single;
Hit: boolean;
C, L: vector;
Result := Makevector(0,0,0);
if TraceDepth > 5 then exit;

Dist := 1000000;
Hit := false;
HitPrim := -1;
ChangeIndicator := -1;
C := MakeVector(0,0,0);

if (LRI[Tracedepth].Lastprim > -1) and (Prim[LRI[TraceDepth].LastPrim].Intersect(Ray, Dist) <> 0) then
Hit := true;
HitPrim := LRI[TraceDepth].LastPrim;
ChangeIndicator := HitPrim+1;

For I := 0 to NumPrims-1 do
if I <> LRI[TraceDepth].LastPrim then
if Prim[I].BBIntersect(Ray) then
if (Prim[I].Intersect(Ray, Dist) <> 0) then
Hit := true;
HitPrim := I;
ChangeIndicator := I+1;

LRI[TraceDepth].LastPrim := HitPrim;

if Hit then
R := TRay.Create;

Pos := VecAdd(Ray.Pos, VecMult(Ray.Dir, Dist));

for I := 0 to NumLights-1 do

R.Dir := Normalise(VecSub(Light[I].Pos, Pos));
R.Pos := VecAdd(Pos, VecMult(R.Dir, 0.001));

Shad := 1;
TempD := Distance(VecSub(R.Pos, Light[I].Pos));

if (LRI[Tracedepth].LastShad[I] > -1) and (Prim[LRI[TraceDepth].LastShad[I]].Intersect(R, TempD) <> 0) then
Shad := 0;
ChangeIndicator := ChangeIndicator + NumPrims;
for J := 0 to NumPrims-1 do
if J <> HitPrim then
//if Prim[I].BBIntersect(R) then
if Prim[J].Intersect(R, TempD) <> 0 then
Shad := 0;
ChangeIndicator := ChangeIndicator + NumPrims;
LRI[TraceDepth].LastShad[I] := J;

if Shad > 0 then
N := Prim[HitPrim].GetNormal(Pos);
L := Normalise(VecSub(Light[I].Pos, Pos));

Dott := Dot(L, N); //Diffuse Shading
if Dott > 0 then
Diff := Shad*Dott*Prim[HitPrim].Mat.DiffPower;
C := VecAdd(C, VecMult(VecMult(Light[I].Color, Prim[HitPrim].Mat.Diffuse), Diff));


if Prim[HitPrim].Mat.Specular > 0 then //Specular Shading
Dott := Dot(Ray.Dir, VecSub(L, VecMult(N, (Dot(L, N)* 2) )));
if (Dott > 0) then
Spec := Power(Dott, 20) * Prim[HitPrim].Mat.Specular * Shad;
C := VecAdd(c, VecMult(Light[I].Color, Spec));


if Prim[HitPrim].Mat.Reflect > 0 then //Reflection
// Tr := TRay.Create;

N := Prim[HitPrim].GetNormal(Pos);
R.Dir := VecSub(Ray.Dir, VecMult(N, 2*Dot(Ray.Dir, N)));
R.Pos := VecAdd(Pos, Vecmult(R.Dir, 0.01));

C := VecAdd(C,
VecMult(Raytrace(R, TraceDepth+1, TempHit, TempCh),

HitPrim := TempHit;
ChangeIndicator := ChangeIndicator+TempCh;

If C[0] > 1 then C[0] := 1;
If C[1] > 1 then C[1] := 1;
If C[2] > 1 then C[2] := 1;

// Blurry Reflections - Tr.Pos := R.Pos;
// Tr.Dir := R.Dir;
{ if TraceDepth = 0 then
TempCol := Makevector(0,0,0);

For I := -1 to 1 do
for J := -1 to 1 do
Tr.Dir[0] := I*0.01;
Tr.Dir[1] := J*0.01;
Tr.Dir[2] := 0;
Tr.Dir := VecAdd(Tr.Dir, R.Dir);

TempCol := VecAdd(RayTrace(TR, TraceDepth+1, TempHit, TempCh), TempCol);

TempCol := VecMult(TempCol, 1/9);

C := VecAdd(C,
VecMult(TempCol, //Raytrace(R, TraceDepth+1, TempHit, TempCh),

Result := C;

14-02-2007, 05:28 PM
Some results:


14-02-2007, 06:49 PM
Hey Nitrogen, any chance you would post up a simple sample application showing this off. As I said, I've never played with ray tracing, but I'd love to see code around it :)

14-02-2007, 09:24 PM
eh that looks very cool :wink:

How long did it take to generate that image?? and what are your specs??

15-02-2007, 07:08 AM
Thanks Nitrogen. I guess it's based on tutorial that is on flipcode.
Looks very good.

How have you made antialiased result ?? I haven't done antialiasing yet :)

15-02-2007, 08:31 AM
I got it...finally, thanks to Nitro again. I noticed that I had a bug because I didn't Add vector of previous color and color after raytracing in the reflection block of code :-) thaanx 8) This was just stupid misstake.

Here is simple picture of my raytracer :


render time : 3 seconds,
2 lights in the scene. ground has reflection set on, both lights
are casting shadows.

15-02-2007, 08:49 AM
So.... in what part of a game could you use ray tracing? You don't want to render a frame in 3 seconds, but the results are great! Could raytracing be used for pre-calculated stuff? (lightmapping or something similar)

15-02-2007, 08:58 AM
I'm not going to do a game, just would like to do some software renderer.
I know that real-time raytracing is possible. I don't know algorithms for this, but somewhere I've seen real-time raytracing...
but for games is better to use lightmaps I think..

15-02-2007, 09:57 AM
Hey Nitrogen, any chance you would post up a simple sample application showing this off. As I said, I've never played with ray tracing, but I'd love to see code around it :)

Hey thanks! It's one of those projects that I didnt want to post up in it's original state because it's so inflexible and horribly stale... I had grand schemes for making it like a little 3D modeller with the 4 viewport business etc. But it never got past that point. Yea I used the Flipcode articles about it.. Really good tutorial that.

The image above took 3.2 seconds to render 640x480 on my AthlonX2 4200.

Yea, raytracing isnt that big of a visual difference from good pixel shaders (and the pixel shaders run a hundred times faster), but you can still use it for small apps like building webpage buttons or rendering logos etc.

15-02-2007, 09:58 AM
There is a realtime ray tracing version of quake.



15-02-2007, 01:10 PM
to Nitrogen >> Have you solved a sampling(antialiasing) in your raytracer ?

15-02-2007, 01:31 PM
Ray.Dir := Normalise(VecSub(Pos, cam.Origin));
Col:= Raytrace(Ray, 0 , HitPrim, Ch);
if (LastPrim <> Ch) or (LastPrims[Rx] <> Ch) then //If last hit primitive is different to this one
For SubX := -1 to 1 do
for SubY := -1 to 1 do
if (SubX <> 0) or (SubY <> 0) then //Already sampled the center point.
D := Pos;
D := VecAdd(D,VecMult(A, SubX*0.5));
D := VecAdd(D,VecMult(B, SubY*0.5)); //Adds a slight offset in 3D space
Ray.Dir := Normalise(VecSub(D, cam.Origin));
AccCol:= Raytrace(Ray, 0 , HitPrim, Ch);
Col := VecAdd(Col, AccCol); //Add subsample to accumulator color

P^ := Rgb(round(Col[0]*255/9), round(Col[1]*255/9), round(Col[2]*255/9)); //average all 9 subsamples.

P^ := Rgb(round(Col[0]*255), round(Col[1]*255), round(Col[2]*255));

Basically you just send off 9 rays for 1 pixel. Each with a slight offset.
The trick comes when you record the last hit primitive, because you dont need to antialias pixels inside primitives, only on the boundaries between primitives.

15-02-2007, 01:48 PM
The blue pixels are the only ones that are antialiased: Note how you must antialias both the primitive boundaries and the shadow boundaries.


Heres that scene again without the blue:


One problem with this approach is that you can only have an antialiased area of one pixel between primitives or shadows.

16-02-2007, 10:03 AM
thank you nitrogen again .

16-02-2007, 03:02 PM
Not a problem ;), post your results here for everyone to see.

Raytracing is one of the more beautiful aspects of programming.

17-02-2007, 07:54 AM
nothing special in my render :-) Just simple test like this :

It will be looong way until my render will be able to do something like this :-)

It is unbelievably what today renderer's like Maxwell render or VRay can do. Really amazing things.

17-02-2007, 08:54 AM
Can you do refraction yet?

17-02-2007, 09:02 AM
yes, I have implemented refraction algorithm, from what I see on the flipcode website, tere is raytracing tutorial...
however, I need to implement transparency to objects...
I think refraction is more visible when the object is little transparent...
I try to do some other things now, exactly improve the speed of rendering...

17-02-2007, 09:40 AM
I implemented full antialiasing support :

17-02-2007, 11:59 AM
Thats where I gave up :)

Spacial partitioning to speed up rendering. I think I went for an octtree, but it's one thing getting the structure setup, it's another getting a ray to traverse it..

17-02-2007, 12:48 PM
:-) nitrogen, how many seconds do you render the same scene with antialiasing, and without antialiasing ? Let's say the scene 512x384 .

I think it will be hard for me to implement kd-tree , but I must do this,
because I have imported a 3DS mesh, that contains only about 4 500 Triangles, and my raytracer is horribly sloow. Really, very slow :? :D

Also, have you tried the soft shadows ? I Plan to this, but really after
it get more speed :)

17-02-2007, 01:12 PM
AA takes quite a hit.

Takes 1.25 sec without
Takes 2.25 sec with AA.

I've tried it before but it tends to make your shadows look grainy if you use a random scatter, and if you use a uniform scatter it creates multiple layers of sharp shadows.. No good either way :(

Unless of course you fire 200 shadow rays for each pixel..

17-02-2007, 01:55 PM
Very good time results :) my Scene where is 53 objects takes about one minute with antialiasing...
terrible.I have to do something with that speed :) However here is the result :


I'll try to implement kd-tree optimisation, after that I'll tell how much the speed has increased . Then it's time to do soft shadows and area lights :)
Then diffuse reflections.