Back to index

radiance  4R0+20100331
m_mirror.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: m_mirror.c,v 2.12 2009/06/06 02:11:43 greg Exp $";
00003 #endif
00004 /*
00005  * Routines for mirror material supporting virtual light sources
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include  "ray.h"
00011 #include  "otypes.h"
00012 #include  "rtotypes.h"
00013 #include  "source.h"
00014 
00015 /*
00016  * The real arguments for MAT_MIRROR are simply:
00017  *
00018  *     3 rrefl grefl brefl
00019  *
00020  * Additionally, the user may specify a single string argument
00021  * which is interpreted as the name of the material to use
00022  * instead of the mirror if the ray being considered is not
00023  * part of the direct calculation.
00024  */
00025 
00026 static int mir_proj(MAT4  pm, OBJREC  *o, SRCREC  *s, int  n);
00027 static void mirrorproj(MAT4  m, FVECT  nv, double  offs);
00028 
00029 VSMATERIAL  mirror_vs = {mir_proj, 1};
00030 
00031 
00032 extern int
00033 m_mirror(                   /* shade mirrored ray */
00034        register OBJREC  *m,
00035        register RAY  *r
00036 )
00037 {
00038        COLOR  mcolor;
00039        RAY  nr;
00040        int  rpure = 1;
00041        register int  i;
00042                                    /* check arguments */
00043        if (m->oargs.nfargs != 3 || m->oargs.nsargs > 1)
00044               objerror(m, USER, "bad number of arguments");
00045                                    /* check for substitute material */
00046        if (m->oargs.nsargs > 0 &&
00047                      (r->rsrc < 0 || source[r->rsrc].so != r->ro)) {
00048               if (!strcmp(m->oargs.sarg[0], VOIDID)) {
00049                      raytrans(r);
00050                      return(1);
00051               }
00052               return(rayshade(r, lastmod(objndx(m), m->oargs.sarg[0])));
00053        }
00054                                    /* check for bad source ray */
00055        if (r->rsrc >= 0 && source[r->rsrc].so != r->ro)
00056               return(1);
00057 
00058        if (r->rod < 0.)            /* back is black */
00059               return(1);
00060                                    /* get modifiers */
00061        raytexture(r, m->omod);
00062                                    /* assign material color */
00063        setcolor(mcolor, m->oargs.farg[0],
00064                      m->oargs.farg[1],
00065                      m->oargs.farg[2]);
00066        multcolor(mcolor, r->pcol);
00067                                    /* compute reflected ray */
00068        if (r->rsrc >= 0) {                /* relayed light source */
00069               rayorigin(&nr, REFLECTED, r, mcolor);
00070                                    /* ignore textures */
00071               for (i = 0; i < 3; i++)
00072                      nr.rdir[i] = r->rdir[i] + 2.*r->rod*r->ron[i];
00073                                    /* source we're aiming for next */
00074               nr.rsrc = source[r->rsrc].sa.sv.sn;
00075        } else {                           /* ordinary reflection */
00076               FVECT  pnorm;
00077               double  pdot;
00078 
00079               if (rayorigin(&nr, REFLECTED, r, mcolor) < 0)
00080                      return(1);
00081               if (DOT(r->pert,r->pert) > FTINY*FTINY) {
00082                      pdot = raynormal(pnorm, r); /* use textures */
00083                      for (i = 0; i < 3; i++)
00084                             nr.rdir[i] = r->rdir[i] + 2.*pdot*pnorm[i];
00085                      rpure = 0;
00086               }
00087                                           /* check for penetration */
00088               if (rpure || DOT(nr.rdir, r->ron) <= FTINY)
00089                      for (i = 0; i < 3; i++)
00090                             nr.rdir[i] = r->rdir[i] + 2.*r->rod*r->ron[i];
00091        }
00092        rayvalue(&nr);
00093        multcolor(nr.rcol, nr.rcoef);
00094        addcolor(r->rcol, nr.rcol);
00095        if (rpure && r->ro != NULL && isflat(r->ro->otype))
00096               r->rt = r->rot + nr.rt;
00097        return(1);
00098 }
00099 
00100 
00101 static int
00102 mir_proj(            /* compute a mirror's projection */
00103        MAT4  pm,
00104        register OBJREC  *o,
00105        SRCREC  *s,
00106        int  n
00107 )
00108 {
00109        double corr = 1.;
00110        FVECT  nv, sc;
00111        double  od, offs;
00112        int  i;
00113                             /* get surface normal and offset */
00114        offs = od = getplaneq(nv, o);
00115        if (s->sflags & SDISTANT)
00116               offs = 0.;
00117                             /* check for extreme point behind */
00118        if (s->sflags & SCIR) {
00119               if (s->sflags & (SFLAT|SDISTANT))
00120                      corr = 1.12837917;   /* correct setflatss() */
00121               else
00122                      corr = 1.0/0.7236;   /* correct sphsetsrc() */
00123        }
00124        VCOPY(sc, s->sloc);
00125        for (i = s->sflags & SFLAT ? SV : SW; i >= 0; i--)
00126               if (DOT(nv, s->ss[i]) > offs)
00127                      VSUM(sc, sc, s->ss[i], corr);
00128               else
00129                      VSUM(sc, sc, s->ss[i], -corr);
00130        if (DOT(sc, nv) <= offs+FTINY)
00131               return(0);
00132                             /* everything OK -- compute projection */
00133        mirrorproj(pm, nv, od);
00134        return(1);
00135 }
00136 
00137 
00138 static void
00139 mirrorproj(          /* get mirror projection for surface */
00140        register MAT4  m,
00141        FVECT  nv,
00142        double  offs
00143 )
00144 {
00145        register int  i, j;
00146                                    /* assign matrix */
00147        setident4(m);
00148        for (j = 0; j < 3; j++) {
00149               for (i = 0; i < 3; i++)
00150                      m[i][j] -= 2.*nv[i]*nv[j];
00151               m[3][j] = 2.*offs*nv[j];
00152        }
00153 }