ftp.nice.ch/pub/next/graphics/3d/geomview.1.4.1.s.tar.gz#/Geomview/src/bin/geomview/common/shaders.c

This is shaders.c in view mode; [Download] [Up]

/*
 * Software shaders.
 * These operate in the mg environment.
 */
#include "drawer.h"
#include "mgP.h"
#include "3d.h"

#define	DOT(a,b)  ((a).x*(b).x + (a).y*(b).y + (a).z*(b).z)

#define	CCMUL(A,B,C)  ((C).r=(A).r*(B).r, (C).g=(A).g*(B).g, (C).b=(A).b*(B).b)
#define	CCADD(A,B,C)  ((C).r=(A).r+(B).r, (C).g=(A).g+(B).g, (C).b=(A).b+(B).b, (C).a = (A).a + (B).a)

#define CSCALE(s, A, B) ( (B).r = (A).r * s, (B).g = (A).g * s, (B).b = (A).b * s, (B).a = (A).b * s)


#define	CCSADD(A,B,s,C)	\
	 ((C).r += (s)*(A).r*(B).r, \
	  (C).g += (s)*(A).g*(B).g, \
	  (C).b += (s)*(A).b*(B).b)

	/* Eye position as an HPoint3 */
#define	EYE	((HPoint3 *) (_mgc->C2W[3]))



	/* Shading parameters, left here for easy dbx viewing. */
static float fog = 0.0;			/* fog control */
static float hypk1 = .5;		/* controls exponential falloff */
static float hypk2 = .0;		/* controls exponential falloff */
static float sphk1 = .5;		/* controls exponential falloff */
static float sphk2 = 0.0;		/* safety zone around light */

#ifdef notdef
/*
 * Transform a vector covariantly
 */
static void
cotransform(register Transform Tinv, register Point3 *in, Point3 *out)
{
    out->x = Tinv[0][0]*in->x + Tinv[0][1]*in->y + Tinv[0][2]*in->z;
    out->y = Tinv[1][0]*in->x + Tinv[1][1]*in->y + Tinv[1][2]*in->z;
    out->z = Tinv[2][0]*in->x + Tinv[2][1]*in->y + Tinv[2][2]*in->z;
}

/*
 * Euclidean shader
 * This function now lives in the common mg code: src/lib/mg/common/mgshade.c.
 * It's left here, commented out, as an example.
 */
 
static float euck1 = 1.0;		/* inverse power falloff */
static float euck2 = 0.0;		/* safety zone around light */

