/* @(#)texmap.sl 1.4 (Pixar - RenderMan Division) 5/7/90 */
/*-______________________________________________________________________
**
** Copyright (c) 1989 PIXAR. All rights reserved. This program or
** documentation contains proprietary confidential information and trade
** secrets of PIXAR. Reverse engineering of object code is prohibited.
** Use of copyright notice is precautionary and does not imply
** publication.
**
** RESTRICTED RIGHTS NOTICE
**
** Use, duplication, or disclosure by the Government is subject to the
** following restrictions: For civilian agencies, subparagraphs (a) through
** (d) of the Commercial Computer Software--Restricted Rights clause at
** 52.227-19 of the FAR; and, for units of the Department of Defense, DoD
** Supplement to the FAR, clause 52.227-7013 (c)(1)(ii), Rights in
** Technical Data and Computer Software.
**
** Pixar
** 3240 Kerner Blvd.
** San Rafael, CA 94901
**
** ______________________________________________________________________
*/
/*----------------------------------------------------------------------------
* texmap - texture-map shader
*
* Puts a texture map onto a surface. Can have 3 different projection
* types or standard mapping.
*
* texname - the name of the texture file
* maptype - the type of mapping (0 for planar, 1 for cylinder, 2 for sphere,
* 3 for "standard" mapping using textcoords)
* maporigin - the center of the projection.
* xaxis, yaxis, zaxis - 3 points defining the orientation of the projection.
* Subtracting maporigin from each of these gives the appropriate axis.
* s1,t1,... - corner points for parameter mapping as in textcoords
* Ka, Kd, Ks, roughness, specularcolor - the usual meaning
*---------------------------------------------------------------------------*/
/*
* This file contains functions to perform decal mapping, which is especially
* useful for putting texture maps onto surfaces consisting of many small
* polygons.
*
* Major function is decalmap, which calls the mapping functions:
* cylinmap, planemap, sphermap, automap (and bilerp).
*
*/
/*----------------------------------------------------------------------
*
* bilerp does a bilinear interpolation of one number between the
* four given corners in texture space to the given point in parameter
* space.
*
* uu,vv - point in parameter space
* x1,x2,x3,x4 - corners in texture space
*
*--------------------------------------------------------------------*/
float
bilerp(float uu,vv,x1,x2,x3,x4)
{
varying float left, right;
left = x1 + uu * (x2 - x1);
right = x3+ uu * (x4 - x3);
return(left + vv * (right - left));
}
/*----------------------------------------------------------------------
*
* cylinmap performs a cylindrical projection to create texture coordinates
* uu and vv
*
* p - point on surface to be projected
* uu,vv - new projected coordinates
* maporigin - the bottom point of the center axis of the cylindrical proj.
* xaxis, yaxis, zaxis - 3 points defining the coordinate system of
* the cylinder. The central axis is along zaxis-maporigin.
* The point on the equator where (uu,vv)==(0,0) is mapped is at xaxis.
*--------------------------------------------------------------------*/
float cylinmap(point p;
float uu,vv;
point maporigin, xaxis, yaxis, zaxis)
{
varying vector V,Vn,
XX, YY, ZZ;
varying float xx, yy;
V = p - maporigin;
Vn = normalize(V);
XX = normalize(xaxis - maporigin);
YY = normalize(yaxis - maporigin);
ZZ = normalize(zaxis - maporigin);
xx = Vn.XX;
yy = Vn.YY;
vv = V.ZZ;
uu = atan(yy, xx) / (2*PI); /* -.5 -> .5 */
uu = uu + step(0,-uu); /* remaps to 0 -> 1 */
}
/*---------------------------------------------------------------------
* planemap performs a planar projection to create texture coordinates
* uu and vv
*
* p - point on surface to be projected
* uu,vv - new projected coordinates
* maporigin, xaxis, yaxis - The projection is performed as if the texture
* map were placed with (uu,vv)==(0,0) at 'maporigin', uu==0 along
* yaxis-maporigin and vv==0 along xaxis-maporigin. The map is then
* projected parallel to itself onto the surface.
*--------------------------------------------------------------------*/
float planemap(point p;
float uu,vv;
point maporigin, xaxis, yaxis)
{
varying vector V,
XX, YY;
varying float xx, yy;
V = p - maporigin;
XX = normalize(xaxis - maporigin);
YY = normalize(yaxis - maporigin);
uu = V.XX;
vv = V.YY;
}
/*--------------------------------------------------------------------
*
* sphermap performs a spherical projection to create texture coordinates
* uu and vv
*
* p - point on surface to be projected
* uu,vv - new projected coordinates
* maporigin - the center of the spherical projection.
* xaxis, yaxis, zaxis - 3 points defining the coordinate system of
* the sphere. The north pole is at zaxis.
* The point on the equator where uu==0 is mapped is at xaxis.
*--------------------------------------------------------------------*/
float sphermap(point p;
float uu,vv;
point maporigin, xaxis, yaxis, zaxis)
{
varying vector V,
XX, YY, ZZ;
varying float xx, yy, zz;
V = normalize(p - maporigin);
XX = normalize(xaxis - maporigin);
YY = normalize(yaxis - maporigin);
ZZ = normalize(zaxis - maporigin);
xx = V.XX;
yy = V.YY;
zz = V.ZZ;
uu = atan(yy, xx) / (2*PI); /* -.5 -> .5 */
uu = uu + step(0,-uu); /* remaps to 0 -> 1 */
vv = acos(-zz) / PI;
}
/*---------------------------------------------------------------------
* automap performs a planar projection using the normal to the surface
* as the normal to the plane to create texture coordinates
* uu and vv
* NOTE: this will only work very well on faceted (polygonal or bilinear)
* surfaces.
*
* p - point on surface to be projected
* uu,vv - new projected coordinates
* maporigin, yaxis - The projection is performed as if the texture
* map were placed with (uu,vv)==(0,0) at 'maporigin', uu==0 along
* yaxis-maporigin and vv==0 along the vector perpendicular to
* both yaxis-maporigin and the normal to the surface. The map is
* then projected parallel to itself onto the surface. This has
* the effect of giving each facet of a surface a separate planar
* projection. This will work better for periodic textures than
* for non-periodic textures. For surfaces that are perpendicular
* to the yaxis-maporigin vector, a reasonable guess at a good
* "up" vector is attempted.
* n - surface normal
*--------------------------------------------------------------------*/
float automap(point p;
float uu,vv;
point maporigin, yaxis, n)
{
varying vector V,
XX, YY, ZZ;
varying float xx, yy,
dot;
uniform vector yvector, zvector;
/*
* The yvector and zvector are the axes of shader space, but expressed
* in shader space coordinates, not in current coordinates, so no
* space conversion is required. Everything else has already been
* put into shader space coordinates by the callers of this routine.
*/
yvector = point (0,1,0);
zvector = point (0,0,1);
V = p - maporigin;
ZZ = normalize(n);
YY = normalize(yaxis - maporigin);
dot = ZZ . YY;
/* if "up" (YY) vector parallel to "at" (ZZ) vector, find new "up" */
if ((dot > (1-0.01))||(dot < (-1+0.01))) {
dot = ZZ . yvector;
if ((dot > (1-0.01))||(dot < (-1+0.01))) YY = zvector;
else YY = yvector;
}
/* get orthogonal coordinate system */
XX = YY ^ ZZ;
YY = ZZ ^ XX;
uu = V.XX;
vv = V.YY;
}
/*--------------------------------------------------------------------
*
* decalmap - perform decal mapping. Calls one of the above mapping functions.
*
* p - point on surface
* s, t - unmapped texture coordinates
* ss, tt - returned mapped texture coordinates
* maptype - the type of mapping (0 for planar, 1 for cylinder, 2 for sphere,
* 3 for "standard" mapping using textcoords, 4 for "auto-planar"
* mapping - planar perpendicular to surface normal)
* maporigin - the center of the projection.
* xaxis, yaxis, zaxis - a local coordinate system that defines the
* orientation of the projection.
* s1,t1,... - corner points for parameter mapping as in textcoords
* n - normal to the surface
*--------------------------------------------------------------------*/
float decalmap(point p;
float s,t;
float ss, tt;
float maptype;
point maporigin, xaxis, yaxis, zaxis;
float s1,t1,s2,t2,s3,t3,s4,t4;
varying point n)
{
varying float uu, vv;
if (maptype == 0) {
planemap(p, uu, vv, maporigin, xaxis, yaxis);
} else if (maptype == 1) {
cylinmap(p, uu, vv, maporigin, xaxis, yaxis, zaxis);
} else if (maptype == 2) {
sphermap(p, uu, vv, maporigin, xaxis, yaxis, zaxis);
} else if (maptype == 4) {
automap(p, uu, vv, maporigin, yaxis, n);
}
if (maptype != 3) {
/* bilinear interpolation to get texture parameters */
ss=bilerp(uu,vv,s1,s2,s3,s4);
tt=bilerp(uu,vv,t1,t2,t3,t4);
} else {
ss = s;
tt = t;
}
}
surface
texmap(string texname = "";
float maptype=3;
point maporigin=point "shader" (0,0,0),
xaxis=point "shader" (1,0,0), yaxis=point "shader" (0,1,0),
zaxis=point "shader" (0,0,1);
float s1=0,t1=0,s2=1,t2=0,s3=0,t3=1,s4=1,t4=1;
float Ka=1, Kd=1, Ks=0, roughness=.25;
color specularcolor = 1)
{
uniform float ssize, tsize;
varying vector Nf, NI;
varying point PP,O,X,Y,Z,NN;
varying color ctx;
varying float ss,tt,ds,dsu,dsv,dt,dtu,dtv;
/* calculate size of st space for boundary check and correction */
if(s1 < s2) ssize = s2 - s1;
else ssize = s1 - s2;
if(t1 < t2) tsize = t2 - t1;
else tsize = t1 - t2;
/* do projection in shader space */
PP=transform("shader",P);
O=transform("shader",maporigin);
X=transform("shader",xaxis);
Y=transform("shader",yaxis);
Z=transform("shader",zaxis);
NN=normalize(transform("shader",N)-transform("shader",(0,0,0)));
decalmap(PP,s,t,ss,tt,maptype,O,X,Y,Z,s1,t1,s2,t2,s3,t3,s4,t4,NN);
Nf = faceforward( normalize(N), I);
/*
* If we allow the texture coordinates to wrap around we will get
* incorrect behavior at the boundaries between max and min value.
* To avoid this we correct for the boundary crossing condition. We
* compute the texture coordinate and check if we cross the boundary.
* The current check is a kludge which relies on the "fact" that
* the size of a micropolygon is less than half the total texture
* space size, but if the coordinates warp around the delta
* is greater than half the total texture space size. If we have
* crossed the boundary we adjust the filter width accordingly.
*/
dsu = abs(Du(ss)*du);
if((2*dsu) > ssize) dsu = ssize - dsu;
dsv = abs(Dv(ss)*dv);
if((2*dsv) > ssize) dsv = ssize - dsv;
ds = dsu + dsv;
dtu = abs(Du(tt)*du);
if((2*dtu) > tsize) dtu = tsize - dtu;
dtv = abs(Dv(tt)*dv);
if((2*dtv) > tsize) dtv = tsize - dtv;
dt = dtu + dtv;
if (texname == "")
ctx = 1;
else
ctx = texture(texname,ss,tt, ss+ds,tt, ss,tt+dt, ss+ds,tt+dt);
Ci = (Ka*ambient() + Kd*diffuse(Nf)) * ctx;
if (Ks != 0.0)
{
NI = normalize(-I);
Ci += Ks*specularcolor*specular(Nf,NI,roughness);
}
Oi = Os;
Ci = Ci * Oi;
}