ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ashikhmin.c
Revision: 2.5
Committed: Thu May 21 05:54:54 2015 UTC (8 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +2 -2 lines
Log Message:
Made axis randomization optional in getperpendicular()

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: ashikhmin.c,v 2.4 2014/12/04 05:26:28 greg Exp $";
3 #endif
4 /*
5 * Shading functions for Ashikhmin-Shirley anisotropic materials.
6 */
7
8 #include "copyright.h"
9
10 #include "ray.h"
11 #include "ambient.h"
12 #include "otypes.h"
13 #include "rtotypes.h"
14 #include "source.h"
15 #include "func.h"
16 #include "random.h"
17
18 #ifndef MAXITER
19 #define MAXITER 10 /* maximum # specular ray attempts */
20 #endif
21
22 /*
23 * Ashikhmin-Shirley model
24 *
25 * Arguments for MAT_ASHIKHMIN are:
26 * 4+ ux uy uz funcfile [transform...]
27 * 0
28 * 8 dred dgrn dblu sred sgrn sblu u-power v-power
29 */
30
31 /* specularity flags */
32 #define SPA_REFL 01 /* has reflected specular component */
33 #define SPA_FLAT 02 /* reflecting surface is flat */
34 #define SPA_RBLT 010 /* reflection below sample threshold */
35
36 typedef struct {
37 OBJREC *mp; /* material pointer */
38 RAY *rp; /* ray pointer */
39 short specfl; /* specularity flags, defined above */
40 COLOR mcolor; /* color of this material */
41 COLOR scolor; /* color of specular component */
42 FVECT u, v; /* u and v vectors orienting anisotropy */
43 double u_power; /* u power */
44 double v_power; /* v power */
45 FVECT pnorm; /* perturbed surface normal */
46 double pdot; /* perturbed dot product */
47 } ASHIKDAT; /* anisotropic material data */
48
49 static void getacoords_as(ASHIKDAT *np);
50 static void ashiksamp(ASHIKDAT *np);
51
52 #undef MAX
53 #define MAX(a,b) ((a)>(b) ? (a) : (b))
54
55
56 static double
57 schlick_fres(double dprod)
58 {
59 double pf = 1. - dprod;
60
61 return(pf*pf*pf*pf*pf);
62 }
63
64
65 static void
66 dirashik( /* compute source contribution */
67 COLOR cval, /* returned coefficient */
68 void *nnp, /* material data */
69 FVECT ldir, /* light source direction */
70 double omega /* light source size */
71 )
72 {
73 ASHIKDAT *np = nnp;
74 double ldot;
75 double dtmp, dtmp1, dtmp2;
76 FVECT h;
77 COLOR ctmp;
78
79 setcolor(cval, 0.0, 0.0, 0.0);
80
81 ldot = DOT(np->pnorm, ldir);
82
83 if (ldot < 0.0)
84 return; /* wrong side */
85
86 /*
87 * Compute and add diffuse reflected component to returned
88 * color.
89 */
90 copycolor(ctmp, np->mcolor);
91 dtmp = ldot * omega * (1.0/PI) * (1. - schlick_fres(ldot));
92 scalecolor(ctmp, dtmp);
93 addcolor(cval, ctmp);
94
95 if (!(np->specfl & SPA_REFL))
96 return;
97 /*
98 * Compute specular reflection coefficient
99 */
100 /* half vector */
101 VSUB(h, ldir, np->rp->rdir);
102 normalize(h);
103 /* ellipse */
104 dtmp1 = DOT(np->u, h);
105 dtmp1 *= dtmp1 * np->u_power;
106 dtmp2 = DOT(np->v, h);
107 dtmp2 *= dtmp2 * np->v_power;
108 /* Ashikhmin-Shirley model*/
109 dtmp = DOT(np->pnorm, h);
110 dtmp = pow(dtmp, (dtmp1+dtmp2)/(1.-dtmp*dtmp));
111 dtmp *= sqrt((np->u_power+1.)*(np->v_power+1.));
112 dtmp /= 8.*PI * DOT(ldir,h) * MAX(ldot,np->pdot);
113 /* worth using? */
114 if (dtmp > FTINY) {
115 copycolor(ctmp, np->scolor);
116 dtmp *= ldot * omega;
117 scalecolor(ctmp, dtmp);
118 addcolor(cval, ctmp);
119 }
120 }
121
122
123 int
124 m_ashikhmin( /* shade ray that hit something anisotropic */
125 OBJREC *m,
126 RAY *r
127 )
128 {
129 ASHIKDAT nd;
130 COLOR ctmp;
131 double fres;
132 int i;
133 /* easy shadow test */
134 if (r->crtype & SHADOW)
135 return(1);
136
137 if (m->oargs.nfargs != 8)
138 objerror(m, USER, "bad number of real arguments");
139 /* check for back side */
140 if (r->rod < 0.0) {
141 if (!backvis) {
142 raytrans(r);
143 return(1);
144 }
145 raytexture(r, m->omod);
146 flipsurface(r); /* reorient if backvis */
147 } else
148 raytexture(r, m->omod);
149 /* get material color */
150 nd.mp = m;
151 nd.rp = r;
152 setcolor(nd.mcolor, m->oargs.farg[0],
153 m->oargs.farg[1],
154 m->oargs.farg[2]);
155 setcolor(nd.scolor, m->oargs.farg[3],
156 m->oargs.farg[4],
157 m->oargs.farg[5]);
158 /* get specular power */
159 nd.specfl = 0;
160 nd.u_power = m->oargs.farg[6];
161 nd.v_power = m->oargs.farg[7];
162
163 nd.pdot = raynormal(nd.pnorm, r); /* perturb normal */
164 if (nd.pdot < .001)
165 nd.pdot = .001; /* non-zero for dirashik() */
166 multcolor(nd.mcolor, r->pcol); /* modify diffuse color */
167
168 if (bright(nd.scolor) > FTINY) { /* adjust specular color */
169 nd.specfl |= SPA_REFL;
170 /* check threshold */
171 if (specthresh >= bright(nd.scolor)-FTINY)
172 nd.specfl |= SPA_RBLT;
173 fres = schlick_fres(nd.pdot); /* Schick's Fresnel approx */
174 for (i = 0; i < 3; i++)
175 colval(nd.scolor,i) += (1.-colval(nd.scolor,i))*fres;
176 }
177 if (r->ro != NULL && isflat(r->ro->otype))
178 nd.specfl |= SPA_FLAT;
179 /* set up coordinates */
180 getacoords_as(&nd);
181 /* specular sampling? */
182 if ((nd.specfl & (SPA_REFL|SPA_RBLT)) == SPA_REFL)
183 ashiksamp(&nd);
184 /* diffuse interreflection */
185 if (bright(nd.mcolor) > FTINY) {
186 copycolor(ctmp, nd.mcolor); /* modified by material color */
187 if (nd.specfl & SPA_RBLT) /* add in specular as well? */
188 addcolor(ctmp, nd.scolor);
189 multambient(ctmp, r, nd.pnorm);
190 addcolor(r->rcol, ctmp); /* add to returned color */
191 }
192 direct(r, dirashik, &nd); /* add direct component */
193
194 return(1);
195 }
196
197
198 static void
199 getacoords_as( /* set up coordinate system */
200 ASHIKDAT *np
201 )
202 {
203 MFUNC *mf;
204 int i;
205
206 mf = getfunc(np->mp, 3, 0x7, 1);
207 setfunc(np->mp, np->rp);
208 errno = 0;
209 for (i = 0; i < 3; i++)
210 np->u[i] = evalue(mf->ep[i]);
211 if ((errno == EDOM) | (errno == ERANGE))
212 np->u[0] = np->u[1] = np->u[2] = 0.0;
213 if (mf->fxp != &unitxf)
214 multv3(np->u, np->u, mf->fxp->xfm);
215 fcross(np->v, np->pnorm, np->u);
216 if (normalize(np->v) == 0.0) {
217 if (fabs(np->u_power - np->v_power) > 0.1)
218 objerror(np->mp, WARNING, "bad orientation vector");
219 getperpendicular(np->u, np->pnorm, 1); /* punting */
220 fcross(np->v, np->pnorm, np->u);
221 np->u_power = np->v_power =
222 2./(1./(np->u_power+1e-5) + 1./(np->v_power+1e-5));
223 } else
224 fcross(np->u, np->v, np->pnorm);
225 }
226
227
228 static void
229 ashiksamp( /* sample anisotropic Ashikhmin-Shirley specular */
230 ASHIKDAT *np
231 )
232 {
233 RAY sr;
234 FVECT h;
235 double rv[2], dtmp;
236 double cosph, sinph, costh, sinth;
237 int maxiter, ntrials, nstarget, nstaken;
238 int i;
239
240 if (rayorigin(&sr, SPECULAR, np->rp, np->scolor) < 0)
241 return;
242
243 nstarget = 1;
244 if (specjitter > 1.5) { /* multiple samples? */
245 nstarget = specjitter*np->rp->rweight + .5;
246 if (sr.rweight <= minweight*nstarget)
247 nstarget = sr.rweight/minweight;
248 if (nstarget > 1) {
249 dtmp = 1./nstarget;
250 scalecolor(sr.rcoef, dtmp);
251 sr.rweight *= dtmp;
252 } else
253 nstarget = 1;
254 }
255 dimlist[ndims++] = (int)(size_t)np->mp;
256 maxiter = MAXITER*nstarget;
257 for (nstaken = ntrials = 0; nstaken < nstarget &&
258 ntrials < maxiter; ntrials++) {
259 if (ntrials)
260 dtmp = frandom();
261 else
262 dtmp = urand(ilhash(dimlist,ndims)+647+samplendx);
263 multisamp(rv, 2, dtmp);
264 dtmp = 2.*PI * rv[0];
265 cosph = sqrt(np->v_power + 1.) * tcos(dtmp);
266 sinph = sqrt(np->u_power + 1.) * tsin(dtmp);
267 dtmp = 1./sqrt(cosph*cosph + sinph*sinph);
268 cosph *= dtmp;
269 sinph *= dtmp;
270 costh = pow(rv[1], 1./(np->u_power*cosph*cosph+np->v_power*sinph*sinph+1.));
271 if (costh <= FTINY)
272 continue;
273 sinth = sqrt(1. - costh*costh);
274 for (i = 0; i < 3; i++)
275 h[i] = cosph*sinth*np->u[i] + sinph*sinth*np->v[i] + costh*np->pnorm[i];
276
277 if (nstaken)
278 rayclear(&sr);
279 dtmp = -2.*DOT(h, np->rp->rdir);
280 VSUM(sr.rdir, np->rp->rdir, h, dtmp);
281 /* sample rejection test */
282 if (DOT(sr.rdir, np->rp->ron) <= FTINY)
283 continue;
284 checknorm(sr.rdir);
285 rayvalue(&sr);
286 multcolor(sr.rcol, sr.rcoef);
287 addcolor(np->rp->rcol, sr.rcol);
288 ++nstaken;
289 }
290 ndims--;
291 }