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

# Content
1 /* Copyright (c) 1992 Regents of the University of California */
2
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 * Later changes described in delta comments.
15 */
16
17 #include "ray.h"
18
19 #include "otypes.h"
20
21 #include "random.h"
22
23 extern double specthresh; /* specular sampling threshold */
24 extern double specjitter; /* specular sampling jitter */
25
26 static gaussamp();
27
28 /*
29 * This routine implements the isotropic Gaussian
30 * model described by Ward in Siggraph `92 article.
31 * 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 /* specularity flags */
42 #define SP_REFL 01 /* has reflected specular component */
43 #define SP_TRAN 02 /* has transmitted specular */
44 #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
49 typedef struct {
50 OBJREC *mp; /* material pointer */
51 RAY *rp; /* ray pointer */
52 short specfl; /* specularity flags, defined above */
53 COLOR mcolor; /* color of this material */
54 COLOR scolor; /* color of specular component */
55 FVECT vrefl; /* vector in direction of reflected ray */
56 FVECT prdir; /* vector in transmitted direction */
57 double alpha2; /* roughness squared */
58 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 } 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 double ldot;
73 double dtmp, d2;
74 FVECT vtmp;
75 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 * 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 */
90 copycolor(ctmp, np->mcolor);
91 dtmp = ldot * omega * np->rdiff / PI;
92 scalecolor(ctmp, dtmp);
93 addcolor(cval, ctmp);
94 }
95 if (ldot > FTINY && (np->specfl&(SP_REFL|SP_PURE)) == SP_REFL) {
96 /*
97 * Compute specular reflection coefficient using
98 * gaussian distribution model.
99 */
100 /* roughness */
101 dtmp = np->alpha2;
102 /* + source if flat */
103 if (np->specfl & SP_FLAT)
104 dtmp += omega/(4.0*PI);
105 /* half vector */
106 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 d2 = DOT(vtmp, np->pnorm);
110 d2 *= d2;
111 d2 = (DOT(vtmp,vtmp) - d2) / d2;
112 /* gaussian */
113 dtmp = exp(-d2/dtmp)/(4.*PI*dtmp);
114 /* worth using? */
115 if (dtmp > FTINY) {
116 copycolor(ctmp, np->scolor);
117 dtmp *= omega * sqrt(ldot/np->pdot);
118 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 if (ldot < -FTINY && (np->specfl&(SP_TRAN|SP_PURE)) == SP_TRAN) {
132 /*
133 * Compute specular transmission. Specular transmission
134 * is always modified by material color.
135 */
136 /* roughness + source */
137 dtmp = np->alpha2 + omega/PI;
138 /* gaussian */
139 dtmp = exp((2.*DOT(np->prdir,ldir)-2.)/dtmp)/(PI*dtmp);
140 /* worth using? */
141 if (dtmp > FTINY) {
142 copycolor(ctmp, np->mcolor);
143 dtmp *= np->tspec * omega * sqrt(-ldot/np->pdot);
144 scalecolor(ctmp, dtmp);
145 addcolor(cval, ctmp);
146 }
147 }
148 }
149
150
151 m_normal(m, r) /* color a ray that hit something normal */
152 register OBJREC *m;
153 register RAY *r;
154 {
155 NORMDAT nd;
156 double transtest, transdist;
157 COLOR ctmp;
158 register int i;
159 /* easy shadow test */
160 if (r->crtype & SHADOW && m->otype != MAT_TRANS)
161 return;
162
163 if (m->oargs.nfargs != (m->otype == MAT_TRANS ? 7 : 5))
164 objerror(m, USER, "bad number of arguments");
165 nd.mp = m;
166 nd.rp = r;
167 /* get material color */
168 setcolor(nd.mcolor, m->oargs.farg[0],
169 m->oargs.farg[1],
170 m->oargs.farg[2]);
171 /* get roughness */
172 nd.specfl = 0;
173 nd.alpha2 = m->oargs.farg[4];
174 if ((nd.alpha2 *= nd.alpha2) <= FTINY)
175 nd.specfl |= SP_PURE;
176 /* reorient if necessary */
177 if (r->rod < 0.0)
178 flipsurface(r);
179 /* get modifiers */
180 raytexture(r, m->omod);
181 nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */
182 if (nd.pdot < .001)
183 nd.pdot = .001; /* non-zero for dirnorm() */
184 multcolor(nd.mcolor, r->pcol); /* modify material color */
185 transtest = 0;
186 /* get specular component */
187 if ((nd.rspec = m->oargs.farg[3]) > FTINY) {
188 nd.specfl |= SP_REFL;
189 /* compute specular color */
190 if (m->otype == MAT_METAL)
191 copycolor(nd.scolor, nd.mcolor);
192 else
193 setcolor(nd.scolor, 1.0, 1.0, 1.0);
194 scalecolor(nd.scolor, nd.rspec);
195 /* check threshold */
196 if (!(nd.specfl & SP_PURE) && specthresh >= nd.rspec-FTINY)
197 nd.specfl |= SP_RBLT;
198 /* compute reflected ray */
199 for (i = 0; i < 3; i++)
200 nd.vrefl[i] = r->rdir[i] + 2.0*nd.pdot*nd.pnorm[i];
201 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
205 if (!(r->crtype & SHADOW) && nd.specfl & SP_PURE) {
206 RAY lr;
207 if (rayorigin(&lr, r, REFLECTED, nd.rspec) == 0) {
208 VCOPY(lr.rdir, nd.vrefl);
209 rayvalue(&lr);
210 multcolor(lr.rcol, nd.scolor);
211 addcolor(r->rcol, lr.rcol);
212 }
213 }
214 }
215 /* compute transmission */
216 if (m->otype == MAT_TRANS) {
217 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 if (nd.tspec > FTINY) {
221 nd.specfl |= SP_TRAN;
222 /* check threshold */
223 if (!(nd.specfl & SP_PURE) &&
224 specthresh >= nd.tspec-FTINY)
225 nd.specfl |= SP_TBLT;
226 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 nd.prdir[i] = r->rdir[i] - r->pert[i];
233 if (DOT(nd.prdir, r->ron) < -FTINY)
234 normalize(nd.prdir); /* OK */
235 else
236 VCOPY(nd.prdir, r->rdir);
237 }
238 }
239 } else
240 nd.tdiff = nd.tspec = nd.trans = 0.0;
241 /* transmitted ray */
242 if ((nd.specfl&(SP_TRAN|SP_PURE)) == (SP_TRAN|SP_PURE)) {
243 RAY lr;
244 if (rayorigin(&lr, r, TRANS, nd.tspec) == 0) {
245 VCOPY(lr.rdir, nd.prdir);
246 rayvalue(&lr);
247 scalecolor(lr.rcol, nd.tspec);
248 multcolor(lr.rcol, nd.mcolor); /* modified by color */
249 addcolor(r->rcol, lr.rcol);
250 transtest *= bright(lr.rcol);
251 transdist = r->rot + lr.rt;
252 }
253 } else
254 transtest = 0;
255
256 if (r->crtype & SHADOW) /* the rest is shadow */
257 return;
258 /* diffuse reflection */
259 nd.rdiff = 1.0 - nd.trans - nd.rspec;
260
261 if (nd.specfl & SP_PURE && nd.rdiff <= FTINY && nd.tdiff <= FTINY)
262 return; /* 100% pure specular */
263
264 if (r->ro != NULL && (r->ro->otype == OBJ_FACE ||
265 r->ro->otype == OBJ_RING))
266 nd.specfl |= SP_FLAT;
267
268 if (nd.specfl & (SP_REFL|SP_TRAN) && !(nd.specfl & SP_PURE))
269 gaussamp(r, &nd);
270
271 if (nd.rdiff > FTINY) { /* ambient from this side */
272 ambient(ctmp, r);
273 if (nd.specfl & SP_RBLT)
274 scalecolor(ctmp, 1.0-nd.trans);
275 else
276 scalecolor(ctmp, nd.rdiff);
277 multcolor(ctmp, nd.mcolor); /* modified by material color */
278 addcolor(r->rcol, ctmp); /* add to returned color */
279 }
280 if (nd.tdiff > FTINY) { /* ambient from other side */
281 flipsurface(r);
282 ambient(ctmp, r);
283 if (nd.specfl & SP_TBLT)
284 scalecolor(ctmp, nd.trans);
285 else
286 scalecolor(ctmp, nd.tdiff);
287 multcolor(ctmp, nd.mcolor); /* modified by color */
288 addcolor(r->rcol, ctmp);
289 flipsurface(r);
290 }
291 /* add direct component */
292 direct(r, dirnorm, &nd);
293 /* check distance */
294 if (transtest > bright(r->rcol))
295 r->rt = transdist;
296 }
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 /* quick test */
310 if ((np->specfl & (SP_REFL|SP_RBLT)) != SP_REFL &&
311 (np->specfl & (SP_TRAN|SP_TBLT)) != SP_TRAN)
312 return;
313 /* 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 if ((np->specfl & (SP_REFL|SP_RBLT)) == SP_REFL &&
324 rayorigin(&sr, r, SPECULAR, np->rspec) == 0) {
325 dimlist[ndims++] = (int)np->mp;
326 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 ndims--;
347 }
348 /* compute transmission */
349 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 d = sqrt( -log(rv[1]) * np->alpha2 );
362 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 scalecolor(sr.rcol, np->tspec);
370 multcolor(sr.rcol, np->mcolor); /* modified by color */
371 addcolor(r->rcol, sr.rcol);
372 ndims--;
373 }
374 }