int mg_eucshade(int nv, HPoint3 *v, Point3 *n, ColorA *c, ColorA *cs)
{
    struct mgxstk *mx = _mgc->xstk;
    struct mgastk *ma = _mgc->astk;
    struct LtLight *l;
    int i;
    HPoint3 V;
    Point3 N, I;
    float s;
    Color Ca;

    euck1 = ma->lighting.attenmult;
    euck2 = ma->lighting.attenmult2;
    fog = ma->lighting.attenconst;

    if(!mx->hasinv) {
	TmInvert(mx->T, mx->Tinv);
	mx->hasinv = 1;
    }

    /* "ambient" color */
    
    Ca.r = Ca.g = Ca.b = 0;
    CCSADD(ma->mat.ambient, ma->lighting.ambient, ma->mat.ka, Ca);

    for(i = 0; i < nv; i++, v++, n++, c++, cs++) {
	ColorA *thiscolor = c;

					/* Transform point by T */
	HPt3Transform(mx->T, v, &V);	/* V = v in world coords */
	HPt3SubPt3(EYE, &V, &I);	/* I = EYE - V (point-to-eye vector) */

					/* Transform normal by T'^-1 */
	cotransform(mx->Tinv, n, &N);
	s = 1/sqrt(DOT(N,N));
	if(DOT(N,I) < 0) {
	    s = -s;			/* Flip normal to face the viewer */

		/* Hack: use otherwise-useless emission color, if defined,
		 * as the back-side material color.
		 */
	    if(ma->mat.valid & MTF_EMISSION)
		thiscolor = (ColorA*)&ma->mat.emission;
	}

	N.x *= s;  N.y *= s;  N.z *= s;
	
					/* Ambient term */
	*(Color *)cs = Ca;

	for(l = ma->lighting.lights; l != NULL; l = l->next) {
	    register Point3 *L;
	    Point3 Lt;
	    float bright, ls, ll, ln, power;

					/* Diffuse term */
	    bright = l->intensity;
	    if(l->globalposition.w == 0) {
		L = (Point3 *)&l->globalposition;
		ll = DOT(*L,*L);
	    } else {
		HPt3SubPt3(&l->globalposition, &V, &Lt);
		L = &Lt;
		ll = DOT(Lt,Lt);
		/* ll = (ll > euck2) ? ll : euck2; */
 		power = pow(ll, -euck1/2.0);
			/* Inverse square falloff */
 		bright *= power;
	    }

	    ln = DOT(*L,N);
	    if(ln <= 0)			/* Ignore lights shining from behind */
		continue;

	    ls = sqrt(ll);
	    s = ma->mat.kd * bright * (ln/ls);
					/* cosine law: L.N diffuse shading */

	    CCSADD(l->color, *thiscolor, s, *cs);

	    if(ma->mat.ks > 0) {	/* Specular term */
		Point3 H;		/* H: halfway between L and I */

		H.x = L->x/ls + I.x, H.y = L->y/ls + I.y, H.z = L->z/ls + I.z;

		s = DOT(H,N) / sqrt(DOT(H,H));
					/* cos angle(H,N) */

			/* Note we need s>=0 for specular term to make sense.
			 * This should be true since we checked
			 * that both L.N and I.N are positive above.
			 */

					/* shininess = specular exponent */
		s = ma->mat.ks * bright * pow(s, ma->mat.shininess);

		CCSADD(l->color, ma->mat.specular, s, *cs);
	    }
	}
	/* insert fog code */
 	if (fog)	{
	    float k1, k2;
	    float d = HPt3Distance(&V, EYE);
	    ColorA surfcolor, fogcolor;
	    d = d - euck2;		/* fog-free sphere of radius euck2 */
	    if (d < 0) d = 0;
	    k1 = exp( -fog * d);
	    k2 = 1.0 - k1;
	    CSCALE(k1, *cs, surfcolor); 
	    CSCALE(k2, _mgc->background, fogcolor); 
	    CCADD(surfcolor, fogcolor, *cs);
	    }
	     
	if(cs->r < 0) cs->r = 0; else if(cs->r > 1) cs->r = 1;
	if(cs->g < 0) cs->g = 0; else if(cs->g > 1) cs->g = 1;
	if(cs->b < 0) cs->b = 0; else if(cs->b > 1) cs->b = 1;
	cs->a = c->a;
    }
    return 0;
}
#endif

#define HPt3R31GramSchmidt	HPt3HypGramSchmidt
#define HPt3R31Distance		HPt3HypDistance

#define HPt3R40GramSchmidt	HPt3SphGramSchmidt
#define HPt3R40Distance		HPt3SphDistance

/*
 * A routine to determine the bisector of two tangent vectors 
 */
void HPt3R31Bisector(HPoint3 *Lt, HPoint3 *I, HPoint3 *H)
{
    HPoint3 tmp1, tmp2;
    float a,b;

    HPt3Sub(I, Lt, &tmp1);
    a = HPt3R31Dot(I, &tmp1); 
    b = HPt3R31Dot(Lt, &tmp1); 
    if ( b == 0) b = 1;
    HPt3Scale(-(a/b), Lt, &tmp2);
    HPt3Add(I, &tmp2, H); 
    if (H->w < 0)   HPt3Scale(-1, H, H);
    return;
}

void HPt3R40Bisector(HPoint3 *Lt, HPoint3 *I, HPoint3 *H)
{
    HPoint3 tmp1, tmp2;
    float a,b;

    HPt3Sub(I, Lt, &tmp1);
    a = HPt3R40Dot(I, &tmp1); 
    b = HPt3R40Dot(Lt, &tmp1); 
    if ( b == 0) b = 1;
    HPt3Scale(-(a/b), Lt, &tmp2);
    HPt3Add(I, &tmp2, H); 
    return;
}

