ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/normal.c
Revision: 2.25
Committed: Thu May 27 15:28:03 1993 UTC (30 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.24: +3 -15 lines
Log Message:
removed approximation to Fresnel reflection, since the direct
component was not being calculated accordingly (BRDF not bidirectional)
changed BRDTfunc arguments and operation, fixed one or two bugs there also

File Contents

# User Rev Content
1 greg 2.2 /* Copyright (c) 1992 Regents of the University of California */
2 greg 1.1
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * normal.c - shading function for normal materials.
9     *
10     * 8/19/85
11     * 12/19/85 - added stuff for metals.
12     * 6/26/87 - improved specular model.
13     * 9/28/87 - added model for translucent materials.
14 greg 2.2 * Later changes described in delta comments.
15 greg 1.1 */
16    
17     #include "ray.h"
18    
19     #include "otypes.h"
20    
21 greg 2.2 #include "random.h"
22    
23 greg 2.5 extern double specthresh; /* specular sampling threshold */
24     extern double specjitter; /* specular sampling jitter */
25    
26 greg 2.24 static gaussamp();
27    
28 greg 1.1 /*
29 greg 2.22 * This routine implements the isotropic Gaussian
30     * model described by Ward in Siggraph `92 article.
31 greg 1.1 * We orient the surface towards the incoming ray, so a single
32     * surface can be used to represent an infinitely thin object.
33     *
34     * Arguments for MAT_PLASTIC and MAT_METAL are:
35     * red grn blu specular-frac. facet-slope
36     *
37     * Arguments for MAT_TRANS are:
38     * red grn blu rspec rough trans tspec
39     */
40    
41 greg 2.2 /* specularity flags */
42     #define SP_REFL 01 /* has reflected specular component */
43     #define SP_TRAN 02 /* has transmitted specular */
44 greg 2.11 #define SP_PURE 04 /* purely specular (zero roughness) */
45     #define SP_FLAT 010 /* flat reflecting surface */
46     #define SP_RBLT 020 /* reflection below sample threshold */
47     #define SP_TBLT 040 /* transmission below threshold */
48 greg 1.1
49 greg 1.3 typedef struct {
50     OBJREC *mp; /* material pointer */
51 greg 2.16 RAY *rp; /* ray pointer */
52 greg 2.2 short specfl; /* specularity flags, defined above */
53 greg 1.1 COLOR mcolor; /* color of this material */
54     COLOR scolor; /* color of specular component */
55     FVECT vrefl; /* vector in direction of reflected ray */
56 greg 1.14 FVECT prdir; /* vector in transmitted direction */
57 greg 2.2 double alpha2; /* roughness squared */
58 greg 1.1 double rdiff, rspec; /* reflected specular, diffuse */
59     double trans; /* transmissivity */
60     double tdiff, tspec; /* transmitted specular, diffuse */
61     FVECT pnorm; /* perturbed surface normal */
62     double pdot; /* perturbed dot product */
63 greg 1.3 } NORMDAT; /* normal material data */
64    
65    
66     dirnorm(cval, np, ldir, omega) /* compute source contribution */
67     COLOR cval; /* returned coefficient */
68     register NORMDAT *np; /* material data */
69     FVECT ldir; /* light source direction */
70     double omega; /* light source size */
71     {
72 greg 1.1 double ldot;
73 greg 2.16 double dtmp, d2;
74     FVECT vtmp;
75 greg 1.3 COLOR ctmp;
76    
77     setcolor(cval, 0.0, 0.0, 0.0);
78    
79     ldot = DOT(np->pnorm, ldir);
80    
81     if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY)
82     return; /* wrong side */
83    
84     if (ldot > FTINY && np->rdiff > FTINY) {
85     /*
86 greg 1.4 * Compute and add diffuse reflected component to returned
87     * color. The diffuse reflected component will always be
88     * modified by the color of the material.
89 greg 1.3 */
90     copycolor(ctmp, np->mcolor);
91     dtmp = ldot * omega * np->rdiff / PI;
92     scalecolor(ctmp, dtmp);
93     addcolor(cval, ctmp);
94     }
95 greg 2.2 if (ldot > FTINY && (np->specfl&(SP_REFL|SP_PURE)) == SP_REFL) {
96 greg 1.3 /*
97     * Compute specular reflection coefficient using
98     * gaussian distribution model.
99     */
100 greg 2.3 /* roughness */
101 greg 2.16 dtmp = np->alpha2;
102 greg 2.3 /* + source if flat */
103     if (np->specfl & SP_FLAT)
104 greg 2.16 dtmp += omega/(4.0*PI);
105 greg 2.23 /* half vector */
106 greg 2.18 vtmp[0] = ldir[0] - np->rp->rdir[0];
107     vtmp[1] = ldir[1] - np->rp->rdir[1];
108     vtmp[2] = ldir[2] - np->rp->rdir[2];
109 greg 2.16 d2 = DOT(vtmp, np->pnorm);
110 greg 2.23 d2 *= d2;
111     d2 = (DOT(vtmp,vtmp) - d2) / d2;
112 greg 1.3 /* gaussian */
113 greg 2.16 dtmp = exp(-d2/dtmp)/(4.*PI*dtmp);
114 greg 1.3 /* worth using? */
115     if (dtmp > FTINY) {
116     copycolor(ctmp, np->scolor);
117 greg 2.14 dtmp *= omega * sqrt(ldot/np->pdot);
118 greg 1.3 scalecolor(ctmp, dtmp);
119     addcolor(cval, ctmp);
120     }
121     }
122     if (ldot < -FTINY && np->tdiff > FTINY) {
123     /*
124     * Compute diffuse transmission.
125     */
126     copycolor(ctmp, np->mcolor);
127     dtmp = -ldot * omega * np->tdiff / PI;
128     scalecolor(ctmp, dtmp);
129     addcolor(cval, ctmp);
130     }
131 greg 2.2 if (ldot < -FTINY && (np->specfl&(SP_TRAN|SP_PURE)) == SP_TRAN) {
132 greg 1.3 /*
133 greg 1.4 * Compute specular transmission. Specular transmission
134 greg 1.13 * is always modified by material color.
135 greg 1.3 */
136     /* roughness + source */
137 greg 2.19 dtmp = np->alpha2 + omega/PI;
138 greg 1.3 /* gaussian */
139 greg 2.21 dtmp = exp((2.*DOT(np->prdir,ldir)-2.)/dtmp)/(PI*dtmp);
140 greg 1.3 /* worth using? */
141     if (dtmp > FTINY) {
142 greg 1.13 copycolor(ctmp, np->mcolor);
143 greg 2.18 dtmp *= np->tspec * omega * sqrt(-ldot/np->pdot);
144 greg 1.13 scalecolor(ctmp, dtmp);
145 greg 1.3 addcolor(cval, ctmp);
146     }
147     }
148     }
149    
150    
151 greg 2.2 m_normal(m, r) /* color a ray that hit something normal */
152 greg 1.3 register OBJREC *m;
153     register RAY *r;
154     {
155     NORMDAT nd;
156 greg 1.9 double transtest, transdist;
157 greg 1.1 COLOR ctmp;
158     register int i;
159     /* easy shadow test */
160     if (r->crtype & SHADOW && m->otype != MAT_TRANS)
161     return;
162 greg 2.2
163     if (m->oargs.nfargs != (m->otype == MAT_TRANS ? 7 : 5))
164     objerror(m, USER, "bad number of arguments");
165 greg 1.3 nd.mp = m;
166 greg 2.16 nd.rp = r;
167 greg 1.1 /* get material color */
168 greg 1.3 setcolor(nd.mcolor, m->oargs.farg[0],
169 greg 1.1 m->oargs.farg[1],
170     m->oargs.farg[2]);
171     /* get roughness */
172 greg 2.2 nd.specfl = 0;
173 greg 1.3 nd.alpha2 = m->oargs.farg[4];
174 greg 2.2 if ((nd.alpha2 *= nd.alpha2) <= FTINY)
175     nd.specfl |= SP_PURE;
176 greg 1.1 /* reorient if necessary */
177     if (r->rod < 0.0)
178     flipsurface(r);
179     /* get modifiers */
180     raytexture(r, m->omod);
181 greg 1.3 nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */
182 greg 1.13 if (nd.pdot < .001)
183     nd.pdot = .001; /* non-zero for dirnorm() */
184 greg 1.3 multcolor(nd.mcolor, r->pcol); /* modify material color */
185 greg 1.9 transtest = 0;
186 greg 1.1 /* get specular component */
187 greg 2.2 if ((nd.rspec = m->oargs.farg[3]) > FTINY) {
188     nd.specfl |= SP_REFL;
189 greg 1.1 /* compute specular color */
190     if (m->otype == MAT_METAL)
191 greg 1.3 copycolor(nd.scolor, nd.mcolor);
192 greg 1.1 else
193 greg 1.3 setcolor(nd.scolor, 1.0, 1.0, 1.0);
194     scalecolor(nd.scolor, nd.rspec);
195 greg 2.15 /* check threshold */
196 greg 2.25 if (!(nd.specfl & SP_PURE) && specthresh >= nd.rspec-FTINY)
197 greg 2.5 nd.specfl |= SP_RBLT;
198 greg 1.1 /* compute reflected ray */
199     for (i = 0; i < 3; i++)
200 greg 1.3 nd.vrefl[i] = r->rdir[i] + 2.0*nd.pdot*nd.pnorm[i];
201 greg 2.7 if (DOT(nd.vrefl, r->ron) <= FTINY) /* penetration? */
202     for (i = 0; i < 3; i++) /* safety measure */
203     nd.vrefl[i] = r->rdir[i] + 2.*r->rod*r->ron[i];
204 greg 1.1
205 greg 2.2 if (!(r->crtype & SHADOW) && nd.specfl & SP_PURE) {
206 greg 1.3 RAY lr;
207     if (rayorigin(&lr, r, REFLECTED, nd.rspec) == 0) {
208     VCOPY(lr.rdir, nd.vrefl);
209 greg 1.1 rayvalue(&lr);
210 greg 1.3 multcolor(lr.rcol, nd.scolor);
211 greg 1.1 addcolor(r->rcol, lr.rcol);
212     }
213 greg 1.3 }
214 greg 1.1 }
215 greg 1.3 /* compute transmission */
216 greg 1.1 if (m->otype == MAT_TRANS) {
217 greg 1.3 nd.trans = m->oargs.farg[5]*(1.0 - nd.rspec);
218     nd.tspec = nd.trans * m->oargs.farg[6];
219     nd.tdiff = nd.trans - nd.tspec;
220 greg 2.2 if (nd.tspec > FTINY) {
221     nd.specfl |= SP_TRAN;
222 greg 2.5 /* check threshold */
223 greg 2.25 if (!(nd.specfl & SP_PURE) &&
224     specthresh >= nd.tspec-FTINY)
225 greg 2.5 nd.specfl |= SP_TBLT;
226 greg 2.2 if (r->crtype & SHADOW ||
227     DOT(r->pert,r->pert) <= FTINY*FTINY) {
228     VCOPY(nd.prdir, r->rdir);
229     transtest = 2;
230     } else {
231     for (i = 0; i < 3; i++) /* perturb */
232 greg 2.19 nd.prdir[i] = r->rdir[i] - r->pert[i];
233 greg 2.7 if (DOT(nd.prdir, r->ron) < -FTINY)
234     normalize(nd.prdir); /* OK */
235     else
236     VCOPY(nd.prdir, r->rdir);
237 greg 2.2 }
238 greg 1.14 }
239 greg 1.1 } else
240 greg 1.3 nd.tdiff = nd.tspec = nd.trans = 0.0;
241 greg 1.1 /* transmitted ray */
242 greg 2.2 if ((nd.specfl&(SP_TRAN|SP_PURE)) == (SP_TRAN|SP_PURE)) {
243 greg 1.3 RAY lr;
244     if (rayorigin(&lr, r, TRANS, nd.tspec) == 0) {
245 greg 1.14 VCOPY(lr.rdir, nd.prdir);
246 greg 1.1 rayvalue(&lr);
247 greg 1.3 scalecolor(lr.rcol, nd.tspec);
248 greg 1.8 multcolor(lr.rcol, nd.mcolor); /* modified by color */
249 greg 1.1 addcolor(r->rcol, lr.rcol);
250 greg 1.9 transtest *= bright(lr.rcol);
251     transdist = r->rot + lr.rt;
252 greg 1.1 }
253 greg 2.11 } else
254     transtest = 0;
255 greg 2.2
256 greg 1.1 if (r->crtype & SHADOW) /* the rest is shadow */
257     return;
258     /* diffuse reflection */
259 greg 1.3 nd.rdiff = 1.0 - nd.trans - nd.rspec;
260 greg 1.1
261 greg 2.2 if (nd.specfl & SP_PURE && nd.rdiff <= FTINY && nd.tdiff <= FTINY)
262     return; /* 100% pure specular */
263 greg 2.3
264 greg 2.12 if (r->ro != NULL && (r->ro->otype == OBJ_FACE ||
265     r->ro->otype == OBJ_RING))
266 greg 2.3 nd.specfl |= SP_FLAT;
267 greg 1.1
268 greg 2.2 if (nd.specfl & (SP_REFL|SP_TRAN) && !(nd.specfl & SP_PURE))
269     gaussamp(r, &nd);
270    
271 greg 1.3 if (nd.rdiff > FTINY) { /* ambient from this side */
272 greg 1.2 ambient(ctmp, r);
273 greg 2.5 if (nd.specfl & SP_RBLT)
274     scalecolor(ctmp, 1.0-nd.trans);
275     else
276     scalecolor(ctmp, nd.rdiff);
277 greg 1.3 multcolor(ctmp, nd.mcolor); /* modified by material color */
278 greg 1.2 addcolor(r->rcol, ctmp); /* add to returned color */
279     }
280 greg 1.3 if (nd.tdiff > FTINY) { /* ambient from other side */
281 greg 1.1 flipsurface(r);
282 greg 1.2 ambient(ctmp, r);
283 greg 2.5 if (nd.specfl & SP_TBLT)
284     scalecolor(ctmp, nd.trans);
285     else
286     scalecolor(ctmp, nd.tdiff);
287 greg 1.13 multcolor(ctmp, nd.mcolor); /* modified by color */
288 greg 1.1 addcolor(r->rcol, ctmp);
289     flipsurface(r);
290     }
291 greg 1.3 /* add direct component */
292     direct(r, dirnorm, &nd);
293 greg 1.9 /* check distance */
294     if (transtest > bright(r->rcol))
295     r->rt = transdist;
296 greg 2.2 }
297    
298    
299     static
300     gaussamp(r, np) /* sample gaussian specular */
301     RAY *r;
302     register NORMDAT *np;
303     {
304     RAY sr;
305     FVECT u, v, h;
306     double rv[2];
307     double d, sinp, cosp;
308     register int i;
309 greg 2.13 /* quick test */
310     if ((np->specfl & (SP_REFL|SP_RBLT)) != SP_REFL &&
311     (np->specfl & (SP_TRAN|SP_TBLT)) != SP_TRAN)
312     return;
313 greg 2.2 /* set up sample coordinates */
314     v[0] = v[1] = v[2] = 0.0;
315     for (i = 0; i < 3; i++)
316     if (np->pnorm[i] < 0.6 && np->pnorm[i] > -0.6)
317     break;
318     v[i] = 1.0;
319     fcross(u, v, np->pnorm);
320     normalize(u);
321     fcross(v, np->pnorm, u);
322     /* compute reflection */
323 greg 2.5 if ((np->specfl & (SP_REFL|SP_RBLT)) == SP_REFL &&
324 greg 2.2 rayorigin(&sr, r, SPECULAR, np->rspec) == 0) {
325     dimlist[ndims++] = (int)np->mp;
326 greg 2.7 d = urand(ilhash(dimlist,ndims)+samplendx);
327     multisamp(rv, 2, d);
328     d = 2.0*PI * rv[0];
329     cosp = cos(d);
330     sinp = sin(d);
331     rv[1] = 1.0 - specjitter*rv[1];
332     if (rv[1] <= FTINY)
333     d = 1.0;
334     else
335     d = sqrt( np->alpha2 * -log(rv[1]) );
336     for (i = 0; i < 3; i++)
337     h[i] = np->pnorm[i] + d*(cosp*u[i] + sinp*v[i]);
338     d = -2.0 * DOT(h, r->rdir) / (1.0 + d*d);
339     for (i = 0; i < 3; i++)
340     sr.rdir[i] = r->rdir[i] + d*h[i];
341     if (DOT(sr.rdir, r->ron) <= FTINY)
342     VCOPY(sr.rdir, np->vrefl); /* jitter no good */
343     rayvalue(&sr);
344     multcolor(sr.rcol, np->scolor);
345     addcolor(r->rcol, sr.rcol);
346 greg 2.2 ndims--;
347     }
348     /* compute transmission */
349 greg 2.8 if ((np->specfl & (SP_TRAN|SP_TBLT)) == SP_TRAN &&
350     rayorigin(&sr, r, SPECULAR, np->tspec) == 0) {
351     dimlist[ndims++] = (int)np->mp;
352     d = urand(ilhash(dimlist,ndims)+1823+samplendx);
353     multisamp(rv, 2, d);
354     d = 2.0*PI * rv[0];
355     cosp = cos(d);
356     sinp = sin(d);
357     rv[1] = 1.0 - specjitter*rv[1];
358     if (rv[1] <= FTINY)
359     d = 1.0;
360     else
361 greg 2.20 d = sqrt( -log(rv[1]) * np->alpha2 );
362 greg 2.8 for (i = 0; i < 3; i++)
363     sr.rdir[i] = np->prdir[i] + d*(cosp*u[i] + sinp*v[i]);
364     if (DOT(sr.rdir, r->ron) < -FTINY)
365     normalize(sr.rdir); /* OK, normalize */
366     else
367     VCOPY(sr.rdir, np->prdir); /* else no jitter */
368     rayvalue(&sr);
369 greg 2.11 scalecolor(sr.rcol, np->tspec);
370     multcolor(sr.rcol, np->mcolor); /* modified by color */
371 greg 2.8 addcolor(r->rcol, sr.rcol);
372     ndims--;
373     }
374 greg 1.1 }