Tridora-CPU/examples/rtpair.pas
2024-09-19 14:10:33 +02:00

110 lines
2.5 KiB
ObjectPascal

{ Raytracer for a scene with a pair of spheres and multiple reflections }
program RtPair;
const MaxX = 639;
MaxY = 399;
HalfX = 320;
HalfY = 200;
var
gd, gm: Integer;
N, M: Integer;
X, Y, Z: Real;
U, V, W: Real;
I, E, F, P, D, T, R, G: Real;
stopReflection: Boolean;
C: Integer;
function Sign(x: Real): Real;
begin
if x>0 then
Sign := 1
else
Sign := -1;
end;
begin
InitGraphics;
SetPalette(0, $000);
SetPalette(4, $A00);
SetPalette(11, $0FF);
SetPalette(15, $FFF);
for N:=0 to MaxY do
for M:=0 to MaxX do
begin
{ Rays' origin point }
X := 0;
Y := -0.1;
Z := 3;
U := (M - 318) / HalfX;
V := (HalfY - N) / 321.34;
W := 1 / Sqrt(U*U + V*V + 1);
U := U*W;
V := V*W;
{ I is the horizontal direction of ray }
{ based on whether it is in left (U<0) or right (U>0) half of the screen }
I := Sign(U);
G := 1;
{ Start the reflection cycle. }
{ A ray may reflect between one sphere and another multiple times before hitting floor or sky. }
repeat
stopReflection := True;
E := X-I;
F := Y-I;
P := U*E + V*F - W*Z;
D := P*P - E*E - F*F - Z*Z + 1;
{ If ray reflects from a sphere one more time }
if D>0 then
begin
T := -P - Sqrt(D);
if T>0 then
begin
X := X + T*U;
Y := Y + T*V;
Z := Z - T*W;
E := X - I;
F := Y - I;
G := Z;
P := 2*(U*E + V*F - W*G);
U := U - P*E;
V := V - P*F;
W := W + P*G;
{ Invert ray's direction and continue the reflection cycle }
I := -I;
stopReflection := False;
end;
end;
until stopReflection;
{ If Y<0 (V<0) a ray hits the floor }
if V<0 then
begin
P := (Y+2)/V;
{ Select checkers floor with Black (0) and Red (4) tiles }
C := (1 And (Round(X - U*P) + Round(Z + W*P))) * 4;
end else begin
{ If Y>0 (V>0) a ray hits the sky }
{ Default sky color is Cyan (11) }
C := 11;
{ Condition for using color White (15) to create fancy Cyan-White horizon }
R := ArcTan(U/W);
R := 0.2+0.1*Cos(3*R)*Abs(Sin(5*R));
if Abs(G)<0.35 then
R := R + 1;
if V<R then
C := 15;
end;
{ Draw current pixel }
PutPixel(M, N, C);
end;
repeat until ConAvail;
end.