/*
 * Hyperbolic shader
 */

int hypshade(int nv, HPoint3 *v, Point3 *n, ColorA *c, ColorA *cs)
{
    struct mgxstk *mx = _mgc->xstk;
    struct mgastk *ma = _mgc->astk;
    struct LtLight *l;
    int i;
    HPoint3 V, n4, N, I;
    float s, ni, d;
    Color Ca;
    static LtLight *cachedlights = NULL;
    static short cached_light_seq = -1;

    hypk1 = ma->lighting.attenmult;
    hypk2 = ma->lighting.attenmult2;
    fog = ma->lighting.attenconst;

    Ca.r = Ca.g = Ca.b = 0;
    CCSADD(ma->mat.ambient, ma->lighting.ambient, ma->mat.ka, Ca);

    /* for now, move lights to be inside hyperbolic space */
    
    if(ma->light_seq != cached_light_seq) {
	LtDeletelist(cachedlights);
	cachedlights = LtCopylist(ma->lighting.lights, 0);
	for(l = cachedlights; l != NULL; l = l->next) {
	    /* use euclidean distance */
	    register HPoint3 *L = &l->globalposition;
	    float d = HPt3R30Dot(L, L);
	    if (d == 0) d = 1;
	    if (d > 1) 	{ 	/* move light to sphere of radius .8 */
		d = .8/sqrt(d);	
		L->x *= d;
		L->y *= d;
		L->z *= d;
		L->w = 1.0;
	    }
	}
	cached_light_seq = ma->light_seq;
    }

    for(i = 0; i < nv; i++, v++, n++, c++, cs++) {

					/* Transform point by T */
	HPt3Transform(mx->T, v, &V);	/* V = v in world coords */
	if ((d = HPt3R31Dot(&V, &V)) >= 0)  /* point at infinity, or beyond */
		continue;		/* outside hyperbolic space */
	HPt3R31Normalize(&V);		/* lie on surface < , > = -1 */

	HPt3Sub( (HPoint3 *) EYE, &V, &I );	/* I = EYE - V (point-to-eye vector) */
	HPt3R31GramSchmidt(&V, &I);
	HPt3R31Normalize(&I);

        n4.x = n->x; n4.y = n->y; n4.z = n->z; n4.w = 1.0;
    	HPt3R31GramSchmidt( v, &n4);
    	HPt3R31Normalize(&n4);

	HPt3Transform(mx->T, &n4, &N);/* transform by inverse adjoint */

	/* tangent space at V has a Euclidean (positive definite) structure */
	ni = HPt3R31Dot(&N,&I);
	if (ni < 0)  
	    {		
	    float s = -1.0;
	    HPt3Scale(s, &N, &N);
	    }
		
	cs->r = Ca.r; cs->g = Ca.g;  cs->b = Ca.b;

	for(l = cachedlights; l != NULL; l = l->next) {
	    register HPoint3 *L;
	    HPoint3 Lt;
	    float bright, ll, ln, light_intensity, d;

	    L = &l->globalposition;
					/* Diffuse term */
	    /* first compute the color of arriving light */
	    bright = l->intensity;
	    ll = HPt3R31Dot(L,L);
	    if (ll >= 0)		/* ignore lights outside of hspace */
		continue;
	    ln = HPt3R31Dot(L,&N);
	    if(ln <= 0)			/* Ignore lights shining from behind */
		continue;
	    /* compute the distance for computation of falloff of light */
	    d = HPt3R31Distance(L, &V);
	    /* the following models the exponential falloff of intensity */
	    light_intensity = exp(-hypk1*d);
	
	    /* now compute the cosine for diffuse shading */
	    Lt = l->globalposition;	/* we'll change the values here */
	    HPt3Sub(&Lt, &V, &Lt);	/* make it a difference vector */
	    HPt3R31GramSchmidt(&V, &Lt);
	    HPt3R31Normalize(&Lt);
	    d = HPt3R31Dot(&Lt, &N);	/* cos of angle between L and N */

	    s = ma->mat.kd * bright * d * light_intensity;
					
	    CCSADD(l->color, *c, s, *cs);

	    if(ma->mat.ks > 0) {	/* Specular term */
		HPoint3 H;		/* H: halfway between L and I */

	 	HPt3R31Bisector(&Lt, &I, &H);
		HPt3R31Normalize(&H);

		s = HPt3R31Dot(&H, &N); /* cos of angle between H and N */
		if (s < 0) continue;

		s = ma->mat.ks * bright * pow(s, ma->mat.shininess);

		CCSADD(l->color, ma->mat.specular, s, *cs);
	    }
	} 
	/* insert fog code */
 	if (fog)	{
	    float k1, k2;
	    float d = HPt3HypDistance(&V, EYE);
	    ColorA surfcolor, fogcolor;
	    d = d - hypk2;		/* fog-free sphere of radius euck2 */
	    if (d < 0) d = 0;
	    k1 = exp( -fog * d);
	    k2 = 1.0 - k1;
	    CSCALE(k1, *cs, surfcolor); 
	    CSCALE(k2, _mgc->background, fogcolor); 
	    CCADD(surfcolor, fogcolor, *cs);
	    }
	if(cs->r < 0) cs->r = 0; else if(cs->r > 1) cs->r = 1;
	if(cs->g < 0) cs->g = 0; else if(cs->g > 1) cs->g = 1;
	if(cs->b < 0) cs->b = 0; else if(cs->b > 1) cs->b = 1;
	cs->a = c->a;
    }
    return 0;
}

