Shaders
simpleFace5 - A procedural shader for a face
/* simpleFace5.sl
* copyright(c) 1995 - dsward@webnation.com
* generate a simple face - two eyes and a mouth
* Parameters (usually in range 0.0 to 1.0)
* Mouth controls -
* mouthLevel - placement of center of the mouth
* mouthWidth - width of mouth
* mouthOffset - vertical offset of edges from center,
* positive=smile, negative=frown
* mouthOpen - mouth opening size
* mouthOpacity - opacity 0=transparent, 1=opaque mouthColor
* Eye controls - a pupil, eye and ring
* eyeLevel - placement of the eyes
* eyeOffset - distance from faceCenter to center of each eye
* eyeRadius - radius of the ring around the eye
* pupilAngle - angle of pupil from center of eye, typically from 0 to pi*2
* pupilOffset - distance between center of pupil and center of eye
* Colors -
* mouthColor, pupilColor, eyeColor, ringColor
* General controls -
* faceCenter - the center for eye and mouth placement
* mapCode - 0 = default
* 1 = invert s
* 2 = invert t
* 3 = invert s and t
* 4 = swap s and t
* 5 = swap s and t, invert s
* 6 = swap s and t, invert t
* 7 = swap s and t, invert s and t
* scaleS - scaling factor for aspect ratio (may be greater than 1.0)
* fuzz - anti-aliasing factor
* Ka, Kd - the usual meanings for matte shading
*
* thanks to the Renderman Repository, the Musgrave site and the Steve May site
* for information and examples of procedural shaders.
*/
surface simpleFace5(
float mouthLevel = 0.35;
float mouthOffset = 0.05;
float mouthWidth = 0.5;
float mouthOpen = 0.02;
float mouthOpacity = 1.0;
float eyeLevel = 0.55;
float eyeOffset = 0.09;
float eyeRadius = 0.05;
float pupilAngle = 0.0;
float pupilOffset = 0.0;
float pupilRadius = 0.025;
color mouthColor = color(0, 0, 0);
color pupilColor = color(0, 0, 1);
color eyeColor = color(1, 1, 1);
color ringColor = color(0, 0, 0);
float faceCenter = 0.5;
float mapCode = 0.0;
float scaleS = 2.0;
float fuzz = 0.0025;
float Ka = 1.0;
float Kd = 1.0;
)
{
color inkColor;
float inkOpacity;
point eyeCenter;
point pupilCenter;
float width;
point mouthPosition;
float mouthPoint, mouthEdge;
float halfOpen, halfWidth;
float d, d1;
float interceptLower, interceptUpper;
color currentColor, finalColor;
color currentOpacity;
point currentPosition;
point Nf;
float eyeLoop;
float invertS = 0;
float invertT = 0;
float mapST = mapCode;
width = eyeRadius / 8; /* width of ring around eye */
/* convert current s,t to a point for distance calculations */
if (mapST < 4.0)
{
currentPosition = ((1 - s) * scaleS, 1 - t, 0);
}
else
{
mapST = mapST - 4;
currentPosition = ((1 - t) * scaleS, 1 - s, 0); /* swap s, t mapping */
}
/* invert s, t mappings if specified */
if (mapST == 1) invertS = 1.0;
if (mapST == 2) invertT = 1.0;
if (mapST == 3)
{
invertS = 1.0;
invertT = 1.0;
}
if (invertS != 0)
{
setxcomp(currentPosition, 1 - xcomp(currentPosition));
}
if (invertT != 0)
{
setycomp(currentPosition, 1 - ycomp(currentPosition));
}
currentOpacity = Os;
currentColor = Cs;
inkColor = Cs;
inkOpacity = 0;
/* two eyes */
for (eyeLoop = 0; eyeLoop < 2; eyeLoop = eyeLoop + 1)
{
if (eyeLoop == 0.0)
{
/* left eye */
eyeCenter = ((faceCenter + eyeOffset), eyeLevel, 0);
}
else
{
/* right eye */
eyeCenter = ((faceCenter - eyeOffset), eyeLevel, 0);
}
d = distance(eyeCenter, currentPosition);
/* check for wrap around */
if (d > eyeRadius + width)
{
d = distance(((xcomp(eyeCenter) + scaleS), eyeLevel, 0), currentPosition);
if (d <= eyeRadius + width)
eyeCenter = ((xcomp(eyeCenter) + scaleS), eyeLevel, 0);
}
if (d > eyeRadius + width)
{
d = distance(((xcomp(eyeCenter) - scaleS), eyeLevel, 0), currentPosition);
if (d <= eyeRadius + width)
eyeCenter = ((xcomp(eyeCenter) - scaleS), eyeLevel, 0);
}
if (d <= eyeRadius + width)
{
if (d <= eyeRadius)
{
pupilCenter = eyeCenter;
setxcomp(pupilCenter, xcomp(pupilCenter) +
(cos(pupilAngle) * pupilOffset));
setycomp(pupilCenter, ycomp(pupilCenter) +
(sin(pupilAngle) * pupilOffset));
d1 = distance(pupilCenter, currentPosition);
if (d1 <= pupilRadius)
{
currentColor = pupilColor;
inkColor = eyeColor;
inkOpacity = smoothstep(pupilRadius - fuzz, pupilRadius, d1);
}
else
{
currentColor = eyeColor;
inkColor = ringColor;
inkOpacity = smoothstep( (eyeRadius - width / 2) - fuzz,
(eyeRadius - width / 2) + fuzz, d) -
smoothstep( (eyeRadius + width / 2) - fuzz,
(eyeRadius + width / 2) + fuzz, d);
}
}
else
{
currentColor = Cs;
inkColor = ringColor;
inkOpacity = smoothstep( (eyeRadius - width / 2) - fuzz,
(eyeRadius - width / 2) + fuzz, d) -
smoothstep( (eyeRadius + width / 2) - fuzz,
(eyeRadius + width / 2) + fuzz, d);
}
}
}
/* mouth */
halfOpen = mouthOpen / 2;
halfWidth = mouthWidth / 2;
mouthPosition = currentPosition;
/* check for wrap-around */
if (faceCenter - halfWidth < 0.0)
{
if (xcomp(mouthPosition) + faceCenter + halfWidth > scaleS)
{
setxcomp(mouthPosition, xcomp(mouthPosition) - scaleS);
}
}
if (faceCenter + halfWidth > scaleS)
{
if (xcomp(mouthPosition) < scaleS - faceCenter)
{
setxcomp(mouthPosition, xcomp(mouthPosition) + scaleS);
}
}
if (xcomp(mouthPosition) >= faceCenter - halfWidth)
{
if (xcomp(mouthPosition) <= faceCenter + halfWidth)
{
mouthPoint = (xcomp(mouthPosition) -
(faceCenter - halfWidth))/ mouthWidth;
mouthEdge = mouthLevel + mouthOffset;
interceptLower = float spline(mouthPoint, mouthEdge, mouthEdge,
mouthLevel - halfOpen, mouthEdge, mouthEdge);
if (ycomp(mouthPosition) >= interceptLower)
{
interceptUpper = float spline(mouthPoint,
mouthEdge, mouthEdge,
mouthLevel + halfOpen,
mouthEdge, mouthEdge);
if (ycomp(mouthPosition) <= interceptUpper)
{
currentColor = Cs;
inkColor = mouthColor;
inkOpacity = smoothstep(interceptLower - fuzz,
interceptLower + fuzz,
ycomp(mouthPosition)) -
smoothstep(interceptUpper - fuzz,
interceptUpper + fuzz,
ycomp(mouthPosition));
currentOpacity = 1.0 -
(inkOpacity * (1.0 - mouthOpacity));
}
}
}
}
finalColor = mix(currentColor, inkColor, inkOpacity);
Nf = faceforward(normalize(N),I);
Ci = Os * finalColor * ( Ka*ambient() + Kd*diffuse(Nf) ) ;
Oi = currentOpacity;
}