G3dRayTraceImpl.mesa
Copyright Ó 1985, 1992 by Xerox Corporation. All rights reserved.
Bloomenthal, August 26, 1992 5:46 pm PDT
DIRECTORY CedarProcess, G3dBasic, G3dDraw, G3dLight, G3dMatrix, G3dRayTrace, G3dVector, G3dView, Imager, ImagerColor, --ImagerFullColorContext,-- ImagerPixel, ImagerSample, IO, Real, RealFns, Rope, RuntimeError--, Terminal--;
G3dRayTraceImpl:
CEDAR
PROGRAM
IMPORTS CedarProcess, G3dDraw, G3dLight, G3dVector, --ImagerFullColorContext,-- ImagerSample, IO, Real, RealFns, RuntimeError--, Terminal--
EXPORTS G3dRayTrace
Types
Triple: TYPE ~ G3dBasic.Triple;
Matrix: TYPE ~ G3dMatrix.Matrix;
RayProc: TYPE ~ G3dRayTrace.RayProc;
RayData: TYPE ~ G3dRayTrace.RayData;
RayDataRep: TYPE ~ G3dRayTrace.RayDataRep;
Viewport: TYPE ~ G3dMatrix.Viewport;
Context: TYPE ~ Imager.Context;
RGB: TYPE ~ ImagerColor.RGB;
PixelMap: TYPE ~ ImagerPixel.PixelMap;
origin: Triple ~ G3dBasic.origin;
yAxis: Triple ~ G3dBasic.yAxis;
zAxis: Triple ~ G3dBasic.zAxis;
Ray Tracing
RayTrace:
PUBLIC
PROC [
display: PixelMap, -- place to create the ray-traced image
eyePoint: Triple ¬ origin, -- position of the eye
eyeView: Triple ¬ zAxis, -- view direction
upDirection: Triple ¬ yAxis, -- orientation
fieldOfView: REAL ¬ 40.0, -- half horizontal view in degrees
jitter: BOOL ¬ FALSE, -- stochastic ray from pixel center
nPixelSamples: NAT ¬ 1, -- sub-sampling of pixels
adaptiveLimit: NAT ¬ 0, -- # levels of adaptive refinement
rayProc: RayProc ¬ NIL, -- client supplied ray-tracing proc
clientData: REF ANY ¬ NIL] -- passed to the rayProc
RETURNS [r: RayData]
~ {
r ¬ NEW[RayDataRep];
r.eyePoint ¬ eyePoint;
r.eyeView ¬ G3dVector.Unit[eyeView];
r.upDirection ¬ upDirection;
r.fieldOfView ¬ fieldOfView;
r.jitter ¬ jitter;
r.nPixelSamples ¬ nPixelSamples;
r.adaptiveLimit ¬ adaptiveLimit;
r.display ¬ display;
r.clientData ¬ clientData;
r.rayProc ¬ rayProc;
r.process ¬ CedarProcess.Fork[RayTracer, r, [priority: background, usePriority: TRUE]];
};
PrepareRayTracer:
PUBLIC
PROC [r: RayData] ~ {
r.eyeView ¬ G3dVector.Unit[r.eyeView];
r.lights ¬ G3dLight.PrepareLights[r.lights, r.eyeView];
};
StartRayTracing:
PUBLIC
PROC [r: RayData] ~ {
IF r.process =
NIL
OR CedarProcess.GetStatus[r.process] # busy
THEN r.process ¬ CedarProcess.Fork[RayTracer, r, [background, TRUE]];
};
StopRayTracing:
PUBLIC
PROC [r: RayData] ~ {
IF CedarProcess.GetStatus[r.process] = busy THEN CedarProcess.Abort[r.process];
};
ResetRayTracing:
PUBLIC
PROC [r: RayData] ~ {r.nextPixel ¬ [0, 0]};
SetNextPixel:
PUBLIC PROC [r: RayData] ~ {
IF (r.nextPixel.x ¬ r.nextPixel.x+1) =
INTEGER[r.x+r.w]
THEN {
r.nextPixel.x ¬ r.x;
IF (r.nextPixel.y ¬ r.nextPixel.y+1) = INTEGER[r.y+r.h] THEN r.nextPixel.y ¬ r.y;
};
};
SetRay:
PUBLIC PROC [r: RayData, x, y:
NAT] ~ {
xHalf: REAL ¬ 0.5*(r.w-r.x);
yHalf: REAL ¬ 0.5*(r.h-r.y);
aspect: REAL ¬ AspectRatio[r];
tangent: REAL ¬ RealFns.TanDeg[r.fieldOfView];
xPortion: REAL ¬ -(REAL[x-r.x]-xHalf)/xHalf; -- +/- 1
yPortion: REAL ¬ -(REAL[y-r.y]-yHalf)/yHalf; -- +/- 1
xVec: Triple ¬ G3dVector.SetVectorLength[
G3dVector.Cross[r.eyeView, r.upDirection], tangent*xPortion];
yVec: Triple ¬ G3dVector.SetVectorLength[r.upDirection, tangent*yPortion*aspect];
r.ray.axis ¬
[r.eyeView.x+xVec.x+yVec.x, r.eyeView.y+xVec.y+yVec.y, r.eyeView.z+xVec.z+yVec.z];
r.ray.base ¬ r.eyePoint;
};
stopEverything:
BOOL ¬
FALSE;
-- for emergencies
RayTracer: CedarProcess.ForkableProc ~ {
Luminance:
PROC [rgb:
RGB]
RETURNS [
NAT] ~ {
v: REAL ¬ IF rgb.R=rgb.G AND rgb.R=rgb.B THEN rgb.R ELSE .3*rgb.R+.59*rgb.G+.11*rgb.B;
RETURN[Real.Round[255.0*v]];
};
r: RayData ¬ NARROW[data];
fbA: Terminal.FrameBuffer ← Terminal.GetColorFrameBufferA[Terminal.Current[]];
fbB: Terminal.FrameBuffer ← Terminal.GetColorFrameBufferB[Terminal.Current[]];
PrepareRayTracer[r];
r.display ← ImagerFullColorContext.PixelMapFromFrameBuffers[fbA, fbB];
r.display[0] ¬ ImagerSample.Clip[r.display[0], [[r.y, r.x], [r.y+r.h, r.x+r.w]]];
r.display[1] ¬ ImagerSample.Clip[r.display[1], [[r.y, r.x], [r.y+r.h, r.x+r.w]]];
r.redo ¬ ImagerSample.NewSampleMap[r.display.box, 1];
WHILE
NOT stopEverything
DO
ENABLE RuntimeError.BoundsFault => CONTINUE;
x, y: NAT;
CedarProcess.CheckAbort[];
SetRay[r, x ¬ r.nextPixel.x, y ¬ r.nextPixel.y];
r.rgb ¬ r.rayProc[[r.ray.base, G3dVector.Unit[r.ray.axis]], r.clientData];
SELECT r.display.samplesPerPixel
FROM
1 => ImagerSample.Put[r.display[0], [y, x], Luminance[r.rgb]];
3 => {
ImagerSample.Put[r.display[0], [y, x], Real.Round[255.0*r.rgb.R]];
ImagerSample.Put[r.display[1], [y, x], Real.Round[255.0*r.rgb.G]];
ImagerSample.Put[r.display[2], [y, x], Real.Round[255.0*r.rgb.B]];
};
ENDCASE;
SetNextPixel[r];
IF r.nextPixel = [r.x, r.y]
THEN {
IF r.finishProc # NIL THEN [] ¬ CedarProcess.Fork[Finisher, r];
EXIT;
};
ENDLOOP;
};
Finisher: CedarProcess.ForkableProc ~ {
r: RayData ¬ NARROW[data];
r.finishProc[r.clientData];
};
Miscellany
AspectRatio:
PUBLIC PROC [r: RayData]
RETURNS [
REAL] ~ {
RETURN[REAL[r.h-r.y]/REAL[r.w-r.x]];
};
RayImageScreenCorners:
PUBLIC
PROC [r: RayData]
RETURNS [p1, p2, p3, p4: Triple] ~ {
tangent: REAL ¬ RealFns.TanDeg[r.fieldOfView];
aspect: REAL ¬ AspectRatio[r];
xVec: Triple ¬ G3dVector.SetVectorLength[
G3dVector.Cross[r.eyeView, r.upDirection], tangent];
yVec: Triple ¬ G3dVector.SetVectorLength[r.upDirection, tangent*aspect];
at: Triple ¬ G3dVector.Add[r.eyePoint, r.eyeView];
p1 ¬ [at.x+xVec.x+yVec.x, at.y+xVec.y+yVec.y, at.z+xVec.z+yVec.z];
p2 ¬ [at.x+xVec.x-yVec.x, at.y+xVec.y-yVec.y, at.z+xVec.z-yVec.z];
p3 ¬ [at.x-xVec.x-yVec.x, at.y-xVec.y-yVec.y, at.z-xVec.z-yVec.z];
p4 ¬ [at.x-xVec.x+yVec.x, at.y-xVec.y+yVec.y, at.z-xVec.z+yVec.z];
};
DrawRayTip:
PUBLIC
PROC [context: Context, r: RayData, view: Matrix, viewport: Viewport] ~ {
G3dDraw.Mark[context, G3dVector.Add[r.ray.base, r.ray.axis], view, viewport,, dot];
};
DrawRayImageScreen:
PUBLIC PROC [
context: Context,
r: RayData,
view: Matrix,
viewport: Viewport ¬ []]
~ {
p1, p2, p3, p4: Triple;
[p1, p2, p3, p4] ¬ RayImageScreenCorners[r];
G3dDraw.Segment[context, p1, p2, view, viewport];
G3dDraw.Segment[context, p2, p3, view, viewport];
G3dDraw.Segment[context, p3, p4, view, viewport];
G3dDraw.Segment[context, p4, p1, view, viewport];
G3dDraw.Segment[context, r.eyePoint, p1, view, viewport];
G3dDraw.Segment[context, r.eyePoint, p2, view, viewport];
G3dDraw.Segment[context, r.eyePoint, p3, view, viewport];
G3dDraw.Segment[context, r.eyePoint, p4, view, viewport];
};
ParametersMessage:
PUBLIC PROC [r: RayData]
RETURNS [rope:
ROPE] ~ {
rope ¬
IO.PutFLR["display w, h: %g, %g, %gjitter, %g subSamples, %g adaptLimit",
LIST[
IO.int[r.w], IO.int[r.h], IO.rope[IF r.jitter THEN NIL ELSE "not "],
IO.int[r.nPixelSamples], IO.int[r.adaptiveLimit]]];
};