DIRECTORY G3dBasic, G3dLight, G3dShade, G3dVector, G3dRender; G3dShadeImpl: CEDAR MONITOR IMPORTS G3dLight, G3dVector EXPORTS G3dShade ~ BEGIN Light: TYPE ~ G3dLight.Light; LightSequence: TYPE ~ G3dLight.LightSequence; RGB: TYPE ~ G3dRender.RGB; Triple: TYPE ~ G3dBasic.Triple; 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]]]; }; 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]; }; END. .. 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], context3d.environment]; ambient.R ¬ ambient.R * vtxClr.R; ambient.G ¬ ambient.G * vtxClr.G; ambient.B ¬ ambient.B * vtxClr.B; IF context3d.lightSources # NIL THEN FOR i: NAT IN [0..context3d.lightSources.length) DO light: Light ¬ context3d.lightSources[i]; vtxCoord: Triple ¬ [vtx.coord.ex, vtx.coord.ey, vtx.coord.ez]; lightClr: RGB ¬ light.lightProc[light, vtxCoord]; center: Triple ¬ light.eyePosition; toLightSrc ¬ G3dVector.Unit[G3dVector.Sub[center, vtxCoord]]; 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]; }; ” G3dShadeImpl.mesa Copyright Σ 1985, 1989, 1992 by Xerox Corporation. All rights reserved. Bloomenthal, July 15, 1992 10:42 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 Shading Ambient Light Get an ambient light value from the eyespace normal to the surface Procedures for Shading Patches PROC[context3d: Context3d, 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 (vector to light source from surface vertex): 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) ΚS•NewlineDelimiter –"cedarcode" style™šœ™Jšœ Οeœ=™HJ™'Jšœ$Οk™'Jšœ"™"J™'J˜Jšž œ4˜=J˜—šΡbln œžœž˜Jšžœ˜Jšžœ ˜J˜—Jšœž˜headšΟl™Jšœ žœ˜"Jšœžœ˜/Jšžœžœ žœ˜Jšœ žœ˜#—š ™šΟ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˜——š  ™ š‘œžœžœžœžœžœ žœ˜QJ™BJšžœžœžœžœ˜(šžœžœž˜Jšœžœžœ˜šœžœ ˜J˜šœžœ˜Jšœ3˜3J˜—JšœΟc1˜PJ˜*J˜—Jšžœ˜"—J˜——š ™J˜—šžœ˜J˜J˜š‘œžœ˜,Jš žœ-žœžœžœžœ ™SJ™&Jšœžœžœ˜.Jš œ žœžœžœžœžœ˜PJš œ žœžœžœžœžœ˜RJš œ žœžœžœžœ"žœ˜VJš œ žœžœžœžœ#žœ˜XJš œ žœžœžœžœžœ˜QJš œ žœžœžœžœžœ˜MJšœ žœ˜&Jšœ žœ˜J˜Jšœžœ˜$Jšœ$žœ˜:JšœžœR˜]JšœG’˜Z˜CJšœ1’˜CJ˜—J˜J™J˜XJ˜"J˜!J˜!J˜š žœžœžœžœžœžœ$ž˜XJšœ™J˜)J˜>Jšœ žœ$˜1J˜$J˜JšœN™NJ˜=J˜J™J˜QJšžœ žœžœ’&˜FJšœ@’˜[J˜=J˜>J™š žœ žœžœžœ žœžœ’˜MJšœ žœžœ˜*Jšžœ˜—šžœžœžœ’#˜PJšœ žœ˜šœ#’˜>J˜6J˜—šœžœ’%˜KJ˜/J˜J˜—šžœžœ˜Jšœ žœ ˜J˜šžœžœ’$˜AJšžœžœžœ&˜EJ˜/J˜Jšžœ˜—šžœžœ˜&Jšžœžœ/˜:—J˜—J™QJ˜DJ˜DJ˜EJ˜"J˜—J™=J˜HJ˜HJ˜HJšžœ ’!˜1—Jšœ%’˜