G3dLightImpl.mesa
Copyright © 1988 by Xerox Corporation. All rights reserved.
Bloomenthal, July 21, 1989 3:13:08 pm PDT
Glassner, January 23, 1989 9:34:54 am PST
Crow, May 16, 1989 6:28:52 pm PDT
DIRECTORY Atom, G3dBasic, G3dLight, G3dVector, IO, Real, RealFns, Rope, TiogaOps, ViewerClasses, ViewerOps, ViewerTools;
G3dLightImpl: CEDAR PROGRAM
IMPORTS Atom, G3dVector, IO, Real, RealFns, Rope, TiogaOps, ViewerOps, ViewerTools
EXPORTS G3dLight
~ BEGIN
Imported Types
RGB:     TYPE ~ G3dLight.RGB;
ROPE:     TYPE ~ Rope.ROPE;
PropList:    TYPE ~ Atom.PropList;
Triple:    TYPE ~ G3dBasic.Triple;
Light:     TYPE ~ G3dLight.Light;
LightRep:    TYPE ~ G3dLight.LightRep;
LightSequence:  TYPE ~ G3dLight.LightSequence;
LightSequenceRep: TYPE ~ G3dLight.LightSequenceRep;
IlluminationProc: TYPE ~ PROC [light: Light, position: Triple] RETURNS [color: RGB];
Errors
Error:     PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE;
Example Lighting Procs
PointSource:   TYPE ~ REF PointSourceRep;
PointSourceRep:  TYPE ~ RECORD [
radius:    REAL ← 2.0 * 93000000.0 * 1609.344, -- 2x solar distance in meters (fc)
exponent:    REAL ← 2.0
];
DefaultIllumination: IlluminationProc ~ {
IlluminationProc: TYPE ~ PROC [light: Light, position: Triple] RETURNS [color: RGB];
d: REAL ← G3dVector.Length[G3dVector.Sub[position, light.position]];
ps: PointSource ← NARROW[light.privateData];
strength: REAL ← RealFns.Power[(ps.radius-d)/ps.radius, ps.exponent];
RETURN[[light.color.R * strength, light.color.G * strength, light.color.B * strength]];
};
Lighting
PrepareLights: PUBLIC PROC [lights: LightSequence, eyeView: Triple]
RETURNS [LightSequence]
~ {
IF lights = NIL THEN lights ← AddToLightSequence[NIL, NEW[LightRep ← [name: "Light1"]]];
FOR n: NAT IN [0..lights.length) DO PrepareLight[lights[n], eyeView]; ENDLOOP;
RETURN[lights];
};
PrepareLight: PUBLIC PROC [light: Light, eyeView: Triple] ~ {
From Blinn: Models of Light Reflection for Computer Synthesized Pictures, Siggraph '77.
indexOfRefraction: REAL ~ 200.0;
specularCharacteristic: REAL ~ 0.35;
r, rSubQ, rAddQ, qrAddQ, qrSubQ, q: REAL;
light.direction ← G3dVector.Unit[light.direction];
light.highlight ← G3dVector.Unit[G3dVector.Add[eyeView, light.direction]];
q ← light.eDotH ← G3dVector.Dot[eyeView, light.direction];
r ← RealFns.SqRt[indexOfRefraction*indexOfRefraction+q*q-1.0];
rSubQ ← r-light.eDotH;
rAddQ ← r+light.eDotH;
qrAddQ ← light.eDotH*rAddQ-1.0;
qrSubQ ← light.eDotH*rSubQ+1.0;
light.f ← ((rSubQ*rSubQ)/(rAddQ*rAddQ))*(1.0+(qrAddQ*qrAddQ)/(qrSubQ*qrSubQ));
light.a ← 1.0/(specularCharacteristic*specularCharacteristic-1.0);
light.b ← light.a+1.0;
};
LightDots: PUBLIC PROC [light: Light, normal, eyeView: Triple]
RETURNS [nDotE, nDotH, nDotL: REAL]
~ {
nDotE ← -G3dVector.Dot[normal, eyeView]; -- want direction to, not from eye
nDotH ← G3dVector.Dot[normal, light.highlight];
nDotL ← G3dVector.Dot[normal, light.direction];
};
SpecularFromDots: PUBLIC PROC [light: Light, nDotE, nDotH, nDotL: REAL]
RETURNS [REAL]
~ {
g: REALIF nDotE < nDotL
THEN IF 2.0*nDotE*nDotH < light.eDotH
THEN 2.0*nDotH/light.eDotH
ELSE 1.0/nDotE
ELSE IF 2.0*nDotL*nDotH < light.eDotH
THEN 2.0*nDotH*nDotL/(light.eDotH*nDotE)
ELSE 1.0/nDotE;
t: REAL ← light.b/(nDotH*nDotH+light.a);
d: REAL ← t*t;
RETURN[MAX[0.0, d*g*light.f]];
};
LengthenLightSequence: PUBLIC PROC [lights: LightSequence]
RETURNS [new: LightSequence] ~ {
newLength: NATMAX[Real.InlineRoundI[1.3*lights.length], 3];
new ← NEW[LightSequenceRep[newLength]];
FOR i: NAT IN [0..lights.length) DO new[i] ← lights[i]; ENDLOOP;
new.length ← lights.length;
};
AddToLightSequence: PUBLIC PROC [
lights: LightSequence,
light: Light,
eyeView: Triple ← []]
RETURNS [LightSequence]
~ {
IF eyeView # [] THEN PrepareLight[light, eyeView];
IF lights = NIL THEN lights ← NEW[LightSequenceRep[1]];
FOR n: NAT IN [0..lights.length) DO
IF NOT Rope.Equal[lights[n].name, light.name, FALSE] THEN LOOP;
lights[n] ← light;
EXIT;
REPEAT
FINISHED => {
IF lights.length = lights.maxLength THEN lights ← LengthenLightSequence[lights];
lights[lights.length] ← light;
lights.length ← lights.length+1;
};
ENDLOOP;
RETURN[lights];
};
DeleteLight: PUBLIC PROC [lights: LightSequence, name: ROPE] ~ {
n: INTEGER ← -1;
IF lights = NIL THEN RETURN;
FOR i: NAT IN [0..lights.length) DO
IF Rope.Equal[lights[i].name, name, FALSE] THEN {n ← i; EXIT};
ENDLOOP;
IF n = -1 THEN RETURN;
FOR nn: INT IN [n..lights.length-1) DO lights[nn] ← lights[nn+1]; ENDLOOP;
lights.length ← lights.length-1;
};
Registration
registeredLightTypes: PropList ← NIL;   -- active lights
RegisterLightType: PUBLIC PROC [light: Light, type: ATOM] ~ {
registeredLightTypes Atom.PutPropOnList[
registeredLightTypes, type, NEW[LightRep ← light^]
];
};
InitStandardLightClasses: PUBLIC PROC ~ { -- register procedures for basic light types
defaultLight: Light ← NEW[LightRep ← [  -- procs for standard lighting
type:      $Default,
illuminationProc: DefaultIllumination
]];
defaultLight.privateData ← NEW[PointSourceRep];
RegisterLightType[defaultLight, $Default];
};
GetLightType: PUBLIC PROC [type: ATOM] RETURNS [light: Light] ~ {
ref: Light ← NARROW[Atom.GetPropFromList[registeredLightTypes, type]];
IF ref # NIL
THEN light ← NEW[LightRep ← ref^]
ELSE Error[$Unimplemented, "Unregistered light type"];
};
Miscellany
RopeFromLights: PUBLIC PROC [lights: LightSequence] RETURNS [r: ROPE] ~ {
r ← "Lights: \n";
IF lights # NIL THEN
FOR n: NAT IN [0..lights.length) DO
l: Light ← lights[n];
r ← Rope.Concat[r, IO.PutFR["\t%g: pos: [%g, %g, %g]",
IO.rope[l.name], IO.real[l.position.x], IO.real[l.position.y], IO.real[l.position.z]]];
r ← Rope.Concat[r, IO.PutFR[" color: [%g, %g, %g]",
IO.real[l.color.R], IO.real[l.color.G], IO.real[l.color.B]]];
r ← Rope.Concat[r, "\n"];
ENDLOOP;
};
AnnotateLightsToViewer: PUBLIC PROC [lights: LightSequence, viewerName: ROPE] ~ {
GetViewer: PROC RETURNS [v: ViewerClasses.Viewer] ~ {
IF (v ← ViewerOps.FindViewer[viewerName]) # NIL THEN RETURN;
v ViewerTools.MakeNewTextViewer[[name:viewerName, file:viewerName, column:right]];
ViewerOps.OpenIcon[v];
};
v: ViewerClasses.Viewer ← GetViewer[];
lastLoc: TiogaOps.Location ← TiogaOps.LastLocWithin[TiogaOps.ViewerDoc[v]];
TiogaOps.SetSelection[v, lastLoc, lastLoc];
TiogaOps.SetLooks["b"];
TiogaOps.InsertRope["Lights:"];
TiogaOps.Break[];
TiogaOps.Nest[];
IF lights # NIL THEN FOR n: NAT IN [0..lights.length) DO
l: Light ← lights[n];
TiogaOps.SetLooks["b"];
TiogaOps.InsertRope[l.name];
TiogaOps.SetLooks[" "];
TiogaOps.InsertRope[IO.PutFR[": pos: (%g, %g, %g)",
IO.real[l.position.x], IO.real[l.position.y], IO.real[l.position.z]]];
TiogaOps.InsertRope[IO.PutFR[" color: [%g, %g, %g]",
IO.real[l.color.R], IO.real[l.color.G], IO.real[l.color.B]]];
TiogaOps.Break[];
ENDLOOP;
TiogaOps.UnNest[];
};
Start Code
InitStandardLightClasses[];
END.