PDA

View Full Version : Raytracing steps



fire.tiger
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 )
end
end

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
end

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.
ivan

jdarling
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 :)

Nitrogen
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;
begin
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
begin
Hit := true;
HitPrim := LRI[TraceDepth].LastPrim;
ChangeIndicator := HitPrim+1;
end;

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

LRI[TraceDepth].LastPrim := HitPrim;

if Hit then
begin
R := TRay.Create;

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

for I := 0 to NumLights-1 do
begin


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
begin
Shad := 0;
ChangeIndicator := ChangeIndicator + NumPrims;
end
else
for J := 0 to NumPrims-1 do
if J <> HitPrim then
begin
//if Prim[I].BBIntersect(R) then
if Prim[J].Intersect(R, TempD) <> 0 then
begin
Shad := 0;
ChangeIndicator := ChangeIndicator + NumPrims;
LRI[TraceDepth].LastShad[I] := J;
Break;
end;
end;

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

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

end;

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

end;


if Prim[HitPrim].Mat.Reflect > 0 then //Reflection
begin
// 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),
VecMult(Prim[HitPrim].Mat.Diffuse,Prim[HitPrim].Mat.Reflect)));

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

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
begin
TempCol := Makevector(0,0,0);

For I := -1 to 1 do
for J := -1 to 1 do
begin
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);

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

C := VecAdd(C,
VecMult(TempCol, //Raytrace(R, TraceDepth+1, TempHit, TempCh),
VecMult(Mat[Prim[HitPrim].Mat].Diffuse,Mat[Prim[HitPrim].Mat].Reflect)));

end
else
begin
}
Result := C;
end;

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

http://www.nitrogen.za.org/gallery/raytrace.png

jdarling
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 :)

chronozphere
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??

fire.tiger
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 :)

fire.tiger
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 :

http://sweb.cz/SOUThavirov/shot1.JPG

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

NecroDOME
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)

fire.tiger
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..

Nitrogen
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.

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

http://www.q4rt.de/

http://www.theinquirer.net/default.aspx?article=36452

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

Nitrogen
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
begin
For SubX := -1 to 1 do
for SubY := -1 to 1 do
if (SubX <> 0) or (SubY <> 0) then //Already sampled the center point.
begin
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



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

end
else
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.

Nitrogen
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.

http://www.nitrogen.za.org/gallery/raytrace1.png

Heres that scene again without the blue:

http://www.nitrogen.za.org/gallery/raytrace2.png

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

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

Nitrogen
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.

fire.tiger
17-02-2007, 07:54 AM
nothing special in my render :-) Just simple test like this :
http://sweb.cz/SOUThavirov/shotx.JPG

It will be looong way until my render will be able to do something like this :-)
http://www.cgtutorials.com/oneadmin/_files/linksdir/628_Creating_an_interior_scene.jpg

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

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

fire.tiger
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...

fire.tiger
17-02-2007, 09:40 AM
I implemented full antialiasing support :
http://sweb.cz/SOUThavirov/shota.JPG

Nitrogen
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..

fire.tiger
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 :)

Nitrogen
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..

fire.tiger
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 :

http://sweb.cz/SOUThavirov/shotra.JPG


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.