<> <> <> <> <> DIRECTORY Imager, ImagerColor, ImagerColorPrivate, RealFns, SVShading, SV3d, SVModelTypes, SVVector3d; SVShadingImpl: CEDAR PROGRAM IMPORTS ImagerColor, ImagerColorPrivate, RealFns, SVVector3d EXPORTS SVShading = BEGIN Color: TYPE = Imager.Color; Vector3d: TYPE = SV3d.Vector3d; Point3d: TYPE = SV3d.Point3d; LightSource: TYPE = SVModelTypes.LightSource; LightSourceList: TYPE = SVModelTypes.LightSourceList; ExtractRGB: PUBLIC PROC [color: Color] RETURNS [r,g,b: REAL] = { rgb: ImagerColor.RGB; rgb _ ImagerColorPrivate.RGBFromColor[NARROW[color]]; r _ rgb.R; g _ rgb.G; b _ rgb.B; }; NormalizeRGB: PUBLIC PROC [r,g,b: REAL] RETURNS [color: Color] = { scaleFactor: REAL; <> scaleFactor _ MAX[r,g,b]; IF scaleFactor > 1.0 THEN { r _ r/scaleFactor; g _ g/scaleFactor; b _ b/scaleFactor; }; color _ ImagerColor.ColorFromRGB[[r,g,b]]; }; CollimatedSpecularRadiance: PUBLIC PROC [surfaceNormal: Vector3d, lightSource: LightSource, albedo: REAL _ 1] RETURNS [radiance: REAL] = {radiance _ 180}; <> DiffuseReflectance: PUBLIC PROC [surfaceNormal: Vector3d, surfacePt: Point3d, surfaceColor: Color, lightSources: LightSourceList] RETURNS [r, g, b: REAL] = { OPEN SVVector3d; intensity: REAL; surfaceToLight, surfaceClr, surfaceClrTemp, liteClr, ambientClr: Vector3d; colorSum: Vector3d _ [0,0,0]; [r, g, b] _ ExtractRGB[NARROW[surfaceColor]]; IF lightSources.first.type # ambient THEN ERROR; [ambientClr[1], ambientClr[2], ambientClr[3]] _ ExtractRGB[NARROW[lightSources.first.color]]; surfaceClr _ [r,g,b]; surfaceNormal _ Normalize[surfaceNormal]; -- all vectors must be kept normalized IF ambientClr[1] > 0.0 OR ambientClr[2] > 0. OR ambientClr[3] > 0.0 THEN colorSum _ ElementwiseProduct[surfaceClr, ambientClr]; -- initialize colorSum. FOR lite: LightSourceList _ lightSources.rest, lite.rest UNTIL lite = NIL -- for each light source DO [r, g, b] _ ExtractRGB[NARROW[lite.first.color]]; liteClr _ [r,g,b]; surfaceToLight _ Normalize[Sub[lite.first.position, surfacePt]]; <> intensity _ DotProduct[surfaceNormal, surfaceToLight]; -- lambertian reflectance IF intensity < 0.0 THEN intensity _ 0.0; -- no negative reflectance allowed surfaceClrTemp _ Scale[surfaceClr, intensity]; -- scale surface color by reflectance surfaceClrTemp _ ElementwiseProduct[surfaceClrTemp, liteClr]; colorSum _ Add[colorSum, surfaceClrTemp];-- sum reflectances for all lights ENDLOOP; <> <> < 1.0 THEN colorSum _ Scale[colorSum, 1.0/scaleFactor];>> r _ colorSum[1]; g _ colorSum[2]; b _ colorSum[3]; <> }; DiffuseAndSpecularReflectance: PUBLIC PROCEDURE [eyePoint: Point3d, surfaceNormal: Vector3d, surfacePt: Point3d, surfaceColor: Color, lightSources: LightSourceList] RETURNS [r, g, b: REAL] = { OPEN SVVector3d; intensity, hilitValue: REAL; surfaceToLight, surfaceToEye, surfaceClr, surfaceClrTemp: Vector3d; ambientClr, finalClr, halfAngle, liteClr: Vector3d; colorSum: Vector3d _ [0,0,0]; [r,g,b] _ ExtractRGB[surfaceColor]; IF lightSources.first.type # ambient THEN ERROR; [ambientClr[1], ambientClr[2], ambientClr[3]] _ ExtractRGB[lightSources.first.color]; surfaceClr _ [r,g,b]; surfaceNormal _ Normalize[surfaceNormal]; -- all vectors must be kept normalized <> IF ambientClr[1] > 0.0 OR ambientClr[2] > 0. OR ambientClr[3] > 0.0 THEN colorSum _ ElementwiseProduct[surfaceClr, ambientClr]; FOR lite: LightSourceList _ lightSources.rest, lite.rest UNTIL lite = NIL -- for each light source DO [r,g,b] _ ExtractRGB[lite.first.color]; liteClr _ [r,g,b]; surfaceToLight _ Normalize[Sub[lite.first.position, surfacePt]]; -- vector from surface to light source intensity _ DotProduct[surfaceNormal, surfaceToLight]; -- lambertian reflectance IF intensity < 0.0 THEN intensity _ 0.0;-- no negative reflectance allowed surfaceClrTemp _ Scale[surfaceClr, intensity];-- scale surface color by reflectance surfaceClrTemp _ ElementwiseProduct[surfaceClrTemp, liteClr]; surfaceToEye _ Normalize[Sub[eyePoint, surfacePt]]; halfAngle _ Normalize[Add[surfaceToLight, surfaceToEye]]; hilitValue _ DotProduct[surfaceNormal, halfAngle]; -- specular reflectance IF hilitValue < 0.95 THEN hilitValue _ 0.0 ELSE hilitValue _ RealFns.Power[hilitValue, 100]; -- all surfaces have same specular power IF hilitValue > .01 THEN -- add in light source color for highlight finalClr _ Add[surfaceClrTemp, Scale[Sub[liteClr, surfaceClrTemp], hilitValue]] ELSE finalClr _ surfaceClrTemp; colorSum _ Add[colorSum, finalClr];-- sum reflectances for all lights ENDLOOP; <> < 1.0 THEN colorSum _ Scale[colorSum, 1.0/scaleFactor];-- desaturation at bright spots>> r _ colorSum[1]; g _ colorSum[2]; b _ colorSum[3]; <> }; Power: PRIVATE PROC [base: REAL, exponent: NAT] RETURNS [baseToExp: REAL] = { baseToExp _ 1.0; FOR i: NAT IN [1..exponent] DO baseToExp _ baseToExp * base; ENDLOOP; }; SimpleFilmIrradiance: PUBLIC PROCEDURE [radiance: REAL, omegaAperture: REAL] RETURNS [irradiance: REAL] = { irradiance _ radiance*omegaAperture; }; SolidAngle: PUBLIC PROCEDURE [surfacePoint: Point3d, areaAperture: REAL] RETURNS [omegaAperture: REAL] = { <> fromApertureToSurface: Vector3d _ surfacePoint;-- same as surfacePoint because aperture at [0,0,0] r: REAL _ SVVector3d.Magnitude[fromApertureToSurface]; cosTheta: REAL _ -fromApertureToSurface[3]/r; omegaAperture _ (areaAperture*cosTheta)/(r*r); }; SpecFilmIrradiance: PUBLIC PROCEDURE [surfaceNormal: Vector3d, lightSource: LightSource, albedo: REAL _ 1, omegaAperture: REAL] RETURNS [irradiance: REAL] = { <> radiance: REAL _ CollimatedSpecularRadiance[surfaceNormal,lightSource,albedo]; irradiance _ SimpleFilmIrradiance[radiance,omegaAperture]; }; END.