int sphshade(int nv, HPoint3 *v, Point3 *n, ColorA *c, ColorA *cs)
{
    struct mgxstk *mx = _mgc->xstk;
    struct mgastk *ma = _mgc->astk;
    struct LtLight *l;
    int i;
    HPoint3 V, n4, N, I;
    float s, ni;
    Color Ca;
    static LtLight *cachedlights = NULL;
    static short cached_light_seq = -1;

    sphk1 = ma->lighting.attenmult;
    sphk2 = ma->lighting.attenmult2;
    fog = ma->lighting.attenconst;

    /* "ambient" color */
    
    Ca.r = Ca.g = Ca.b = 0;
    CCSADD(ma->mat.ambient, ma->lighting.ambient, ma->mat.ka, Ca);

    /* for now, move lights to be inside spherical space */
    if(ma->light_seq != cached_light_seq) {
	LtDeletelist(cachedlights);
	cachedlights = LtCopylist(ma->lighting.lights, 0);
	for(l = ma->lighting.lights; l != NULL; l = l->next) {
	  float d;
	  register HPoint3 *L;
	  L = &l->globalposition;
	  /* use euclidean distance */
	  d = HPt3R40Dot(L, L);
	  if (d == 0) d = 1;
	  if (d >= 1.0) { 	/* move light to be in S3 */
	      d = 1.0/sqrt(d);	
	      L->x *= d;
	      L->y *= d;
	      L->z *= d;
	      L->w *= d;
	  }
	}
	cached_light_seq = ma->light_seq;
    }

    for(i = 0; i < nv; i++, v++, n++, c++, cs++) {

					/* Transform point by T */
	HPt3Transform(mx->T, v, &V);	/* V = v in world coords */
	HPt3R40Normalize(&V);		/* lie on surface < , > = -1 */
					/* I = EYE - V (point-to-eye vector) */
	HPt3Sub(  (HPoint3 *) EYE, &V, &I );	
	HPt3R40GramSchmidt(&V, &I);
	HPt3R40Normalize(&I);

        n4.x = n->x; n4.y = n->y; n4.z = n->z; n4.w = 1.0;
    	HPt3R40GramSchmidt( v, &n4);
    	HPt3R40Normalize(&n4);

	HPt3Transform(mx->T, &n4, &N);/* transform by inverse adjoint */

	/* tangent space at V has a Euclidean (positive definite) structure */
	ni = HPt3R40Dot(&N,&I);
	if (ni < 0)  
	    {		
	    float s = -1.0;
	    HPt3Scale(s, &N, &N);
	    }
		
	cs->r = Ca.r; cs->g = Ca.g;  cs->b = Ca.b;

	for(l = ma->lighting.lights; l != NULL; l = l->next) {
	    register HPoint3 *L;
	    HPoint3 Lt;
	    float bright, ln, d, radius, light_intensity;

	    L = &l->globalposition;
					/* Diffuse term */
	    /* first compute the color of arriving light */
	    bright = l->intensity;
	    /*ll = HPt3R40Dot(L,L);*/	/* this should be 1.0 by above */
	    ln = HPt3R40Dot(L,&N);
	    if(ln <= 0)			/* Ignore lights shining from behind */
		continue;
	    /* compute the distance for computation of falloff of light */
	    d = HPt3R40Distance(L, &V);
	    /* the amount of light from the source which arrives at
	    the surface is inversely proportional to the area 
	    of the sphere centered at the light which contains 
	    the surface point. The radius of this sphere is the sin
	    of the distance between L and V */
	    radius = sin((double) d);
	    if (radius > sphk2)
		{
		float kk = (sphk2/radius);	/* 0 <= sphk2 <= 1.0 */
	        light_intensity = pow(kk, -sphk1);
		}
	    else light_intensity = 1.0;
	    /* we model the atmosphere as a murky fluid that has exponential
	    dissipation; sphk1 controls exponential drop off; value of 0
	    avoids any drop off */
	    d = HPt3R40Distance((HPoint3 *) EYE, &V);
	    light_intensity *= exp(-sphk1 * d);
	
	    /* now compute the cosine for diffuse shading */
	    Lt = l->globalposition;	/* we'll change the values here */
	    HPt3Sub(&Lt, &V, &Lt);	/* make it a difference vector */
	    HPt3R40GramSchmidt(&V, &Lt);
	    HPt3R40Normalize(&Lt);
	    d = HPt3R40Dot(&Lt, &N);	/* cos of angle between L and N */

	    s = ma->mat.kd * bright * d * light_intensity;
					
	    CCSADD(l->color, *c, s, *cs);

	    if(ma->mat.ks > 0) {	/* Specular term */
		HPoint3 H;		/* H: halfway between L and I */

	 	HPt3R40Bisector(&Lt, &I, &H);
		HPt3R40Normalize(&H);

		s = HPt3R40Dot(&H, &N); /* cos of angle between H and N */
		if (s < 0) continue;

		s = ma->mat.ks * bright * pow(s, ma->mat.shininess);

		CCSADD(l->color, ma->mat.specular, s, *cs);
	    }
	}
	/* insert fog code */
 	if (fog)	{
	    float k1, k2;
	    float d = HPt3SphDistance(&V, EYE);
	    ColorA surfcolor, fogcolor;

	    d = d - sphk2;		/* fog-free sphere of radius euck2 */
	    if (d < 0) d = 0;
	    k1 = exp( -fog * d);
	    k2 = 1.0 - k1;
	    CSCALE(k1, *cs, surfcolor); 
	    CSCALE(k2, _mgc->background, fogcolor); 
	    CCADD(surfcolor, fogcolor, *cs);
	    }
	if(cs->r < 0) cs->r = 0; else if(cs->r > 1) cs->r = 1;
	if(cs->g < 0) cs->g = 0; else if(cs->g > 1) cs->g = 1;
	if(cs->b < 0) cs->b = 0; else if(cs->b > 1) cs->b = 1;
	cs->a = c->a;
    }
    return 0;
}


mgshadefunc
softshader(int camid)
{
    switch(spaceof(camid)) {
    case TM_HYPERBOLIC: return hypshade;
    case TM_EUCLIDEAN: return mg_eucshade;
    case TM_SPHERICAL: return sphshade;
    default: return mg_eucshade;
    }
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.