980 lines
No EOL
28 KiB
ObjectPascal
980 lines
No EOL
28 KiB
ObjectPascal
unit RayTr;
|
||
{ Everything-independent super ultra ray-tracing
|
||
by Brooke Vibber, 12-13-92, based on lots of stuff
|
||
last revised 12-25-92, unless I forget to change this line.
|
||
12-25-92: set for Floats
|
||
}
|
||
interface
|
||
|
||
{$N+}
|
||
|
||
uses Objects; { For TCollection, a super-useful thingy }
|
||
|
||
type
|
||
Float = Double;
|
||
const
|
||
MinReal = 5.0e-324;
|
||
MaxReal = 1.7e308;
|
||
|
||
type
|
||
PUniverse = ^TUniverse;
|
||
PObject3d = ^TObject3d;
|
||
PLightSource = ^TLightSource;
|
||
PPoint3d = ^TPoint3d;
|
||
PRayInfo = ^TRayInfo;
|
||
{PPolygon3d = ^TPolygon3d;}
|
||
{PPolygonList = ^TPolygonList;}
|
||
|
||
TPoint3d = object
|
||
x,y,z: Float;
|
||
procedure SetTo(ax,ay,az: Float);
|
||
procedure MakeUnit;
|
||
procedure Cross(v: TPoint3d);
|
||
function Dot(v: TPoint3d): Float;
|
||
procedure Add(v: TPoint3d);
|
||
procedure Sub(v: TPoint3d);
|
||
procedure Scale(s: Float);
|
||
function Length: Float;
|
||
procedure RotateFrom(v: TPoint3d);
|
||
procedure RotateTo(v: TPoint3d);
|
||
end;
|
||
TRay = record
|
||
case Integer of
|
||
0: (Origin, Direction: TPoint3d);
|
||
1: (o,d: TPoint3d); { Shorthand versions }
|
||
2: (a,b: TPoint3d); { " " " " }
|
||
end;
|
||
RgbTriple = record
|
||
r,g,b: Float; { 0 - 1 }
|
||
end;
|
||
TRayInfo = record
|
||
Hit: Boolean;
|
||
Time: Float;
|
||
GoingIn: Boolean;
|
||
Pos,Normal: TPoint3d;
|
||
Reflectivity,Opacity,Color: RgbTriple;
|
||
Brightness: Float; { 0 - 1 }
|
||
SpecularN,IndexRefraction: Float;
|
||
end;
|
||
|
||
TObject3d = object(TObject)
|
||
Owner: PUniverse;
|
||
procedure GetInfo(Ray: TRay; var Inf: TRayInfo); virtual;
|
||
function SpecularW(Angle: Float): Float; virtual;
|
||
end;
|
||
TLightSource = object(TObject)
|
||
Pos: TPoint3d;
|
||
Color: RgbTriple;
|
||
constructor Init(x,y,z,r,g,b: Float);
|
||
end;
|
||
|
||
TUniverse = object(TObject)
|
||
Shading,Shadows,Specular,Transparency,Reflection,ScaleBase: Boolean;
|
||
ScrWidth,ScrHeight: Integer;
|
||
Eye,Gaze,Up,vX,vY,vU,vV,vH,vM: TPoint3d;
|
||
DistScreen,AngleHoriz,AngleVert: Float; { Use degrees }
|
||
BackColor,Ambient: RgbTriple;
|
||
ReflectCount,MaxReflect: Integer;
|
||
Items,Lights: TCollection;
|
||
constructor Init(aScrWidth,aScrHeight,aMaxReflect: Integer;
|
||
anEyeX,anEyeY,anEyeZ,
|
||
aGazeX,aGazeY,aGazeZ,anUpX,anUpY,anUpZ,aDistScreen,
|
||
anAngleHoriz,anAngleVert,anAmbientR,anAmbientG,anAmbientB,
|
||
aBackR,aBackG,aBackB: Float);
|
||
destructor Done; virtual;
|
||
procedure TraceRay(Ray: TRay; var Col: RgbTriple);
|
||
procedure TracePoint(x,y: Integer; var Col: RgbTriple);
|
||
procedure Insert(Item: PObject3d);
|
||
procedure Delete(Item: PObject3d);
|
||
procedure InsertLight(Item: PLightSource);
|
||
procedure DeleteLight(Item: PLightSource);
|
||
procedure DeleteAllObjects;
|
||
procedure DeleteAllLights;
|
||
procedure DeleteAll;
|
||
procedure FreeAllObjects;
|
||
procedure FreeAllLights;
|
||
procedure FreeAll;
|
||
end;
|
||
|
||
PSphere = ^TSphere;
|
||
PPlane = ^TPlane;
|
||
PPlanePts = ^TPlanePts;
|
||
PCylinder = ^TCylinder;
|
||
PCone = ^TCone;
|
||
|
||
TSphere = object(TObject3d)
|
||
Pos: TPoint3d;
|
||
r,r2: Float;
|
||
constructor Init(xa,ya,za,ra: Float);
|
||
procedure GetInfo(Ray: TRay; var Inf: TRayInfo); virtual;
|
||
end;
|
||
TPlane = object(TObject3d)
|
||
Pos,Normal: TPoint3d;
|
||
constructor Init(xa,ya,za,vx,vy,vz: Float);
|
||
procedure GetInfo(Ray: TRay; var Inf: TRayInfo); virtual;
|
||
end;
|
||
TPlanePts = object(TPlane)
|
||
constructor Init(x1,y1,z1,x2,y2,z2,x3,y3,z3: Float);
|
||
end;
|
||
TCylinder = object(TObject3d)
|
||
Pos,Normal: TPoint3d;
|
||
r,r2,h: Float;
|
||
Ends: ShortInt; { 0 = no, 1 = bottom, 2 = top, 3 = both }
|
||
constructor Init(xa,ya,za,vx,vy,vz,ra,ha: Float; aends: ShortInt);
|
||
procedure GetInfo(Ray: TRay; var Inf: TRayInfo); virtual;
|
||
end;
|
||
TCone = object(TObject3d)
|
||
Pos,Normal: TPoint3d;
|
||
ra,rb,ra2,rb2,h,th: Float;
|
||
Ends: ShortInt; { 0 = no, 1 = bottom, 2 = top, 3 = both }
|
||
constructor Init(xa,ya,za,vx,vy,vz,ra1,rb1,ha: Float; aends: ShortInt);
|
||
procedure GetInfo(Ray: TRay; var Inf: TRayInfo); virtual;
|
||
end;
|
||
|
||
procedure GetSphereInfo(Ray: TRay; Pos: TPoint3d; r: Float; var close,farther: Float);
|
||
procedure GetCylinderInfo(Ray: TRay; Pos,Normal: TPoint3d; r,h: Float; ends: ShortInt;
|
||
var close,farther,end1,end2: Float);
|
||
procedure GetConeInfo(Ray: TRay; Pos,Normal: TPoint3d; ra,rb,h: Float; ends: ShortInt;
|
||
var close,farther,end1,end2: Float);
|
||
procedure GetPlaneInfo(Ray: TRay; Pos,Normal: TPoint3d; var time: Float);
|
||
|
||
procedure MakeTrip(r,g,b: Float; var c: RgbTriple);
|
||
function Power(x,y: Float): Float;
|
||
function Log(x,y: Float): Float;
|
||
function ArcSin(x: Float): Float;
|
||
function ArcCos(x: Float): Float;
|
||
function Tan(x: Float): Float;
|
||
|
||
implementation
|
||
|
||
procedure MakeTrip(r,g,b: Float; var c: RgbTriple);
|
||
begin
|
||
c.r := r; c.g := g; c.b := b;
|
||
end;
|
||
|
||
function Power(x,y: Float): Float;
|
||
var
|
||
i: Integer;
|
||
x1: Float;
|
||
begin
|
||
{Power := Exp(y * Ln(x));}
|
||
x1 := x;
|
||
for i := 1 to Trunc(y)-1 do
|
||
x1 := x1 * x;
|
||
Power := x;
|
||
end;
|
||
|
||
function Log(x,y: Float): Float;
|
||
begin
|
||
Log := Ln(x) / Ln(y);
|
||
end;
|
||
|
||
function ArcSin(x: Float): Float;
|
||
begin
|
||
ArcSin := ArcTan(x / Sqrt(1 - (x*x)));
|
||
end;
|
||
|
||
function ArcCos(x: Float): Float;
|
||
begin
|
||
ArcCos := ArcTan(Sqrt(1 - Sqr(x)) / x);
|
||
end;
|
||
|
||
function Tan(x: Float): Float;
|
||
begin
|
||
Tan := Sin(x) / Cos(x);
|
||
end;
|
||
|
||
procedure TPoint3d.SetTo(ax,ay,az: Float);
|
||
begin
|
||
x := ax; y := ay; z := az;
|
||
end;
|
||
|
||
procedure TPoint3d.MakeUnit;
|
||
var
|
||
d: Float;
|
||
begin
|
||
d := Sqrt(Sqr(x)+Sqr(y)+Sqr(z));
|
||
if d <> 0 then begin
|
||
x := x / d;
|
||
y := y / d;
|
||
z := z / d;
|
||
end;
|
||
end;
|
||
|
||
procedure TPoint3d.Cross(v: TPoint3d);
|
||
var
|
||
xa,ya: Float;
|
||
begin
|
||
xa := y*v.z - z*v.y;
|
||
ya := z*v.x - x*v.z;
|
||
z := x*v.y - y*v.x;
|
||
x := xa; y := ya;
|
||
end;
|
||
|
||
function TPoint3d.Dot(v: TPoint3d): Float;
|
||
begin
|
||
Dot := x*v.x + y*v.y + z*v.z;
|
||
end;
|
||
|
||
procedure TPoint3d.Add(v: TPoint3d);
|
||
begin
|
||
x := x + v.x;
|
||
y := y + v.y;
|
||
z := z + v.z;
|
||
end;
|
||
|
||
procedure TPoint3d.Sub(v: TPoint3d);
|
||
begin
|
||
x := x - v.x;
|
||
y := y - v.y;
|
||
z := z - v.z;
|
||
end;
|
||
|
||
procedure TPoint3d.Scale(s: Float);
|
||
begin
|
||
x := x * s;
|
||
y := y * s;
|
||
z := z * s;
|
||
end;
|
||
|
||
function TPoint3d.Length: Float;
|
||
begin
|
||
Length := Sqrt(Sqr(x)+Sqr(y)+Sqr(z));
|
||
end;
|
||
|
||
procedure TPoint3d.RotateFrom(v: TPoint3d);
|
||
var
|
||
d,xa,ya,za,cos1,sin1: Float;
|
||
begin
|
||
v.MakeUnit;
|
||
d := Sqrt(Sqr(v.y)+Sqr(v.z));
|
||
cos1 := v.z/d; sin1 := v.y/d;
|
||
ya := y*cos1-z*sin1; z := y*sin1+z*cos1; y := ya;
|
||
cos1 := d; sin1 := -v.x;
|
||
za := z*cos1-x*sin1; x := z*sin1+x*cos1; z := za;
|
||
end;
|
||
|
||
procedure TPoint3d.RotateTo(v: TPoint3d);
|
||
var
|
||
d,xa,ya,za,cos1,sin1: Float;
|
||
begin
|
||
v.MakeUnit;
|
||
d := Sqrt(Sqr(v.y)+Sqr(v.z));
|
||
cos1 := -v.z/d; sin1 := -v.y/d;
|
||
ya := y*cos1-z*sin1; z := y*sin1+z*cos1; y := ya;
|
||
cos1 := -d; sin1 := v.x;
|
||
za := z*cos1-x*sin1; x := z*sin1+x*cos1; z := za;
|
||
end;
|
||
|
||
|
||
procedure TObject3d.GetInfo(Ray: TRay; var Inf: TRayInfo);
|
||
begin
|
||
Inf.Hit := False;
|
||
end;
|
||
|
||
function TObject3d.SpecularW(Angle: Float): Float;
|
||
begin
|
||
SpecularW := Angle / 90;
|
||
end;
|
||
|
||
|
||
constructor TLightSource.Init(x,y,z,r,g,b: Float);
|
||
begin
|
||
TObject.Init;
|
||
Pos.x := x; Pos.y := y; Pos.z := z;
|
||
Color.r := r; Color.g := g; Color.b := b;
|
||
end;
|
||
|
||
constructor TUniverse.Init(aScrWidth,aScrHeight,aMaxReflect: Integer;
|
||
anEyeX,anEyeY,anEyeZ,
|
||
aGazeX,aGazeY,aGazeZ,anUpX,anUpY,anUpZ,aDistScreen,
|
||
anAngleHoriz,anAngleVert,anAmbientR,anAmbientG,anAmbientB,
|
||
aBackR,aBackG,aBackB: Float);
|
||
begin
|
||
TObject.Init;
|
||
Items.Init(5,5);
|
||
Lights.Init(5,5);
|
||
Shading := True; Shadows := True; Specular := True;
|
||
Transparency := True; Reflection := True; ScaleBase := False;
|
||
ScrWidth := aScrWidth; ScrHeight := aScrHeight;
|
||
MaxReflect := aMaxReflect;
|
||
Eye.x := anEyeX; Eye.y := anEyeY; Eye.z := anEyeZ;
|
||
Gaze.x := aGazeX; Gaze.y := aGazeY; Gaze.z := aGazeZ;
|
||
Up.x := anUpX; Up.y := anUpY; Up.z := anUpZ;
|
||
DistScreen := aDistScreen;
|
||
AngleHoriz := anAngleHoriz; AngleVert := anAngleVert;
|
||
Ambient.r := anAmbientR; Ambient.g := anAmbientG; Ambient.b := anAmbientB;
|
||
MakeTrip(aBackR,aBackG,aBackB,BackColor);
|
||
Gaze.MakeUnit;
|
||
Up.MakeUnit;
|
||
vX := Gaze; vX.Cross(Up); vX.MakeUnit;
|
||
vY := vX; vY.Cross(Gaze); vY.MakeUnit;
|
||
vM := Gaze; vM.Scale(DistScreen); vM.Add(Eye);
|
||
vH := vX; vH.Scale(DistScreen*Tan(AngleHoriz*pi/180));
|
||
vV := vY; vV.Scale(DistScreen*Tan(AngleVert*pi/180));
|
||
end;
|
||
|
||
destructor TUniverse.Done;
|
||
begin
|
||
Items.Done;
|
||
Lights.Done;
|
||
TObject.Done;
|
||
end;
|
||
|
||
procedure TUniverse.TraceRay(Ray: TRay; var Col: RgbTriple);
|
||
type
|
||
InfAr = array[0..(65520 div SizeOf(TRayInfo))-1] of TRayInfo;
|
||
var
|
||
Inf: ^InfAr;
|
||
Info: TRayInfo;
|
||
i,j,k,l: Integer;
|
||
c,lc: RgbTriple;
|
||
ra,Min,cosTheta,ir,ig,ib,d: Float;
|
||
ndotn, idotn, idotn_div_ndotn_x2: Float;
|
||
li,v1,v2: TPoint3d;
|
||
r: TRay;
|
||
begin
|
||
GetMem(Inf,Items.Count * SizeOf(TRayInfo));
|
||
Ray.d.MakeUnit;
|
||
for i := 0 to Items.Count-1 do
|
||
PObject3d(Items.At(i))^.GetInfo(Ray,Inf^[i]);
|
||
Min := MaxReal; j := -1;
|
||
for i := 0 to Items.Count-1 do
|
||
with Inf^[i] do
|
||
if Hit and (Time < Min) and (Time > 0.001) then begin
|
||
Min := Time; j := i;
|
||
end;
|
||
if j = -1 then begin
|
||
Col := BackColor
|
||
end else begin
|
||
Info := Inf^[j];
|
||
with Info do begin
|
||
Normal.MakeUnit;
|
||
c := Color;
|
||
if Shading then begin
|
||
ir := Brightness * Ambient.r;
|
||
ig := Brightness * Ambient.g;
|
||
ib := Brightness * Ambient.b;
|
||
for i := 0 to Lights.Count-1 do begin
|
||
li := PLightSource(Lights.At(i))^.Pos;
|
||
lc := PLightSource(Lights.At(i))^.Color;
|
||
Li.Sub(Pos);
|
||
with li do
|
||
d := Sqrt(Sqr(x)+Sqr(y)+Sqr(z));
|
||
li.MakeUnit;
|
||
costheta := (Normal.x*Li.x + Normal.y*Li.y + Normal.z*Li.z);
|
||
if Shadows then begin
|
||
r.Origin := Pos;
|
||
r.Direction := li;
|
||
repeat
|
||
for k := 0 to Items.Count-1 do
|
||
PObject3d(Items.At(k))^.GetInfo(r,Inf^[k]);
|
||
Min := MaxReal; l := -1;
|
||
for k := 0 to Items.Count-1 do
|
||
with Inf^[k] do
|
||
if Hit and (Time < Min) and (Time < d) and
|
||
(Time > 0.001) and ((Opacity.r+Opacity.g+Opacity.b) > 0)
|
||
then begin
|
||
Min := Time; l := k;
|
||
end;
|
||
if l <> -1 then
|
||
with Inf^[l] do begin
|
||
lc.r := lc.r * (1-Opacity.r);
|
||
lc.g := lc.g * (1-Opacity.g);
|
||
lc.b := lc.b * (1-Opacity.b);
|
||
r.o := Pos;
|
||
end;
|
||
until l = -1;
|
||
end;
|
||
if Specular and (costheta > 0) then begin
|
||
{ Don't bother if light is behind }
|
||
v1 := Ray.d;
|
||
ndotn := (normal.x * normal.x +
|
||
normal.y * normal.y +
|
||
normal.z * normal.z);
|
||
idotn := (normal.x * li.x +
|
||
normal.y * li.y +
|
||
normal.z * li.z);
|
||
idotn_div_ndotn_x2 := (2.0 * (idotn) / ndotn);
|
||
v2.x := li.x - idotn_div_ndotn_x2 * Normal.x;
|
||
v2.y := li.y - idotn_div_ndotn_x2 * Normal.y;
|
||
v2.z := li.z - idotn_div_ndotn_x2 * Normal.z;
|
||
v2.MakeUnit;
|
||
ra := v1.Dot(v2);
|
||
if ra > 0 then costheta := costheta + (
|
||
PObject3d(Items.At(j))^.SpecularW(ArcCos(costheta)*180/pi) *
|
||
Power(ra,SpecularN));
|
||
end;
|
||
if (costheta < 0) then begin
|
||
costheta := -costheta;
|
||
lc.r := lc.r * (1-Opacity.r);
|
||
lc.g := lc.g * (1-Opacity.g);
|
||
lc.b := lc.b * (1-Opacity.b);
|
||
end;
|
||
Ir := Ir + ((Brightness * lc.r) / (d + 0.001)) * costheta;
|
||
Ig := Ig + ((Brightness * lc.g) / (d + 0.001)) * costheta;
|
||
Ib := Ib + ((Brightness * lc.b) / (d + 0.001)) * costheta;
|
||
end;
|
||
c.r := c.r - 1 + Ir;
|
||
c.g := c.g - 1 + Ig;
|
||
c.b := c.b - 1 + Ib;
|
||
end;
|
||
if Reflection and (ReflectCount < MaxReflect) and
|
||
((Reflectivity.r+Reflectivity.g+Reflectivity.b) > 0) then begin
|
||
ndotn := (normal.x * normal.x +
|
||
normal.y * normal.y +
|
||
normal.z * normal.z);
|
||
idotn := (normal.x * ray.d.x +
|
||
normal.y * ray.d.y +
|
||
normal.z * ray.d.z);
|
||
idotn_div_ndotn_x2 := (2.0 * (idotn) / ndotn);
|
||
r.Origin := Pos;
|
||
r.d.x := Ray.d.x - idotn_div_ndotn_x2 * Normal.x;
|
||
r.d.y := Ray.d.y - idotn_div_ndotn_x2 * Normal.y;
|
||
r.d.z := Ray.d.z - idotn_div_ndotn_x2 * Normal.z;
|
||
Inc(ReflectCount);
|
||
TraceRay(r,lc);
|
||
Dec(ReflectCount);
|
||
if ScaleBase then begin
|
||
c.r := (c.r*(1-Reflectivity.r)) + (Reflectivity.r * lc.r);
|
||
c.g := (c.g*(1-Reflectivity.g)) + (Reflectivity.g * lc.g);
|
||
c.b := (c.b*(1-Reflectivity.b)) + (Reflectivity.b * lc.b);
|
||
end else begin
|
||
c.r := c.r + (Reflectivity.r * lc.r);
|
||
c.g := c.g + (Reflectivity.g * lc.g);
|
||
c.b := c.b + (Reflectivity.b * lc.b);
|
||
end;
|
||
end;
|
||
if Transparency and (ReflectCount < MaxReflect) and
|
||
(Opacity.r < 1) and (Opacity.g < 1) and (Opacity.b < 1) then begin
|
||
if GoingIn then
|
||
ra := 1 / IndexRefraction
|
||
else
|
||
ra := IndexRefraction;
|
||
idotn := -(Normal.x*Ray.d.x +
|
||
Normal.y*Ray.d.y +
|
||
Normal.z*Ray.d.z);
|
||
d := 1 + Sqr(ra)*(Sqr(idotn)-1);
|
||
r.o := Pos;
|
||
if d >= 0 then begin
|
||
Min := ra*idotn - Sqrt(d);
|
||
r.d.x := Ray.d.x*ra + Normal.x*Min;
|
||
r.d.y := Ray.d.y*ra + Normal.y*Min;
|
||
r.d.z := Ray.d.z*ra + Normal.z*Min;
|
||
end else begin
|
||
ndotn := (normal.x * normal.x +
|
||
normal.y * normal.y +
|
||
normal.z * normal.z);
|
||
idotn := (normal.x * ray.d.x +
|
||
normal.y * ray.d.y +
|
||
normal.z * ray.d.z);
|
||
idotn_div_ndotn_x2 := (2.0 * (idotn) / ndotn);
|
||
r.d.x := Ray.d.x - idotn_div_ndotn_x2 * Normal.x;
|
||
r.d.y := Ray.d.y - idotn_div_ndotn_x2 * Normal.y;
|
||
r.d.z := Ray.d.z - idotn_div_ndotn_x2 * Normal.z;
|
||
end;
|
||
Inc(ReflectCount);
|
||
TraceRay(r,lc);
|
||
Dec(ReflectCount);
|
||
if ScaleBase then begin
|
||
c.r := (c.r*Opacity.r) + ((1-Opacity.r) * lc.r);
|
||
c.g := (c.g*Opacity.g) + ((1-Opacity.g) * lc.g);
|
||
c.b := (c.b*Opacity.b) + ((1-Opacity.b) * lc.b);
|
||
end else begin
|
||
c.r := c.r + ((1-Opacity.r) * lc.r);
|
||
c.g := c.g + ((1-Opacity.g) * lc.g);
|
||
c.b := c.b + ((1-Opacity.b) * lc.b);
|
||
end;
|
||
end;
|
||
Col := c;
|
||
end;
|
||
end;
|
||
FreeMem(Inf,Items.Count * SizeOf(TRayInfo));
|
||
end;
|
||
|
||
procedure TUniverse.TracePoint(x,y: Integer; var Col: RgbTriple);
|
||
var
|
||
Ray: TRay;
|
||
v,h: TPoint3d;
|
||
begin
|
||
Ray.Origin := Eye;
|
||
Ray.d := vM; Ray.d.Sub(Eye);
|
||
h := vH; v := vV;
|
||
h.Scale(-(2*(x/ScrWidth)-1));
|
||
v.Scale(2*(y/ScrHeight)-1);
|
||
Ray.d.Add(h);
|
||
Ray.d.Add(v);
|
||
TraceRay(Ray,Col);
|
||
end;
|
||
|
||
procedure TUniverse.Insert(Item: PObject3d);
|
||
begin
|
||
Items.Insert(Item);
|
||
Item^.Owner := @Self;
|
||
end;
|
||
|
||
procedure TUniverse.Delete(Item: PObject3d);
|
||
begin
|
||
Items.Delete(Item);
|
||
Item^.Owner := nil;
|
||
end;
|
||
|
||
procedure TUniverse.InsertLight(Item: PLightSource);
|
||
begin
|
||
Lights.Insert(Item);
|
||
end;
|
||
|
||
procedure TUniverse.DeleteLight(Item: PLightSource);
|
||
begin
|
||
Lights.Delete(Item);
|
||
end;
|
||
|
||
procedure TUniverse.DeleteAllObjects;
|
||
var i: Integer;
|
||
begin
|
||
Items.DeleteAll;
|
||
end;
|
||
|
||
procedure TUniverse.DeleteAllLights;
|
||
begin
|
||
Lights.DeleteAll;
|
||
end;
|
||
|
||
procedure TUniverse.DeleteAll;
|
||
begin
|
||
Items.DeleteAll;
|
||
Lights.DeleteAll;
|
||
end;
|
||
|
||
procedure TUniverse.FreeAllObjects;
|
||
begin
|
||
Items.FreeAll;
|
||
end;
|
||
|
||
procedure TUniverse.FreeAllLights;
|
||
begin
|
||
Lights.FreeAll;
|
||
end;
|
||
|
||
procedure TUniverse.FreeAll;
|
||
begin
|
||
Items.FreeAll;
|
||
Lights.FreeAll;
|
||
end;
|
||
|
||
constructor TSphere.Init(xa,ya,za,ra: Float);
|
||
begin
|
||
TObject3d.Init;
|
||
Pos.SetTo(xa,ya,za);
|
||
r := ra; r2 := Sqr(ra);
|
||
end;
|
||
|
||
procedure TSphere.GetInfo(Ray: TRay; var Inf: TRayInfo);
|
||
var
|
||
a, b, c, t1, t2, t3, close, farther: Float;
|
||
begin
|
||
a := ray.d.x * ray.d.x + ray.d.y * ray.d.y + ray.d.z * ray.d.z;
|
||
close := -1.0;
|
||
farther := -1.0;
|
||
if a <> 0 then begin
|
||
b := 2.0 * ((ray.o.x - Pos.x) * ray.d.x
|
||
+ (ray.o.y - Pos.y) * ray.d.y
|
||
+ (ray.o.z - Pos.z) * ray.d.z);
|
||
c := (ray.o.x - Pos.x) * (ray.o.x - Pos.x)
|
||
+ (ray.o.y - Pos.y) * (ray.o.y - Pos.y)
|
||
+ (ray.o.z - Pos.z) * (ray.o.z - Pos.z) - r2;
|
||
t1 := b * b - 4.0 * a * c;
|
||
if t1 > 0 then begin
|
||
t2 := sqrt(t1);
|
||
t3 := 2.0 * a;
|
||
close := -(b + t2) / t3;
|
||
farther := -(b - t2) / t3;
|
||
end;
|
||
end;
|
||
if (close <= 0.001) and (farther > 0.001) then begin
|
||
Inf.Time := farther; Inf.GoingIn := False;
|
||
end else
|
||
if (close > 0.001) and (farther <= 0.001) then begin
|
||
Inf.Time := close; Inf.GoingIn := False;
|
||
end else begin
|
||
Inf.GoingIn := True;
|
||
if close < farther then
|
||
Inf.Time := close
|
||
else
|
||
Inf.Time := farther;
|
||
end;
|
||
Inf.Hit := (Inf.Time > 0.001);
|
||
if not Inf.Hit then Exit;
|
||
Inf.Pos.SetTo(
|
||
ray.o.x+ray.d.x*Inf.Time,
|
||
ray.o.y+ray.d.y*Inf.Time,
|
||
ray.o.z+ray.d.z*Inf.Time);
|
||
Inf.Normal := Inf.Pos;
|
||
Inf.Normal.Sub(Pos);
|
||
if not Inf.GoingIn then Inf.Normal.Scale(-1);
|
||
MakeTrip(0.9,0.8,0.7,Inf.Color);
|
||
Inf.Brightness := 1;
|
||
MakeTrip(0.3,0.3,0.3,Inf.Reflectivity);
|
||
MakeTrip(1,1,1,Inf.Opacity);
|
||
Inf.SpecularN := 100;
|
||
Inf.IndexRefraction := 0.95;
|
||
end;
|
||
|
||
constructor TPlane.Init(xa,ya,za,vx,vy,vz: Float);
|
||
begin
|
||
TObject3d.Init;
|
||
Pos.SetTo(xa,ya,za);
|
||
Normal.SetTo(vx,vy,vz);
|
||
Normal.MakeUnit;
|
||
end;
|
||
|
||
procedure TPlane.GetInfo(Ray: TRay; var Inf: TRayInfo);
|
||
var
|
||
p1, p2, p3: Float;
|
||
begin
|
||
p1 := Pos.x * Normal.x + Pos.y * Normal.y + Pos.z * Normal.z;
|
||
p2 := ray.o.x * Normal.x + ray.o.y * Normal.y + ray.o.z * Normal.z;
|
||
p3 := ray.d.x * Normal.x + ray.d.y * Normal.y + ray.d.z * Normal.z;
|
||
if p3 = 0 then p3 := 0.001;
|
||
Inf.Time := (p1-p2)/p3;
|
||
Inf.Hit := (Inf.Time > 0.001);
|
||
if not Inf.Hit then Exit;
|
||
Inf.Normal := Normal;
|
||
if Ray.d.Dot(Inf.Normal) > 0 then Inf.Normal.Scale(-1);
|
||
Inf.Pos.SetTo(
|
||
ray.o.x+ray.d.x*Inf.Time,
|
||
ray.o.y+ray.d.y*Inf.Time,
|
||
ray.o.z+ray.d.z*Inf.Time);
|
||
MakeTrip(0.75,0.75,0.75,Inf.Color);
|
||
Inf.GoingIn := True;
|
||
Inf.Brightness := 1;
|
||
MakeTrip(0.1,0.1,0.1,Inf.Reflectivity);
|
||
MakeTrip(1,1,1,Inf.Opacity);
|
||
Inf.SpecularN := 50;
|
||
Inf.IndexRefraction := 0.99;
|
||
end;
|
||
|
||
constructor TPlanePts.Init(x1,y1,z1,x2,y2,z2,x3,y3,z3: Float);
|
||
begin
|
||
TPlane.Init(x1,y1,z1,
|
||
y1*(z2-z3)+y2*(z3-z1)+y3*(z1-z2),
|
||
z1*(x2-x3)+z2*(x3-x1)+z3*(x1-x2),
|
||
x1*(y2-y3)+x2*(y3-y1)+x3*(y1-y2));
|
||
end;
|
||
|
||
constructor TCylinder.Init(xa,ya,za,vx,vy,vz,ra,ha: Float; aends: ShortInt);
|
||
begin
|
||
TObject3d.Init;
|
||
Pos.SetTo(xa,ya,za);
|
||
Normal.SetTo(vx,vy,vz);
|
||
Normal.MakeUnit;
|
||
r := ra; r2 := Sqr(ra);
|
||
h := ha;
|
||
ends := aends;
|
||
end;
|
||
|
||
procedure TCylinder.GetInfo(Ray: TRay; var Inf: TRayInfo);
|
||
var
|
||
r1: TRay;
|
||
a,b,c,t1,t2,t3,close1,farther1,close,farther,end1,end2: Float;
|
||
p1,p2: TPoint3d;
|
||
begin
|
||
Inf.Hit := False;
|
||
r1 := Ray;
|
||
r1.o.Sub(Pos);
|
||
r1.o.RotateFrom(Normal);
|
||
r1.d.RotateFrom(Normal);
|
||
if (ends and 1) <> 0 then begin
|
||
t3 := r1.d.z;
|
||
if t3 = 0 then t3 := 0.001;
|
||
end1 := (-r1.o.z)/t3;
|
||
if (Sqr(r1.o.x+r1.d.x*end1)+
|
||
Sqr(r1.o.y+r1.d.y*end1)+
|
||
Sqr(r1.o.z+r1.d.z*end1)) > r2 then end1 := -1;
|
||
end else
|
||
end1 := -1;
|
||
if (ends and 2) <> 0 then begin
|
||
t3 := r1.d.z;
|
||
if t3 = 0 then t3 := 0.001;
|
||
end2 := (h-r1.o.z)/t3;
|
||
if (Sqr(r1.o.x+r1.d.x*end2)+
|
||
Sqr(r1.o.y+r1.d.y*end2)+
|
||
Sqr(r1.o.z+r1.d.z*end2-h)) > r2 then end2 := -1;
|
||
end else
|
||
end2 := -1;
|
||
a := r1.d.x * r1.d.x + r1.d.y * r1.d.y;
|
||
close := -1.0;
|
||
farther := -1.0;
|
||
if a <> 0 then begin
|
||
b := 2.0 * (r1.o.x * r1.d.x
|
||
+ r1.o.y * r1.d.y);
|
||
c := r1.o.x * r1.o.x
|
||
+ r1.o.y * r1.o.y - r2;
|
||
t1 := b * b - 4.0 * a * c;
|
||
if t1 > 0 then begin
|
||
t2 := sqrt(t1);
|
||
t3 := 2.0 * a;
|
||
close1 := -(b + t2) / t3;
|
||
farther1 := -(b - t2) / t3;
|
||
if close1 > 0 then begin
|
||
p1 := r1.d;
|
||
p1.Scale(close1);
|
||
close := p1.Length;
|
||
p1.Add(r1.o);
|
||
if (p1.z < 0) or (p1.z > h) then close := -1;
|
||
end;
|
||
if farther1 > 0 then begin
|
||
p2 := r1.d;
|
||
p2.Scale(farther1);
|
||
farther := p2.Length;
|
||
p2.Add(r1.o);
|
||
if (p2.z < 0) or (p2.z > h) then farther := -1;
|
||
end;
|
||
end;
|
||
end;
|
||
Inf.Time := MaxReal;
|
||
if (close < Inf.Time) and (close > 0.001) then Inf.Time := close;
|
||
if (farther < Inf.Time) and (farther > 0.001) then Inf.Time := farther;
|
||
if (end1 < Inf.Time) and (end1 > 0.001) then Inf.Time := end1;
|
||
if (end2 < Inf.Time) and (end2 > 0.001) then Inf.Time := end2;
|
||
Inf.Hit := Inf.Time < MaxReal;
|
||
if not Inf.Hit then Exit;
|
||
Inf.Pos := Ray.d;
|
||
Inf.Pos.Scale(Inf.Time);
|
||
Inf.Pos.Add(Ray.o);
|
||
Inf.Normal := Normal;
|
||
if (Inf.Time = close) or (Inf.Time = farther) then begin
|
||
if Inf.Time = close then
|
||
Inf.Normal.Scale(p1.z)
|
||
else
|
||
Inf.Normal.Scale(p2.z);
|
||
Inf.Normal.Add(Pos);
|
||
Inf.Normal.Sub(Inf.Pos);
|
||
end else begin
|
||
if Inf.Time = end2 then Inf.Normal.Scale(-1);
|
||
end;
|
||
Inf.GoingIn := Ray.d.Dot(Inf.Normal) > 0;
|
||
if Inf.GoingIn then Inf.Normal.Scale(-1);
|
||
MakeTrip(0.7,0.8,0.9,Inf.Color);
|
||
Inf.Brightness := 1;
|
||
MakeTrip(0,0,0,Inf.Reflectivity);
|
||
MakeTrip(1,1,1,Inf.Opacity);
|
||
Inf.SpecularN := 100;
|
||
Inf.IndexRefraction := 0.95;
|
||
end;
|
||
|
||
constructor TCone.Init(xa,ya,za,vx,vy,vz,ra1,rb1,ha: Float; aends: ShortInt);
|
||
begin
|
||
TObject3d.Init;
|
||
Pos.SetTo(xa,ya,za);
|
||
Normal.SetTo(vx,vy,vz);
|
||
Normal.MakeUnit;
|
||
ra := ra1; ra2 := Sqr(ra);
|
||
rb := rb1; rb2 := Sqr(rb);
|
||
h := ha;
|
||
th := h+((rb*h)/(ra-rb));
|
||
ends := aends;
|
||
end;
|
||
|
||
procedure TCone.GetInfo(Ray: TRay; var Inf: TRayInfo);
|
||
var
|
||
r1: TRay;
|
||
v1,v2,a,b,c,t1,t2,t3,close1,farther1,close,farther,end1,end2: Float;
|
||
p1,p2: TPoint3d;
|
||
begin
|
||
Inf.Hit := False;
|
||
r1 := Ray;
|
||
r1.o.Sub(Pos);
|
||
r1.o.RotateFrom(Normal);
|
||
r1.d.RotateFrom(Normal);
|
||
if (ends and 1) <> 0 then begin
|
||
t3 := r1.d.z;
|
||
if t3 = 0 then t3 := 0.001;
|
||
end1 := (-r1.o.z)/t3;
|
||
if (Sqr(r1.o.x+r1.d.x*end1)+
|
||
Sqr(r1.o.y+r1.d.y*end1)+
|
||
Sqr(r1.o.z+r1.d.z*end1)) > ra2 then end1 := -1;
|
||
end else
|
||
end1 := -1;
|
||
if (ends and 2) <> 0 then begin
|
||
t3 := r1.d.z;
|
||
if t3 = 0 then t3 := 0.001;
|
||
end2 := (h-r1.o.z)/t3;
|
||
if (Sqr(r1.o.x+r1.d.x*end2)+
|
||
Sqr(r1.o.y+r1.d.y*end2)+
|
||
Sqr(r1.o.z+r1.d.z*end2-h)) > rb2 then end2 := -1;
|
||
end else
|
||
end2 := -1;
|
||
a := r1.d.x * r1.d.x + r1.d.y * r1.d.y;
|
||
(*
|
||
x<>+y<>=(1-(z/th))r<>
|
||
take (1-(z/th))*ra2 and use as r2 in cyl stuff
|
||
*)
|
||
{ get p1.z, p2.z }
|
||
v1 := (1-(p1.z/th))*ra2;
|
||
v2 := (1-(p2.z/th))*ra2;
|
||
a := r1.d.x * r1.d.x + r1.d.y * r1.d.y;
|
||
close := -1.0;
|
||
farther := -1.0;
|
||
if a <> 0 then begin
|
||
b := 2.0 * (r1.o.x * r1.d.x
|
||
+ r1.o.y * r1.d.y);
|
||
c := r1.o.x * r1.o.x
|
||
+ r1.o.y * r1.o.y - ra2;
|
||
t1 := b * b - 4.0 * a * c;
|
||
if t1 > 0 then begin
|
||
t2 := sqrt(t1);
|
||
t3 := 2.0 * a;
|
||
close1 := -(b + t2) / t3;
|
||
farther1 := -(b - t2) / t3;
|
||
if close1 > 0 then begin
|
||
p1 := r1.d;
|
||
p1.Scale(close1);
|
||
close := p1.Length;
|
||
p1.Add(r1.o);
|
||
if (p1.z < 0) or (p1.z > h) then close := -1;
|
||
end;
|
||
if farther1 > 0 then begin
|
||
p2 := r1.d;
|
||
p2.Scale(farther1);
|
||
farther := p2.Length;
|
||
p2.Add(r1.o);
|
||
if (p2.z < 0) or (p2.z > h) then farther := -1;
|
||
end;
|
||
end;
|
||
end;
|
||
Inf.Time := MaxReal;
|
||
if (close < Inf.Time) and (close > 0.001) then Inf.Time := close;
|
||
if (farther < Inf.Time) and (farther > 0.001) then Inf.Time := farther;
|
||
if (end1 < Inf.Time) and (end1 > 0.001) then Inf.Time := end1;
|
||
if (end2 < Inf.Time) and (end2 > 0.001) then Inf.Time := end2;
|
||
Inf.Hit := Inf.Time < MaxReal;
|
||
if not Inf.Hit then Exit;
|
||
Inf.Pos := Ray.d;
|
||
Inf.Pos.Scale(Inf.Time);
|
||
Inf.Pos.Add(Ray.o);
|
||
Inf.Normal := Normal;
|
||
if (Inf.Time = close) or (Inf.Time = farther) then begin
|
||
if Inf.Time = close then
|
||
Inf.Normal.Scale(p1.z)
|
||
else
|
||
Inf.Normal.Scale(p2.z);
|
||
Inf.Normal.Add(Pos);
|
||
Inf.Normal.Sub(Inf.Pos);
|
||
end else begin
|
||
if Inf.Time = end2 then Inf.Normal.Scale(-1);
|
||
end;
|
||
Inf.GoingIn := Ray.d.Dot(Inf.Normal) > 0;
|
||
if Inf.GoingIn then Inf.Normal.Scale(-1);
|
||
MakeTrip(0.7,0.8,0.9,Inf.Color);
|
||
Inf.Brightness := 1;
|
||
MakeTrip(0,0,0,Inf.Reflectivity);
|
||
MakeTrip(1,1,1,Inf.Opacity);
|
||
Inf.SpecularN := 100;
|
||
Inf.IndexRefraction := 0.95;
|
||
end;
|
||
|
||
procedure GetSphereInfo(Ray: TRay; Pos: TPoint3d; r: Float; var close,farther: Float);
|
||
var
|
||
r2, a, b, c, t1, t2, t3: Float;
|
||
begin
|
||
r2 := Sqr(r);
|
||
a := ray.d.x * ray.d.x + ray.d.y * ray.d.y + ray.d.z * ray.d.z;
|
||
close := -1.0;
|
||
farther := -1.0;
|
||
if a <> 0 then begin
|
||
b := 2.0 * ((ray.o.x - Pos.x) * ray.d.x
|
||
+ (ray.o.y - Pos.y) * ray.d.y
|
||
+ (ray.o.z - Pos.z) * ray.d.z);
|
||
c := (ray.o.x - Pos.x) * (ray.o.x - Pos.x)
|
||
+ (ray.o.y - Pos.y) * (ray.o.y - Pos.y)
|
||
+ (ray.o.z - Pos.z) * (ray.o.z - Pos.z) - r2;
|
||
t1 := b * b - 4.0 * a * c;
|
||
if t1 > 0 then begin
|
||
t2 := sqrt(t1);
|
||
t3 := 2.0 * a;
|
||
close := -(b + t2) / t3;
|
||
farther := -(b - t2) / t3;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure GetCylinderInfo(Ray: TRay; Pos,Normal: TPoint3d; r,h: Float; ends: ShortInt;
|
||
var close,farther,end1,end2: Float);
|
||
var
|
||
r1: TRay;
|
||
r2,a,b,c,t1,t2,t3,close1,farther1: Float;
|
||
p1,p2: TPoint3d;
|
||
begin
|
||
r2 := Sqr(r);
|
||
r1 := Ray;
|
||
r1.o.Sub(Pos);
|
||
r1.o.RotateFrom(Normal);
|
||
r1.d.RotateFrom(Normal);
|
||
if (ends and 1) <> 0 then begin
|
||
t3 := r1.d.z;
|
||
if t3 = 0 then t3 := 0.001;
|
||
end1 := (-r1.o.z)/t3;
|
||
if (Sqr(r1.o.x+r1.d.x*end1)+
|
||
Sqr(r1.o.y+r1.d.y*end1)+
|
||
Sqr(r1.o.z+r1.d.z*end1)) > r2 then end1 := -1;
|
||
end else
|
||
end1 := -1;
|
||
if (ends and 2) <> 0 then begin
|
||
t3 := r1.d.z;
|
||
if t3 = 0 then t3 := 0.001;
|
||
end2 := (h-r1.o.z)/t3;
|
||
if (Sqr(r1.o.x+r1.d.x*end2)+
|
||
Sqr(r1.o.y+r1.d.y*end2)+
|
||
Sqr(r1.o.z+r1.d.z*end2-h)) > r2 then end2 := -1;
|
||
end else
|
||
end2 := -1;
|
||
a := r1.d.x * r1.d.x + r1.d.y * r1.d.y;
|
||
close := -1.0;
|
||
farther := -1.0;
|
||
if a <> 0 then begin
|
||
b := 2.0 * (r1.o.x * r1.d.x
|
||
+ r1.o.y * r1.d.y);
|
||
c := r1.o.x * r1.o.x
|
||
+ r1.o.y * r1.o.y - r2;
|
||
t1 := b * b - 4.0 * a * c;
|
||
if t1 > 0 then begin
|
||
t2 := sqrt(t1);
|
||
t3 := 2.0 * a;
|
||
close1 := -(b + t2) / t3;
|
||
farther1 := -(b - t2) / t3;
|
||
if close1 > 0 then begin
|
||
p1 := r1.d;
|
||
p1.Scale(close1);
|
||
close := p1.Length;
|
||
p1.Add(r1.o);
|
||
if (p1.z < 0) or (p1.z > h) then close := -1;
|
||
end;
|
||
if farther1 > 0 then begin
|
||
p2 := r1.d;
|
||
p2.Scale(farther1);
|
||
farther := p2.Length;
|
||
p2.Add(r1.o);
|
||
if (p2.z < 0) or (p2.z > h) then farther := -1;
|
||
end;
|
||
end;
|
||
end;
|
||
end;
|
||
|
||
procedure GetConeInfo(Ray: TRay; Pos,Normal: TPoint3d; ra,rb,h: Float; ends: ShortInt;
|
||
var close,farther,end1,end2: Float);
|
||
begin
|
||
end;
|
||
|
||
procedure GetPlaneInfo(Ray: TRay; Pos,Normal: TPoint3d; var time: Float);
|
||
var
|
||
p1, p2, p3: Float;
|
||
begin
|
||
p1 := Pos.x * Normal.x + Pos.y * Normal.y + Pos.z * Normal.z;
|
||
p2 := ray.o.x * Normal.x + ray.o.y * Normal.y + ray.o.z * Normal.z;
|
||
p3 := ray.d.x * Normal.x + ray.d.y * Normal.y + ray.d.z * Normal.z;
|
||
if p3 = 0 then p3 := 0.001;
|
||
Time := (p1-p2)/p3;
|
||
end;
|
||
|
||
end. |