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
~ BEGIN
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;
ROPE:     TYPE ~ Rope.ROPE;
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]]];
};
END.