ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ashikhmin.c
Revision: 2.4
Committed: Thu Dec 4 05:26:28 2014 UTC (9 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.3: +13 -15 lines
Log Message:
Improved behavior of anisotropic reflections

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.4 static const char RCSid[] = "$Id: ashikhmin.c,v 2.3 2013/08/07 05:10:09 greg Exp $";
3 greg 2.1 #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 greg 2.2 static void getacoords_as(ASHIKDAT *np);
50     static void ashiksamp(ASHIKDAT *np);
51 greg 2.1
52 greg 2.2 #undef MAX
53     #define MAX(a,b) ((a)>(b) ? (a) : (b))
54 greg 2.1
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 greg 2.4 if (!(np->specfl & SPA_REFL))
96 greg 2.1 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 greg 2.2 dtmp /= 8.*PI * DOT(ldir,h) * MAX(ldot,np->pdot);
113 greg 2.1 /* 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 greg 2.2 getacoords_as(&nd);
181 greg 2.1 /* specular sampling? */
182     if ((nd.specfl & (SPA_REFL|SPA_RBLT)) == SPA_REFL)
183 greg 2.2 ashiksamp(&nd);
184 greg 2.1 /* 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 greg 2.2 setfunc(np->mp, np->rp);
208 greg 2.1 errno = 0;
209     for (i = 0; i < 3; i++)
210     np->u[i] = evalue(mf->ep[i]);
211 greg 2.4 if ((errno == EDOM) | (errno == ERANGE))
212     np->u[0] = np->u[1] = np->u[2] = 0.0;
213 greg 2.1 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 greg 2.4 if (fabs(np->u_power - np->v_power) > 0.1)
218     objerror(np->mp, WARNING, "bad orientation vector");
219     getperpendicular(np->u, np->pnorm); /* 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 greg 2.1 }
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 greg 2.4 if (rayorigin(&sr, SPECULAR, np->rp, np->scolor) < 0)
241 greg 2.1 return;
242    
243     nstarget = 1;
244     if (specjitter > 1.5) { /* multiple samples? */
245 greg 2.2 nstarget = specjitter*np->rp->rweight + .5;
246 greg 2.1 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 greg 2.2 dtmp = urand(ilhash(dimlist,ndims)+647+samplendx);
263 greg 2.1 multisamp(rv, 2, dtmp);
264     dtmp = 2.*PI * rv[0];
265 greg 2.2 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 greg 2.1 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 greg 2.2 dtmp = -2.*DOT(h, np->rp->rdir);
280     VSUM(sr.rdir, np->rp->rdir, h, dtmp);
281 greg 2.1 /* sample rejection test */
282 greg 2.2 if (DOT(sr.rdir, np->rp->ron) <= FTINY)
283 greg 2.1 continue;
284 greg 2.2 checknorm(sr.rdir);
285 greg 2.1 rayvalue(&sr);
286     multcolor(sr.rcol, sr.rcoef);
287 greg 2.2 addcolor(np->rp->rcol, sr.rcol);
288 greg 2.1 ++nstaken;
289     }
290     ndims--;
291     }