DIRECTORY Atom, G3dBasic, G3dLight, G3dRender, G3dShade, G3dVector, Real; G3dShadeImpl: CEDAR MONITOR IMPORTS Atom, G3dLight, G3dRender, G3dVector, Real EXPORTS G3dShade ~ BEGIN RGB: TYPE ~ G3dRender.RGB; PropList: TYPE ~ Atom.PropList; Shape: TYPE ~ G3dShade.Shape; Light: TYPE ~ G3dLight.Light; RenderData: TYPE ~ G3dRender.RenderData; RenderStyle: TYPE ~ G3dRender.RenderStyle; Triple: TYPE ~ G3dRender.Triple; NatSequence: TYPE ~ G3dBasic.NatSequence; NatSequenceRep: TYPE ~ G3dBasic.NatSequenceRep; PairSequence: TYPE ~ G3dBasic.PairSequence; TripleSequence: TYPE ~ G3dBasic.TripleSequence; LightSequence: TYPE ~ G3dLight.LightSequence; ShadingClass: TYPE ~ G3dShade.ShadingClass; defaultWhite: RGB _ [1.0, 1.0, 1.0]; registeredShadingClasses: PropList _ NIL; -- keeps active shading classes TotalSurfaceIntensity: PUBLIC PROC [ normal, eyeView: Triple, lights: LightSequence, portionSpecular: REAL] RETURNS [i: REAL _ 0.0] ~ { portionDiffuse: REAL _ 1.0-portionSpecular; IF lights # NIL THEN FOR n: NAT IN [0..lights.length) DO nDotE, nDotH, nDotL, specular: REAL; l: Light _ lights[n]; [nDotE, nDotH, nDotL] _ G3dLight.LightDots[l, normal, eyeView]; specular _ G3dLight.SpecularFromDots[l, nDotE, nDotH, nDotL]; i _ i+portionSpecular*specular+portionDiffuse*MAX[0.0, nDotL]; ENDLOOP; }; SurfaceIntensity: PUBLIC PROC [light: Light, normal, eyeView: Triple, portionSpecular: REAL] RETURNS [REAL] ~ { nDotE, nDotH, nDotL, specular: REAL; [nDotE, nDotH, nDotL] _ G3dLight.LightDots[light, normal, eyeView]; specular _ G3dLight.SpecularFromDots[light, nDotE, nDotH, nDotL]; RETURN[portionSpecular*specular+(1.0-portionSpecular)*MAX[0.0, nDotL]]; }; SpecularIntensity: PUBLIC PROC [light: Light, normal, eyeView: Triple] RETURNS [REAL] ~ { nDotE, nDotH, nDotL: REAL; [nDotE, nDotH, nDotL] _ G3dLight.LightDots[light, normal, eyeView]; RETURN[G3dLight.SpecularFromDots[light, nDotE, nDotH, nDotL]]; }; DiffuseIntensity: PUBLIC PROC [light: Light, normal: Triple] RETURNS [REAL] ~ { RETURN[MAX[0, G3dVector.Dot[normal, light.direction]]]; }; RegisterShadingClass: PUBLIC PROC [class: ShadingClass, type: ATOM] ~ { registeredShadingClasses _ Atom.PutPropOnList[registeredShadingClasses, type, NEW[ShadingClass _class]]; }; GetShadingClass: PUBLIC PROC [type: ATOM] RETURNS [class: ShadingClass] ~ { ref: REF ShadingClass _ NARROW[Atom.GetPropFromList[registeredShadingClasses, type]]; IF ref # NIL THEN class _ ref^ ELSE G3dRender.Error[$Unimplemented, "Unregistered shading class"]; }; LoadShadingClass: PUBLIC PROC [shape: Shape, type: ATOM _ $Default ] ~ { renderData: REF RenderData; class: REF ShadingClass _ NARROW[Atom.GetPropFromList[registeredShadingClasses, type]]; IF class = NIL THEN G3dRender.Error[$Unimplemented, "Unregistered shading class"]; renderData _ G3dRender.RenderDataFrom[shape]; IF renderData.shadingClass = NIL THEN renderData.shadingClass _ NEW[ShadingClass _ class^] ELSE { new: REF ShadingClass _ NEW[ShadingClass _ class^]; IF new.renderMethod = NIL THEN new.renderMethod _ renderData.shadingClass.renderMethod; new.color _ renderData.shadingClass.color; new.diffuseReflectivity _ renderData.shadingClass.diffuseReflectivity; new.specularReflectivity _ renderData.shadingClass.specularReflectivity; new.metallicity _ renderData.shadingClass.metallicity; new.shininess _ renderData.shadingClass.shininess; new.clientShadingData _ renderData.shadingClass.clientShadingData; new.transmittance _ renderData.shadingClass.transmittance; IF new.texture = NIL THEN new.texture _ renderData.shadingClass.texture; new.textureScale _ renderData.shadingClass.textureScale; new.bumpScale _ renderData.shadingClass.bumpScale; IF new.cnvrtVtx = NIL THEN new.cnvrtVtx _ renderData.shadingClass.cnvrtVtx; IF new.getColor = NIL THEN new.getColor _ renderData.shadingClass.getColor; IF new.shadeVtx = NIL THEN new.shadeVtx _ renderData.shadingClass.shadeVtx; renderData.shadingClass _ new; }; }; InitStandardShadeClasses: PROC[] ~ { -- register procedures for basic shade types defaultShadingClass: ShadingClass _ [ -- procs for standard shading (no texture) type: $Default, renderMethod: NEW[RenderStyle _ faceted], shadeVtx: ShadeVtx ]; RegisterShadingClass[defaultShadingClass, $Default]; defaultShadingClass.type _ $NoShading; defaultShadingClass.shadeVtx _ NoShadeVtx; RegisterShadingClass[defaultShadingClass, $NoShading]; }; Ambient: PUBLIC PROC [normal: Triple, data: REF _ NIL] RETURNS [ambient: RGB] ~ { IF data = NIL THEN RETURN[[.2, .2, .2]]; WITH data SELECT FROM clr: REF RGB => ambient _ clr^; dir: REF Triple => { direction: Triple _ dir^; dotNL: REAL _ G3dVector.Dot[ G3dVector.Unit[direction], G3dVector.Unit[ normal ] ]; dotNL _ (dotNL + 1.0) / 2.0; -- range ambient light over shadowed portions too ambient.R _ ambient.G _ ambient.B _ dotNL; }; ENDCASE => ambient _ [.2, .2, .2]; }; NoShadeVtx: PUBLIC G3dRender.CtlPtInfoProc ~ { shadingClass: REF ShadingClass _ NARROW[data]; shapeClr: RGB _ IF shadingClass # NIL THEN shadingClass.color ELSE defaultWhite; shapeTrans: REAL _ IF shadingClass # NIL THEN shadingClass.transmittance ELSE 0.0; vtx.shade.er _ vtx.shade.r * shapeClr.R; vtx.shade.eg _ vtx.shade.g * shapeClr.G; vtx.shade.eb _ vtx.shade.b * shapeClr.B; IF shapeTrans > 0.0 THEN { -- compute transmittance if transparent vtx.shade.et _ vtx.shade.t * shapeTrans; -- Transmittance vtx.shade.et _ MAX[0.0, MIN[vtx.shade.et, 1.]]; }; RETURN[vtx]; -- avoids shading calculations for background polygons, shadows, etc. }; ShadeVtx: PUBLIC G3dRender.CtlPtInfoProc ~ { shadingClass: REF ShadingClass _ NARROW[data]; shapeClr: RGB _ IF shadingClass # NIL THEN shadingClass.color ELSE defaultWhite; shapeTrans: REAL _ IF shadingClass # NIL THEN shadingClass.transmittance ELSE 0.0; kDiffuse: REAL _ IF shadingClass # NIL THEN shadingClass.diffuseReflectivity ELSE 1.0; kSpecular: REAL _ IF shadingClass # NIL THEN shadingClass.specularReflectivity ELSE 1.0; metallicity: REAL _ IF shadingClass # NIL THEN shadingClass.metallicity ELSE 0.0; shininess: REAL _ IF shadingClass # NIL THEN shadingClass.shininess ELSE 0.0; shinyPwr: NAT _ Real.Round[shininess]; partShiny: REAL _ 1.0; toLightSrc, toEye: Triple; dotNL, dotNE, sumHilite: REAL _ 0.0; ambient, diffuse, specular, result: RGB _ [0.0, 0.0, 0.0]; vtxClr: RGB _ [vtx.shade.r * shapeClr.R, vtx.shade.g * shapeClr.G, vtx.shade.b * shapeClr.B]; toEye _ G3dVector.Unit[[-vtx.coord.ex, -vtx.coord.ey, -vtx.coord.ez]]; -- direction to eye [ [vtx.shade.exn, vtx.shade.eyn, vtx.shade.ezn] ] _ G3dVector.Unit[ [vtx.shade.exn, vtx.shade.eyn, vtx.shade.ezn] -- often not unitd ]; ambient _ Ambient[[vtx.shade.exn, vtx.shade.eyn, vtx.shade.ezn], context.environment]; ambient.R _ ambient.R * vtxClr.R; ambient.G _ ambient.G * vtxClr.G; ambient.B _ ambient.B * vtxClr.B; IF context.lightSources # NIL THEN FOR i: NAT IN [0..context.lightSources.length) DO lightClr: RGB _ context.lightSources[i].illuminationProc[ context.lightSources[i], [vtx.coord.ex, vtx.coord.ey, vtx.coord.ez] ]; center: Triple _ context.lightSources[i].eyePosition; toLightSrc _ G3dVector.Unit[ -- vector to light source from surface vtx. [ center.x - vtx.coord.ex, center.y - vtx.coord.ey, center.z - vtx.coord.ez ] ]; dotNL _ G3dVector.Dot[toLightSrc, [vtx.shade.exn, vtx.shade.eyn, vtx.shade.ezn]]; IF dotNL <= 0. THEN LOOP; -- surface faces away from light, skip diffuse.R _ (1. - ambient.R) * dotNL * lightClr.R * vtxClr.R; -- surface facing the light diffuse.G _ (1. - ambient.G) * dotNL * lightClr.G * vtxClr.G; diffuse.B _ (1. - ambient.B) * dotNL * lightClr.B * vtxClr.B; IF vtx.data # NIL THEN WITH vtx.data SELECT FROM -- extract partial shinyness ptShiny: REF REAL => partShiny _ ptShiny^; ENDCASE; IF shinyPwr > 0 AND partShiny > 0.0 THEN { -- compute Phong specular component pctHilite: REAL _ 0.0; halfWay: Triple _ G3dVector.Unit[ -- unitd average of vectors G3dVector.Mul[ G3dVector.Add[toEye, toLightSrc], 0.5 ] ]; dotNormHalfWay: REAL _ G3dVector.Dot[ -- cos angle betw. normal and average [vtx.shade.exn, vtx.shade.eyn, vtx.shade.ezn], halfWay ]; IF dotNormHalfWay > 0. THEN { binaryCount: NAT _ shinyPwr; pctHilite _ partShiny; WHILE binaryCount > 0 DO -- compute power by repeated squares IF (binaryCount MOD 2) = 1 THEN pctHilite _ pctHilite*dotNormHalfWay; dotNormHalfWay _ dotNormHalfWay*dotNormHalfWay; binaryCount _ binaryCount/2; ENDLOOP; IF pctHilite < 0.0 OR pctHilite > 1.0 THEN SIGNAL G3dRender.Error[$MisMatch, "Highlight error"]; }; specular.R _ (1.0 - diffuse.R - ambient.R) * pctHilite * lightClr.R; specular.G _ (1.0 - diffuse.G - ambient.G) * pctHilite * lightClr.G; specular.B _ (1.0 - diffuse.B - ambient.B) * pctHilite * lightClr.B; sumHilite _ sumHilite + pctHilite; }; result.R _ result.R + (kDiffuse * diffuse.R) + (kSpecular * specular.R); result.G _ result.G + (kDiffuse * diffuse.G) + (kSpecular * specular.G); result.B _ result.B + (kDiffuse * diffuse.B) + (kSpecular * specular.B); ENDLOOP; -- end loop for each light source result.R _ result.R + ambient.R; -- add in ambient light result.G _ result.G + ambient.G; result.B _ result.B + ambient.B; vtx.shade.er _ MAX[0.0, MIN[result.R, 1.]]; vtx.shade.eg _ MAX[0.0, MIN[result.G, 1.]]; vtx.shade.eb _ MAX[0.0, MIN[result.B, 1.]]; IF shapeTrans > 0.0 THEN { -- compute transmittance if transparent dotNE _ G3dVector.Dot[toEye, [vtx.shade.exn, vtx.shade.eyn, vtx.shade.ezn]]; dotNE _ 1.0 - ABS[dotNE]; dotNE _ 1.0 - (dotNE * dotNE); -- invert, square, invert vtx.shade.et _ dotNE * vtx.shade.t * shapeTrans; -- Transmittance as seen from eyepoint vtx.shade.et _ MIN[1.0 - sumHilite, vtx.shade.et]; -- make highlights more opaque vtx.shade.et _ MAX[0.0, MIN[vtx.shade.et, 1.]]; } ELSE vtx.shade.et _ 0.0; RETURN[vtx]; }; InitStandardShadeClasses[]; END. ΨG3dShadeImpl.mesa Copyright Σ 1985, 1989 by Xerox Corporation. All rights reserved. Bloomenthal, June 19, 1989 12:17:11 pm PDT Heckbert, August 9, 1988 4:50:32 pm PDT Crow, June 10, 1989 2:48:39 pm PDT Glassner, July 19, 1989 12:14:25 pm PDT Types Miscellaneous Types Imported Sequences Shade Definitions Global Variables Shading Class Registration and Installation Ambient Light Get an ambient light value from the eyespace normal to the surface Procedures for Shading Patches PROC[ context: Context, vtx: CtlPtInfo, data: REF ANY _ NIL ] RETURNS[CtlPtInfo] Calculate shade at vertices of polygon Get ambient component of light Do for each light source Get Light Direction from Surface Get Basic Lambertian Shade Get Highlight Contribution Add in Highlight, based on headroom left after diffuse and ambient light included Accumulate diffuse and specular contributions from each light Transmittance is cosine of angle between to eye and normal (modified for effect) Start Code Κ „˜šœ™JšœB™BJšœ*™*Icodešœ$Οk™'Kšœ"™"K™'J˜Jš œ@˜IJ˜—šΡbln œœ˜Jšœ+˜2Jšœ ˜J˜—Jšœ˜headšΟl™šŸ™Jšœœ œ˜Jšœ œ˜"Jšœ œ˜ Jšœ œ˜"Jšœœ˜+Jšœœ˜-Jšœ œ˜$—šŸ™Jšœœ˜+Jšœœ˜0Jšœœ˜,Jšœœ˜0Jšœœ˜.—šΠbl™Jšœœ˜1——š ™Iašœœ˜$Idefaultšœ%œΟc˜K—šŸ™šΟnœœœ˜$JšœAœ˜FJšœœ˜Jšœ˜Jšœœ˜+š œ œœœœœ˜8Jšœœ˜$J˜J˜?J˜=Jšœ.œ ˜>Jšœ˜—J˜J˜—š’œœœ:œ˜\Jšœœ˜J˜Jšœœ˜$J˜CJ˜AJšœ0œ˜GJ˜J˜—š ’œœœ(œœ˜YJšœœ˜J˜CJšœ8˜>J˜J˜—š ’œœœœœ˜OJšœœ-˜7J˜——šŸ#™#š’œœœœ˜GJš œΟsœ.£œ£œ £œ ˜hJ˜—š ’œœœœœ˜KNšœœœ7˜Ušœœ˜ Nšœ˜Nšœ?˜C—N˜—š’œœœœ˜HNšœ œ ˜Nšœœœ7˜WNšœ œœ?˜RJšœ-˜-šœœ˜!Jšœœ˜9šœ˜Jšœœœ˜3šœœ˜Jšœ9˜=—Jšœ*˜*JšœF˜FJšœH˜HJšœ6˜6Jšœ2˜2JšœB˜BJšœ:˜:Jšœœœ/˜HJšœ8˜8Jšœ2˜2Jšœœœ1˜KJšœœœ1˜KJšœœœ1˜KJšœ˜J˜——N˜N˜—š’œœ‘,˜Ršœ'‘*˜QJ˜Jšœœ˜)J˜J˜—N˜5J˜&Jšœ*˜*N˜6J˜——šŸ ™ š’œœœœœœ œ˜QN™BNšœœœœ˜(šœœ˜Nšœœœ˜šœœ ˜Nšœ˜šœœ˜Nšœ3˜3N˜—Nšœ‘1˜PN˜*N˜—Nšœ˜"—J˜——šŸ™š’ œœ˜.Nšœœœ˜.Nš œ œœœœœ˜PNš œ œœœœœ˜RN˜)N˜(N˜(šœœ‘'˜GNšœ0‘˜@Nšœœœ˜/N˜—Jšœ‘E˜SN˜—š’œœ˜,Nš œ*œœœœ ™PM™&Nšœœœ˜.Nš œ œœœœœ˜PNš œ œœœœœ˜RNš œ œœœœ"œ˜VNš œ œœœœ#œ˜XNš œ œœœœœ˜QNš œ œœœœœ˜MNšœ œ˜&Nšœ œ˜N˜Nšœœ˜$Nšœ$œ˜:NšœœR˜]NšœG‘˜Z˜CNšœ1‘˜CN˜—M˜N™NšœV˜VN˜"N˜!N˜!M˜š œœœœœœ"˜TNšœ™šœ œ,˜9NšœC˜CNšœ˜—Mšœ6˜6N™ šœ ‘+˜KNšœP˜PNšœ˜—K˜N™N˜QNšœ œœ‘&˜FNšœ@‘˜[N˜=N˜>N™š œ œœœ œœ‘˜MNšœ œœ˜*Nšœ˜—šœœœ‘#˜PNšœ œ˜šœ#‘˜>N˜6N˜—šœœ‘%˜KN˜/N˜N˜—šœœ˜Nšœ œ ˜N˜šœœ‘$˜ANšœœœ&˜EN˜/N˜Nšœ˜—šœœ˜&Nšœœ/˜:—N˜—N™QN˜DN˜DN˜EN˜"N˜—N™=N˜HN˜HN˜HNšœ ‘!˜1—Nšœ%‘˜