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 RGB: TYPE ~ G3dLight.RGB; ROPE: TYPE ~ Rope.ROPE; PropList: TYPE ~ Atom.PropList; Triple: TYPE ~ G3dBasic.Triple; Light: TYPE ~ G3dLight.Light; LightProc: TYPE ~ G3dLight.LightProc; LightRep: TYPE ~ G3dLight.LightRep; LightSequence: TYPE ~ G3dLight.LightSequence; LightSequenceRep: TYPE ~ G3dLight.LightSequenceRep; Error: PUBLIC SIGNAL [code: ATOM, reason: ROPE] = CODE; DefaultIllumination: LightProc ~ { d: REAL ¬ G3dVector.Length[G3dVector.Sub[position, light.position]]; strength: REAL ¬ RealFns.Power[(light.radius-d)/light.radius, light.exponent]; RETURN[[light.color.R*strength, light.color.G*strength, light.color.B*strength]]; }; 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: REAL ¬ IF 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]]; }; AddLight: PUBLIC PROC [ lights: LightSequence, name: ROPE, position, direction: Triple, color: RGB ¬ [1,1,1], eyeView: Triple ¬ []] RETURNS [LightSequence] ~ { light: Light ¬ NEW[LightRep]; -- make new light of given type light.name ¬ name; light.position ¬ position; light.color ¬ color; light.direction ¬ direction; 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]; }; LengthenLightSequence: PUBLIC PROC [lights: LightSequence] RETURNS [new: LightSequence] ~ { newLength: NAT ¬ MAX[Real.Round[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; }; 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; }; PrepareLight: PUBLIC PROC [light: Light, eyeView: Triple] ~ { indexOfRefraction: REAL ~ 200.0; specularCharacteristic: REAL ~ 0.35; r, rSubQ, rAddQ, qrAddQ, qrSubQ, q: REAL; light.position ¬ G3dVector.Unit[light.position]; -- keep to unit sphere, for user interaction 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; IF light.lightProc = NIL THEN light.lightProc ¬ DefaultIllumination; }; PrepareLights: PUBLIC PROC [lights: LightSequence, eyeView: Triple] RETURNS [LightSequence] ~ { IF lights = NIL THEN lights ¬ AddLight[NIL, "Light1", [200.0, 100.0, 100.0], [1.0, 0.0, 0.0]]; FOR n: NAT IN [0..lights.length) DO PrepareLight[lights[n], eyeView]; ENDLOOP; RETURN[lights]; }; registeredLights: PropList ¬ NIL; -- registered lights RegisterLight: PUBLIC PROC [light: Light, type: ATOM] ~ { registeredLights ¬ Atom.PutPropOnList[registeredLights, type, NEW[LightRep ¬ light­]]; }; GetRegisteredLight: PUBLIC PROC [type: ATOM] RETURNS [light: Light] ~ { ref: Light ¬ NARROW[Atom.GetPropFromList[registeredLights, type]]; IF ref # NIL THEN light ¬ NEW[LightRep ¬ ref­] ELSE Error[$Unimplemented, "Unregistered light type"]; }; InitDefaultLightClasses: PUBLIC PROC ~ { defaultLight: Light ¬ NEW[LightRep]; defaultLight.lightProc ¬ DefaultIllumination; RegisterLight[defaultLight, $Default]; }; 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.PutFLR["\t%g: pos: [%g, %g, %g]", LIST[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[]; }; InitDefaultLightClasses[]; END. Κ G3dLightImpl.mesa Copyright Σ 1988, 1992 by Xerox Corporation. All rights reserved. Bloomenthal, July 15, 1992 10:47 pm PDT Glassner, January 23, 1989 9:34:54 am PST Crow, May 16, 1989 6:28:52 pm PDT Imported Types Errors Lighting Local Phong shading: Modified Torrance-Sparrow (Blinn) shading: Light Sequences Preparation From Blinn: Models of Light Reflection for Computer Synthesized Pictures, Siggraph '77. Registration Miscellany Start Code ΚΆ•NewlineDelimiter –"cedarcode" style™™Jšœ Οeœ6™BJ™'Jšœ&Οk™)Jšœž™!J˜Jšž œ&žœG˜xJ˜—šΡbln œžœž˜Jšžœžœ7˜RJšžœ ˜J˜—Jšœž˜headšΟl™Jšžœžœ žœ˜Jšžœžœžœ˜Jšœ žœ˜"Jšœ žœ˜"Jšœ žœ˜!Jšœ žœ˜'Jšœ žœ˜&Jšœžœ˜.Jšœžœ˜3—š ™Jš Οnœžœžœžœ žœžœ˜:—š ™™J™š‘œ˜"Jšœžœ=˜DJšœ žœA˜OJšžœK˜QJ˜J˜——™*J™š‘ œžœžœ(˜>Jšžœžœ˜#J˜Jšœ)Οc"˜KJ˜/J˜/J˜J˜—š‘œžœžœ%žœ˜GJšžœžœ˜J˜šœžœžœ˜šžœžœ˜%Jšžœ˜Jšžœ ˜—šžœžœ˜%Jšžœ$˜(Jšžœ ˜——Jšœžœ!˜(Jšœžœ˜Jšžœžœ˜J˜———š ™š‘œžœžœ˜Jšœ˜JšœΟsžœ˜ Jšœ£œ˜Jšœ£ž£œ£œ˜J˜Jšžœ˜J˜Jšœžœ ’˜=J˜J˜J˜J˜Jšœ˜Jšžœ žœžœ žœ˜7šžœžœžœž˜#Jš žœžœ(žœžœžœ˜?J˜Jšžœ˜Jšž˜šžœ˜ Jšžœ"žœ(˜PJ˜J˜ J˜—Jšžœ˜—Jšžœ ˜J˜J˜—š‘œžœžœ˜:Jšžœ˜ Jšœ žœžœ#˜7Jšœžœ˜'Jš žœžœžœžœžœ˜@J˜J˜J˜—š‘ œžœžœžœ˜@Jšœžœ˜Jšžœ žœžœžœ˜šžœžœžœž˜#Jšžœ"žœžœ žœ˜>Jšžœ˜—Jšžœžœžœ˜Jš žœžœžœžœžœ˜JJ˜ J˜——š  ™ J˜š‘ œžœžœ$˜=™WJšœžœ ˜ Jšœžœ˜$Jšœ$žœ˜)Jšœ1’,˜]J˜2J˜JJ˜:J˜>J˜J˜J˜J˜J˜NJ˜BJ˜Jšžœžœžœ'˜D—J˜J˜—š‘ œžœžœ)˜CJšžœ˜J˜Jšžœ žœžœžœ4˜^Jš žœžœžœžœ#žœ˜NJšžœ ˜J˜——š  ™ Jšœžœ’˜8J˜š‘ œžœžœžœ˜9Jš œ£œ&£œ£žœ £œ ˜VJ˜—š ‘œžœžœžœžœ˜GJšœ žœ/˜Bšžœžœ˜ Jšžœ žœ˜"Jšžœ2˜6—J˜J˜—š‘œžœžœ˜(Jšœžœ ˜$J˜-Jšœ&˜&Jšœ˜——š  ™ š ‘œžœžœžœžœ˜IJ˜šžœ žœž˜šžœžœžœž˜#J˜šœžœ"˜7Jš žœžœžœžœžœ˜]—šœžœ˜3Jšžœžœžœ˜=—J˜Jšžœ˜——J˜J˜—š‘œž œ%žœ˜Qš‘ œžœžœ˜5Jšžœ*žœžœžœ˜