| 1 | – | /* Copyright (c) 1995 Regents of the University of California */ | 
| 2 | – |  | 
| 1 |  | #ifndef lint | 
| 2 | < | static char SCCSid[] = "$SunId$ LBL"; | 
| 2 | > | static const char       RCSid[] = "$Id$"; | 
| 3 |  | #endif | 
| 6 | – |  | 
| 4 |  | /* | 
| 5 |  | * Routines to do the actual calculation for mkillum | 
| 6 |  | */ | 
| 7 |  |  | 
| 8 | < | #include  "mkillum.h" | 
| 8 | > | #include <string.h> | 
| 9 |  |  | 
| 10 | + | #include  "mkillum.h" | 
| 11 |  | #include  "face.h" | 
| 14 | – |  | 
| 12 |  | #include  "cone.h" | 
| 13 | + | #include  "source.h" | 
| 14 |  |  | 
| 17 | – | #include  "random.h" | 
| 15 |  |  | 
| 16 | + | COLORV *        distarr = NULL;         /* distribution array */ | 
| 17 | + | int             distsiz = 0; | 
| 18 | + | COLORV *        direct_discount = NULL; /* amount to take off direct */ | 
| 19 |  |  | 
| 20 | < | o_default(ob, il, rt, nm)       /* default illum action */ | 
| 21 | < | OBJREC  *ob; | 
| 22 | < | struct illum_args  *il; | 
| 23 | < | struct rtproc  *rt; | 
| 24 | < | char  *nm; | 
| 20 | > | void | 
| 21 | > | newdist(                        /* allocate & clear distribution array */ | 
| 22 | > | int siz | 
| 23 | > | ) | 
| 24 |  | { | 
| 25 | + | if (siz <= 0) { | 
| 26 | + | if (distsiz > 0) | 
| 27 | + | free((void *)distarr); | 
| 28 | + | distarr = NULL; | 
| 29 | + | distsiz = 0; | 
| 30 | + | return; | 
| 31 | + | } | 
| 32 | + | if (distsiz < siz) { | 
| 33 | + | if (distsiz > 0) | 
| 34 | + | free((void *)distarr); | 
| 35 | + | distarr = (COLORV *)malloc(sizeof(COLOR)*siz); | 
| 36 | + | if (distarr == NULL) | 
| 37 | + | error(SYSTEM, "out of memory in newdist"); | 
| 38 | + | distsiz = siz; | 
| 39 | + | } | 
| 40 | + | memset(distarr, '\0', sizeof(COLOR)*siz); | 
| 41 | + | } | 
| 42 | + |  | 
| 43 | + |  | 
| 44 | + | static void | 
| 45 | + | new_discount()                  /* allocate space for direct contrib. record */ | 
| 46 | + | { | 
| 47 | + | if (distsiz <= 0) | 
| 48 | + | return; | 
| 49 | + | direct_discount = (COLORV *)calloc(distsiz, sizeof(COLOR)); | 
| 50 | + | if (direct_discount == NULL) | 
| 51 | + | error(SYSTEM, "out of memory in new_discount"); | 
| 52 | + | } | 
| 53 | + |  | 
| 54 | + |  | 
| 55 | + | static void | 
| 56 | + | done_discount()                 /* clear off direct contrib. record */ | 
| 57 | + | { | 
| 58 | + | if (direct_discount == NULL) | 
| 59 | + | return; | 
| 60 | + | free((void *)direct_discount); | 
| 61 | + | direct_discount = NULL; | 
| 62 | + | } | 
| 63 | + |  | 
| 64 | + |  | 
| 65 | + | int | 
| 66 | + | process_ray(                    /* process a ray result or report error */ | 
| 67 | + | RAY *r, | 
| 68 | + | int rv | 
| 69 | + | ) | 
| 70 | + | { | 
| 71 | + | COLORV  *colp; | 
| 72 | + |  | 
| 73 | + | if (rv == 0)                    /* no result ready */ | 
| 74 | + | return(0); | 
| 75 | + | if (rv < 0) | 
| 76 | + | error(USER, "ray tracing process died"); | 
| 77 | + | if (r->rno >= distsiz) | 
| 78 | + | error(INTERNAL, "bad returned index in process_ray"); | 
| 79 | + | multcolor(r->rcol, r->rcoef);   /* in case it's a source ray */ | 
| 80 | + | colp = &distarr[r->rno * 3]; | 
| 81 | + | addcolor(colp, r->rcol); | 
| 82 | + | if (r->rsrc >= 0 &&             /* remember source contrib. */ | 
| 83 | + | direct_discount != NULL) { | 
| 84 | + | colp = &direct_discount[r->rno * 3]; | 
| 85 | + | addcolor(colp, r->rcol); | 
| 86 | + | } | 
| 87 | + | return(1); | 
| 88 | + | } | 
| 89 | + |  | 
| 90 | + |  | 
| 91 | + | void | 
| 92 | + | raysamp(                        /* queue a ray sample */ | 
| 93 | + | int  ndx, | 
| 94 | + | FVECT  org, | 
| 95 | + | FVECT  dir | 
| 96 | + | ) | 
| 97 | + | { | 
| 98 | + | RAY     myRay; | 
| 99 | + | int     rv; | 
| 100 | + |  | 
| 101 | + | if ((ndx < 0) | (ndx >= distsiz)) | 
| 102 | + | error(INTERNAL, "bad index in raysamp"); | 
| 103 | + | VCOPY(myRay.rorg, org); | 
| 104 | + | VCOPY(myRay.rdir, dir); | 
| 105 | + | myRay.rmax = .0; | 
| 106 | + | rayorigin(&myRay, PRIMARY, NULL, NULL); | 
| 107 | + | myRay.rno = ndx; | 
| 108 | + | /* queue ray, check result */ | 
| 109 | + | process_ray(&myRay, ray_pqueue(&myRay)); | 
| 110 | + | } | 
| 111 | + |  | 
| 112 | + |  | 
| 113 | + | void | 
| 114 | + | srcsamps(                       /* sample sources from this surface position */ | 
| 115 | + | struct illum_args *il, | 
| 116 | + | FVECT org, | 
| 117 | + | FVECT nrm, | 
| 118 | + | MAT4 ixfm | 
| 119 | + | ) | 
| 120 | + | { | 
| 121 | + | int  nalt, nazi; | 
| 122 | + | SRCINDEX  si; | 
| 123 | + | RAY  sr; | 
| 124 | + | FVECT   v; | 
| 125 | + | double  d; | 
| 126 | + | int  i, j; | 
| 127 | + | /* get sampling density */ | 
| 128 | + | if (il->sampdens <= 0) { | 
| 129 | + | nalt = nazi = 1; | 
| 130 | + | } else { | 
| 131 | + | i = PI * il->sampdens; | 
| 132 | + | nalt = sqrt(i/PI) + .5; | 
| 133 | + | nazi = PI*nalt + .5; | 
| 134 | + | } | 
| 135 | + | initsrcindex(&si);                      /* loop over (sub)sources */ | 
| 136 | + | for ( ; ; ) { | 
| 137 | + | VCOPY(sr.rorg, org);            /* pick side to shoot from */ | 
| 138 | + | if (il->sd != NULL) { | 
| 139 | + | int  sn = si.sn; | 
| 140 | + | if (si.sp+1 >= si.np) ++sn; | 
| 141 | + | if (sn >= nsources) break; | 
| 142 | + | if (source[sn].sflags & SDISTANT) | 
| 143 | + | d = DOT(source[sn].sloc, nrm); | 
| 144 | + | else { | 
| 145 | + | VSUB(v, source[sn].sloc, org); | 
| 146 | + | d = DOT(v, nrm); | 
| 147 | + | } | 
| 148 | + | } else | 
| 149 | + | d = 1.0;                /* only transmission */ | 
| 150 | + | if (d < 0.0) | 
| 151 | + | d = -1.0001*il->thick - 5.*FTINY; | 
| 152 | + | else | 
| 153 | + | d = 5.*FTINY; | 
| 154 | + | for (i = 3; i--; ) | 
| 155 | + | sr.rorg[i] += d*nrm[i]; | 
| 156 | + | if (!srcray(&sr, NULL, &si)) | 
| 157 | + | break;                  /* end of sources */ | 
| 158 | + | /* index direction */ | 
| 159 | + | if (ixfm != NULL) | 
| 160 | + | multv3(v, sr.rdir, ixfm); | 
| 161 | + | else | 
| 162 | + | VCOPY(v, sr.rdir); | 
| 163 | + | if (il->sd != NULL) { | 
| 164 | + | i = getBSDF_incndx(il->sd, v); | 
| 165 | + | if (i < 0) | 
| 166 | + | continue;       /* must not be important */ | 
| 167 | + | sr.rno = i; | 
| 168 | + | d = 1.0/getBSDF_incohm(il->sd, i); | 
| 169 | + | } else { | 
| 170 | + | if (v[2] >= -FTINY) | 
| 171 | + | continue;       /* only sample transmission */ | 
| 172 | + | v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; | 
| 173 | + | sr.rno = flatindex(v, nalt, nazi); | 
| 174 | + | d = nalt*nazi*(1./PI) * v[2]; | 
| 175 | + | } | 
| 176 | + | d *= si.dom;                    /* solid angle correction */ | 
| 177 | + | scalecolor(sr.rcoef, d); | 
| 178 | + | process_ray(&sr, ray_pqueue(&sr)); | 
| 179 | + | } | 
| 180 | + | } | 
| 181 | + |  | 
| 182 | + |  | 
| 183 | + | void | 
| 184 | + | rayclean()                      /* finish all pending rays */ | 
| 185 | + | { | 
| 186 | + | RAY     myRay; | 
| 187 | + |  | 
| 188 | + | while (process_ray(&myRay, ray_presult(&myRay, 0))) | 
| 189 | + | ; | 
| 190 | + | } | 
| 191 | + |  | 
| 192 | + |  | 
| 193 | + | static void | 
| 194 | + | mkaxes(                 /* compute u and v to go with n */ | 
| 195 | + | FVECT  u, | 
| 196 | + | FVECT  v, | 
| 197 | + | FVECT  n | 
| 198 | + | ) | 
| 199 | + | { | 
| 200 | + | register int  i; | 
| 201 | + |  | 
| 202 | + | v[0] = v[1] = v[2] = 0.0; | 
| 203 | + | for (i = 0; i < 3; i++) | 
| 204 | + | if (n[i] < 0.6 && n[i] > -0.6) | 
| 205 | + | break; | 
| 206 | + | v[i] = 1.0; | 
| 207 | + | fcross(u, v, n); | 
| 208 | + | normalize(u); | 
| 209 | + | fcross(v, n, u); | 
| 210 | + | } | 
| 211 | + |  | 
| 212 | + |  | 
| 213 | + | static void | 
| 214 | + | rounddir(               /* compute uniform spherical direction */ | 
| 215 | + | register FVECT  dv, | 
| 216 | + | double  alt, | 
| 217 | + | double  azi | 
| 218 | + | ) | 
| 219 | + | { | 
| 220 | + | double  d1, d2; | 
| 221 | + |  | 
| 222 | + | dv[2] = 1. - 2.*alt; | 
| 223 | + | d1 = sqrt(1. - dv[2]*dv[2]); | 
| 224 | + | d2 = 2.*PI * azi; | 
| 225 | + | dv[0] = d1*cos(d2); | 
| 226 | + | dv[1] = d1*sin(d2); | 
| 227 | + | } | 
| 228 | + |  | 
| 229 | + |  | 
| 230 | + | void | 
| 231 | + | flatdir(                /* compute uniform hemispherical direction */ | 
| 232 | + | FVECT  dv, | 
| 233 | + | double  alt, | 
| 234 | + | double  azi | 
| 235 | + | ) | 
| 236 | + | { | 
| 237 | + | double  d1, d2; | 
| 238 | + |  | 
| 239 | + | d1 = sqrt(alt); | 
| 240 | + | d2 = 2.*PI * azi; | 
| 241 | + | dv[0] = d1*cos(d2); | 
| 242 | + | dv[1] = d1*sin(d2); | 
| 243 | + | dv[2] = sqrt(1. - alt); | 
| 244 | + | } | 
| 245 | + |  | 
| 246 | + | int | 
| 247 | + | flatindex(              /* compute index for hemispherical direction */ | 
| 248 | + | FVECT   dv, | 
| 249 | + | int     nalt, | 
| 250 | + | int     nazi | 
| 251 | + | ) | 
| 252 | + | { | 
| 253 | + | double  d; | 
| 254 | + | int     i, j; | 
| 255 | + |  | 
| 256 | + | d = 1.0 - dv[2]*dv[2]; | 
| 257 | + | i = d*nalt; | 
| 258 | + | d = atan2(dv[1], dv[0]) * (0.5/PI); | 
| 259 | + | if (d < 0.0) d += 1.0; | 
| 260 | + | j = d*nazi + 0.5; | 
| 261 | + | if (j >= nazi) j = 0; | 
| 262 | + | return(i*nazi + j); | 
| 263 | + | } | 
| 264 | + |  | 
| 265 | + |  | 
| 266 | + | int | 
| 267 | + | my_default(     /* default illum action */ | 
| 268 | + | OBJREC  *ob, | 
| 269 | + | struct illum_args  *il, | 
| 270 | + | char  *nm | 
| 271 | + | ) | 
| 272 | + | { | 
| 273 |  | sprintf(errmsg, "(%s): cannot make illum for %s \"%s\"", | 
| 274 |  | nm, ofun[ob->otype].funame, ob->oname); | 
| 275 |  | error(WARNING, errmsg); | 
| 276 |  | printobj(il->altmat, ob); | 
| 277 | + | return(1); | 
| 278 |  | } | 
| 279 |  |  | 
| 280 |  |  | 
| 281 | < | o_face(ob, il, rt, nm)          /* make an illum face */ | 
| 282 | < | OBJREC  *ob; | 
| 283 | < | struct illum_args  *il; | 
| 284 | < | struct rtproc  *rt; | 
| 285 | < | char  *nm; | 
| 281 | > | int | 
| 282 | > | my_face(                /* make an illum face */ | 
| 283 | > | OBJREC  *ob, | 
| 284 | > | struct illum_args  *il, | 
| 285 | > | char  *nm | 
| 286 | > | ) | 
| 287 |  | { | 
| 288 | < | #define MAXMISS         (5*n*il->nsamps) | 
| 289 | < | int  dim[3]; | 
| 41 | < | int  n, nalt, nazi, h; | 
| 42 | < | float  *distarr; | 
| 288 | > | int  dim[2]; | 
| 289 | > | int  n, nalt, nazi, alti; | 
| 290 |  | double  sp[2], r1, r2; | 
| 291 | + | int  h; | 
| 292 |  | FVECT  dn, org, dir; | 
| 293 |  | FVECT  u, v; | 
| 294 |  | double  ur[2], vr[2]; | 
| 295 | < | int  nmisses; | 
| 296 | < | register FACE  *fa; | 
| 297 | < | register int  i, j; | 
| 295 | > | MAT4  xfm; | 
| 296 | > | int  nallow; | 
| 297 | > | FACE  *fa; | 
| 298 | > | int  i, j; | 
| 299 |  | /* get/check arguments */ | 
| 300 |  | fa = getface(ob); | 
| 301 |  | if (fa->area == 0.0) { | 
| 302 |  | freeface(ob); | 
| 303 | < | o_default(ob, il, rt, nm); | 
| 55 | < | return; | 
| 303 | > | return(my_default(ob, il, nm)); | 
| 304 |  | } | 
| 305 |  | /* set up sampling */ | 
| 306 | < | if (il->sampdens <= 0) | 
| 307 | < | nalt = nazi = 1; | 
| 308 | < | else { | 
| 309 | < | n = PI * il->sampdens; | 
| 310 | < | nalt = sqrt(n/PI) + .5; | 
| 311 | < | nazi = PI*nalt + .5; | 
| 306 | > | if (il->sd != NULL) { | 
| 307 | > | if (!getBSDF_xfm(xfm, fa->norm, il->udir)) { | 
| 308 | > | objerror(ob, WARNING, "illegal up direction"); | 
| 309 | > | freeface(ob); | 
| 310 | > | return(my_default(ob, il, nm)); | 
| 311 | > | } | 
| 312 | > | n = il->sd->ninc; | 
| 313 | > | } else { | 
| 314 | > | if (il->sampdens <= 0) { | 
| 315 | > | nalt = nazi = 1;        /* diffuse assumption */ | 
| 316 | > | } else { | 
| 317 | > | n = PI * il->sampdens; | 
| 318 | > | nalt = sqrt(n/PI) + .5; | 
| 319 | > | nazi = PI*nalt + .5; | 
| 320 | > | } | 
| 321 | > | n = nazi*nalt; | 
| 322 |  | } | 
| 323 | < | n = nalt*nazi; | 
| 324 | < | distarr = (float *)calloc(n, 3*sizeof(float)); | 
| 67 | < | if (distarr == NULL) | 
| 68 | < | error(SYSTEM, "out of memory in o_face"); | 
| 69 | < | /* take first edge longer than sqrt(area) */ | 
| 323 | > | newdist(n); | 
| 324 | > | /* take first edge >= sqrt(area) */ | 
| 325 |  | for (j = fa->nv-1, i = 0; i < fa->nv; j = i++) { | 
| 326 |  | u[0] = VERTEX(fa,i)[0] - VERTEX(fa,j)[0]; | 
| 327 |  | u[1] = VERTEX(fa,i)[1] - VERTEX(fa,j)[1]; | 
| 348 |  | } | 
| 349 |  | dim[0] = random(); | 
| 350 |  | /* sample polygon */ | 
| 351 | < | nmisses = 0; | 
| 352 | < | for (dim[1] = 0; dim[1] < nalt; dim[1]++) | 
| 98 | < | for (dim[2] = 0; dim[2] < nazi; dim[2]++) | 
| 351 | > | nallow = 5*n*il->nsamps; | 
| 352 | > | for (dim[1] = 0; dim[1] < n; dim[1]++) | 
| 353 |  | for (i = 0; i < il->nsamps; i++) { | 
| 354 | < | /* random direction */ | 
| 355 | < | h = ilhash(dim, 3) + i; | 
| 356 | < | multisamp(sp, 2, urand(h)); | 
| 357 | < | r1 = (dim[1] + sp[0])/nalt; | 
| 358 | < | r2 = (dim[2] + sp[1] - .5)/nazi; | 
| 359 | < | flatdir(dn, r1, r2); | 
| 360 | < | for (j = 0; j < 3; j++) | 
| 361 | < | dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*fa->norm[j]; | 
| 362 | < | /* random location */ | 
| 354 | > | /* randomize direction */ | 
| 355 | > | h = ilhash(dim, 2) + i; | 
| 356 | > | if (il->sd != NULL) { | 
| 357 | > | r_BSDF_incvec(dir, il->sd, dim[1], urand(h), xfm); | 
| 358 | > | } else { | 
| 359 | > | multisamp(sp, 2, urand(h)); | 
| 360 | > | alti = dim[1]/nazi; | 
| 361 | > | r1 = (alti + sp[0])/nalt; | 
| 362 | > | r2 = (dim[1] - alti*nazi + sp[1] - .5)/nazi; | 
| 363 | > | flatdir(dn, r1, r2); | 
| 364 | > | for (j = 0; j < 3; j++) | 
| 365 | > | dir[j] = -dn[0]*u[j] - dn[1]*v[j] - | 
| 366 | > | dn[2]*fa->norm[j]; | 
| 367 | > | } | 
| 368 | > | /* randomize location */ | 
| 369 |  | do { | 
| 370 | < | multisamp(sp, 2, urand(h+4862+nmisses)); | 
| 370 | > | multisamp(sp, 2, urand(h+4862+nallow)); | 
| 371 |  | r1 = ur[0] + (ur[1]-ur[0]) * sp[0]; | 
| 372 |  | r2 = vr[0] + (vr[1]-vr[0]) * sp[1]; | 
| 373 |  | for (j = 0; j < 3; j++) | 
| 374 |  | org[j] = r1*u[j] + r2*v[j] | 
| 375 |  | + fa->offset*fa->norm[j]; | 
| 376 | < | } while (!inface(org, fa) && nmisses++ < MAXMISS); | 
| 377 | < | if (nmisses > MAXMISS) { | 
| 376 | > | } while (!inface(org, fa) && nallow-- > 0); | 
| 377 | > | if (nallow < 0) { | 
| 378 |  | objerror(ob, WARNING, "bad aspect"); | 
| 379 | < | rt->nrays = 0; | 
| 379 | > | rayclean(); | 
| 380 |  | freeface(ob); | 
| 381 | < | free((char *)distarr); | 
| 122 | < | o_default(ob, il, rt, nm); | 
| 123 | < | return; | 
| 381 | > | return(my_default(ob, il, nm)); | 
| 382 |  | } | 
| 383 | + | if (il->sd != NULL && DOT(dir, fa->norm) < -FTINY) | 
| 384 | + | r1 = -1.0001*il->thick - 5.*FTINY; | 
| 385 | + | else | 
| 386 | + | r1 = 5.*FTINY; | 
| 387 |  | for (j = 0; j < 3; j++) | 
| 388 | < | org[j] += .001*fa->norm[j]; | 
| 388 | > | org[j] += r1*fa->norm[j]; | 
| 389 |  | /* send sample */ | 
| 390 | < | raysamp(distarr+3*(dim[1]*nazi+dim[2]), org, dir, rt); | 
| 390 | > | raysamp(dim[1], org, dir); | 
| 391 |  | } | 
| 392 | < | rayflush(rt); | 
| 392 | > | /* add in direct component? */ | 
| 393 | > | if (!directvis && (il->flags & IL_LIGHT || il->sd != NULL)) { | 
| 394 | > | MAT4    ixfm; | 
| 395 | > | if (il->sd == NULL) { | 
| 396 | > | for (i = 3; i--; ) { | 
| 397 | > | ixfm[i][0] = u[i]; | 
| 398 | > | ixfm[i][1] = v[i]; | 
| 399 | > | ixfm[i][2] = fa->norm[i]; | 
| 400 | > | ixfm[i][3] = 0.; | 
| 401 | > | } | 
| 402 | > | ixfm[3][0] = ixfm[3][1] = ixfm[3][2] = 0.; | 
| 403 | > | ixfm[3][3] = 1.; | 
| 404 | > | } else { | 
| 405 | > | if (!invmat4(ixfm, xfm)) | 
| 406 | > | objerror(ob, INTERNAL, | 
| 407 | > | "cannot invert BSDF transform"); | 
| 408 | > | if (!(il->flags & IL_LIGHT)) | 
| 409 | > | new_discount(); | 
| 410 | > | } | 
| 411 | > | dim[0] = random(); | 
| 412 | > | nallow = 10*il->nsamps; | 
| 413 | > | for (i = 0; i < il->nsamps; i++) { | 
| 414 | > | /* randomize location */ | 
| 415 | > | h = dim[0] + samplendx++; | 
| 416 | > | do { | 
| 417 | > | multisamp(sp, 2, urand(h+nallow)); | 
| 418 | > | r1 = ur[0] + (ur[1]-ur[0]) * sp[0]; | 
| 419 | > | r2 = vr[0] + (vr[1]-vr[0]) * sp[1]; | 
| 420 | > | for (j = 0; j < 3; j++) | 
| 421 | > | org[j] = r1*u[j] + r2*v[j] | 
| 422 | > | + fa->offset*fa->norm[j]; | 
| 423 | > | } while (!inface(org, fa) && nallow-- > 0); | 
| 424 | > | if (nallow < 0) { | 
| 425 | > | objerror(ob, WARNING, "bad aspect"); | 
| 426 | > | rayclean(); | 
| 427 | > | freeface(ob); | 
| 428 | > | return(my_default(ob, il, nm)); | 
| 429 | > | } | 
| 430 | > | /* sample source rays */ | 
| 431 | > | srcsamps(il, org, fa->norm, ixfm); | 
| 432 | > | } | 
| 433 | > | } | 
| 434 | > | /* wait for all rays to finish */ | 
| 435 | > | rayclean(); | 
| 436 | > | if (il->sd != NULL) {   /* run distribution through BSDF */ | 
| 437 | > | nalt = sqrt(il->sd->nout/PI) + .5; | 
| 438 | > | nazi = PI*nalt + .5; | 
| 439 | > | redistribute(il->sd, nalt, nazi, u, v, fa->norm, xfm); | 
| 440 | > | done_discount(); | 
| 441 | > | if (!il->sampdens) | 
| 442 | > | il->sampdens = nalt*nazi/PI + .999; | 
| 443 | > | } | 
| 444 |  | /* write out the face and its distribution */ | 
| 445 | < | if (average(il, distarr, nalt*nazi)) { | 
| 445 | > | if (average(il, distarr, n)) { | 
| 446 |  | if (il->sampdens > 0) | 
| 447 |  | flatout(il, distarr, nalt, nazi, u, v, fa->norm); | 
| 448 |  | illumout(il, ob); | 
| 450 |  | printobj(il->altmat, ob); | 
| 451 |  | /* clean up */ | 
| 452 |  | freeface(ob); | 
| 453 | < | free((char *)distarr); | 
| 141 | < | #undef MAXMISS | 
| 453 | > | return(0); | 
| 454 |  | } | 
| 455 |  |  | 
| 456 |  |  | 
| 457 | < | o_sphere(ob, il, rt, nm)        /* make an illum sphere */ | 
| 458 | < | register OBJREC  *ob; | 
| 459 | < | struct illum_args  *il; | 
| 460 | < | struct rtproc  *rt; | 
| 461 | < | char  *nm; | 
| 457 | > | int | 
| 458 | > | my_sphere(      /* make an illum sphere */ | 
| 459 | > | register OBJREC  *ob, | 
| 460 | > | struct illum_args  *il, | 
| 461 | > | char  *nm | 
| 462 | > | ) | 
| 463 |  | { | 
| 464 |  | int  dim[3]; | 
| 465 |  | int  n, nalt, nazi; | 
| 153 | – | float  *distarr; | 
| 466 |  | double  sp[4], r1, r2, r3; | 
| 467 |  | FVECT  org, dir; | 
| 468 |  | FVECT  u, v; | 
| 478 |  | nalt = sqrt(2./PI*n) + .5; | 
| 479 |  | nazi = PI/2.*nalt + .5; | 
| 480 |  | } | 
| 481 | + | if (il->sd != NULL) | 
| 482 | + | objerror(ob, WARNING, "BSDF ignored"); | 
| 483 |  | n = nalt*nazi; | 
| 484 | < | distarr = (float *)calloc(n, 3*sizeof(float)); | 
| 171 | < | if (distarr == NULL) | 
| 172 | < | error(SYSTEM, "out of memory in o_sphere"); | 
| 484 | > | newdist(n); | 
| 485 |  | dim[0] = random(); | 
| 486 |  | /* sample sphere */ | 
| 487 |  | for (dim[1] = 0; dim[1] < nalt; dim[1]++) | 
| 506 |  | dir[j] = -dir[j]; | 
| 507 |  | } | 
| 508 |  | /* send sample */ | 
| 509 | < | raysamp(distarr+3*(dim[1]*nazi+dim[2]), org, dir, rt); | 
| 509 | > | raysamp(dim[1]*nazi+dim[2], org, dir); | 
| 510 |  | } | 
| 511 | < | rayflush(rt); | 
| 511 | > | /* wait for all rays to finish */ | 
| 512 | > | rayclean(); | 
| 513 |  | /* write out the sphere and its distribution */ | 
| 514 | < | if (average(il, distarr, nalt*nazi)) { | 
| 514 | > | if (average(il, distarr, n)) { | 
| 515 |  | if (il->sampdens > 0) | 
| 516 |  | roundout(il, distarr, nalt, nazi); | 
| 517 |  | else | 
| 520 |  | } else | 
| 521 |  | printobj(il->altmat, ob); | 
| 522 |  | /* clean up */ | 
| 523 | < | free((char *)distarr); | 
| 523 | > | return(1); | 
| 524 |  | } | 
| 525 |  |  | 
| 526 |  |  | 
| 527 | < | o_ring(ob, il, rt, nm)          /* make an illum ring */ | 
| 528 | < | OBJREC  *ob; | 
| 529 | < | struct illum_args  *il; | 
| 530 | < | struct rtproc  *rt; | 
| 531 | < | char  *nm; | 
| 527 | > | int | 
| 528 | > | my_ring(                /* make an illum ring */ | 
| 529 | > | OBJREC  *ob, | 
| 530 | > | struct illum_args  *il, | 
| 531 | > | char  *nm | 
| 532 | > | ) | 
| 533 |  | { | 
| 534 | < | int  dim[3]; | 
| 535 | < | int  n, nalt, nazi; | 
| 536 | < | float  *distarr; | 
| 537 | < | double  sp[4], r1, r2, r3; | 
| 534 | > | int  dim[2]; | 
| 535 | > | int  n, nalt, nazi, alti; | 
| 536 | > | double  sp[2], r1, r2, r3; | 
| 537 | > | int  h; | 
| 538 |  | FVECT  dn, org, dir; | 
| 539 |  | FVECT  u, v; | 
| 540 | < | register CONE  *co; | 
| 541 | < | register int  i, j; | 
| 540 | > | MAT4  xfm; | 
| 541 | > | CONE  *co; | 
| 542 | > | int  i, j; | 
| 543 |  | /* get/check arguments */ | 
| 544 |  | co = getcone(ob, 0); | 
| 545 |  | /* set up sampling */ | 
| 546 | < | if (il->sampdens <= 0) | 
| 547 | < | nalt = nazi = 1; | 
| 548 | < | else { | 
| 549 | < | n = PI * il->sampdens; | 
| 550 | < | nalt = sqrt(n/PI) + .5; | 
| 551 | < | nazi = PI*nalt + .5; | 
| 546 | > | if (il->sd != NULL) { | 
| 547 | > | if (!getBSDF_xfm(xfm, co->ad, il->udir)) { | 
| 548 | > | objerror(ob, WARNING, "illegal up direction"); | 
| 549 | > | freecone(ob); | 
| 550 | > | return(my_default(ob, il, nm)); | 
| 551 | > | } | 
| 552 | > | n = il->sd->ninc; | 
| 553 | > | } else { | 
| 554 | > | if (il->sampdens <= 0) { | 
| 555 | > | nalt = nazi = 1;        /* diffuse assumption */ | 
| 556 | > | } else { | 
| 557 | > | n = PI * il->sampdens; | 
| 558 | > | nalt = sqrt(n/PI) + .5; | 
| 559 | > | nazi = PI*nalt + .5; | 
| 560 | > | } | 
| 561 | > | n = nazi*nalt; | 
| 562 |  | } | 
| 563 | < | n = nalt*nazi; | 
| 239 | < | distarr = (float *)calloc(n, 3*sizeof(float)); | 
| 240 | < | if (distarr == NULL) | 
| 241 | < | error(SYSTEM, "out of memory in o_ring"); | 
| 563 | > | newdist(n); | 
| 564 |  | mkaxes(u, v, co->ad); | 
| 565 |  | dim[0] = random(); | 
| 566 |  | /* sample disk */ | 
| 567 | < | for (dim[1] = 0; dim[1] < nalt; dim[1]++) | 
| 246 | < | for (dim[2] = 0; dim[2] < nazi; dim[2]++) | 
| 567 | > | for (dim[1] = 0; dim[1] < n; dim[1]++) | 
| 568 |  | for (i = 0; i < il->nsamps; i++) { | 
| 569 |  | /* next sample point */ | 
| 570 | < | multisamp(sp, 4, urand(ilhash(dim,3)+i)); | 
| 571 | < | /* random direction */ | 
| 572 | < | r1 = (dim[1] + sp[0])/nalt; | 
| 573 | < | r2 = (dim[2] + sp[1] - .5)/nazi; | 
| 574 | < | flatdir(dn, r1, r2); | 
| 575 | < | for (j = 0; j < 3; j++) | 
| 576 | < | dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*co->ad[j]; | 
| 577 | < | /* random location */ | 
| 570 | > | h = ilhash(dim,2) + i; | 
| 571 | > | /* randomize direction */ | 
| 572 | > | if (il->sd != NULL) { | 
| 573 | > | r_BSDF_incvec(dir, il->sd, dim[1], urand(h), xfm); | 
| 574 | > | } else { | 
| 575 | > | multisamp(sp, 2, urand(h)); | 
| 576 | > | alti = dim[1]/nazi; | 
| 577 | > | r1 = (alti + sp[0])/nalt; | 
| 578 | > | r2 = (dim[1] - alti*nazi + sp[1] - .5)/nazi; | 
| 579 | > | flatdir(dn, r1, r2); | 
| 580 | > | for (j = 0; j < 3; j++) | 
| 581 | > | dir[j] = -dn[0]*u[j] - dn[1]*v[j] - dn[2]*co->ad[j]; | 
| 582 | > | } | 
| 583 | > | /* randomize location */ | 
| 584 | > | multisamp(sp, 2, urand(h+8371)); | 
| 585 |  | r3 = sqrt(CO_R0(co)*CO_R0(co) + | 
| 586 | < | sp[2]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co))); | 
| 587 | < | r2 = 2.*PI*sp[3]; | 
| 586 | > | sp[0]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co))); | 
| 587 | > | r2 = 2.*PI*sp[1]; | 
| 588 |  | r1 = r3*cos(r2); | 
| 589 |  | r2 = r3*sin(r2); | 
| 590 | + | if (il->sd != NULL && DOT(dir, co->ad) < -FTINY) | 
| 591 | + | r3 = -1.0001*il->thick - 5.*FTINY; | 
| 592 | + | else | 
| 593 | + | r3 = 5.*FTINY; | 
| 594 |  | for (j = 0; j < 3; j++) | 
| 595 |  | org[j] = CO_P0(co)[j] + r1*u[j] + r2*v[j] + | 
| 596 | < | .001*co->ad[j]; | 
| 265 | < |  | 
| 596 | > | r3*co->ad[j]; | 
| 597 |  | /* send sample */ | 
| 598 | < | raysamp(distarr+3*(dim[1]*nazi+dim[2]), org, dir, rt); | 
| 598 | > | raysamp(dim[1], org, dir); | 
| 599 |  | } | 
| 600 | < | rayflush(rt); | 
| 600 | > | /* add in direct component? */ | 
| 601 | > | if (!directvis && (il->flags & IL_LIGHT || il->sd != NULL)) { | 
| 602 | > | MAT4    ixfm; | 
| 603 | > | if (il->sd == NULL) { | 
| 604 | > | for (i = 3; i--; ) { | 
| 605 | > | ixfm[i][0] = u[i]; | 
| 606 | > | ixfm[i][1] = v[i]; | 
| 607 | > | ixfm[i][2] = co->ad[i]; | 
| 608 | > | ixfm[i][3] = 0.; | 
| 609 | > | } | 
| 610 | > | ixfm[3][0] = ixfm[3][1] = ixfm[3][2] = 0.; | 
| 611 | > | ixfm[3][3] = 1.; | 
| 612 | > | } else { | 
| 613 | > | if (!invmat4(ixfm, xfm)) | 
| 614 | > | objerror(ob, INTERNAL, | 
| 615 | > | "cannot invert BSDF transform"); | 
| 616 | > | if (!(il->flags & IL_LIGHT)) | 
| 617 | > | new_discount(); | 
| 618 | > | } | 
| 619 | > | dim[0] = random(); | 
| 620 | > | for (i = 0; i < il->nsamps; i++) { | 
| 621 | > | /* randomize location */ | 
| 622 | > | h = dim[0] + samplendx++; | 
| 623 | > | multisamp(sp, 2, urand(h)); | 
| 624 | > | r3 = sqrt(CO_R0(co)*CO_R0(co) + | 
| 625 | > | sp[0]*(CO_R1(co)*CO_R1(co) - CO_R0(co)*CO_R0(co))); | 
| 626 | > | r2 = 2.*PI*sp[1]; | 
| 627 | > | r1 = r3*cos(r2); | 
| 628 | > | r2 = r3*sin(r2); | 
| 629 | > | for (j = 0; j < 3; j++) | 
| 630 | > | org[j] = CO_P0(co)[j] + r1*u[j] + r2*v[j]; | 
| 631 | > | /* sample source rays */ | 
| 632 | > | srcsamps(il, org, co->ad, ixfm); | 
| 633 | > | } | 
| 634 | > | } | 
| 635 | > | /* wait for all rays to finish */ | 
| 636 | > | rayclean(); | 
| 637 | > | if (il->sd != NULL) {   /* run distribution through BSDF */ | 
| 638 | > | nalt = sqrt(il->sd->nout/PI) + .5; | 
| 639 | > | nazi = PI*nalt + .5; | 
| 640 | > | redistribute(il->sd, nalt, nazi, u, v, co->ad, xfm); | 
| 641 | > | done_discount(); | 
| 642 | > | if (!il->sampdens) | 
| 643 | > | il->sampdens = nalt*nazi/PI + .999; | 
| 644 | > | } | 
| 645 |  | /* write out the ring and its distribution */ | 
| 646 | < | if (average(il, distarr, nalt*nazi)) { | 
| 646 | > | if (average(il, distarr, n)) { | 
| 647 |  | if (il->sampdens > 0) | 
| 648 |  | flatout(il, distarr, nalt, nazi, u, v, co->ad); | 
| 649 |  | illumout(il, ob); | 
| 651 |  | printobj(il->altmat, ob); | 
| 652 |  | /* clean up */ | 
| 653 |  | freecone(ob); | 
| 654 | < | free((char *)distarr); | 
| 280 | < | } | 
| 281 | < |  | 
| 282 | < |  | 
| 283 | < | raysamp(res, org, dir, rt)      /* compute a ray sample */ | 
| 284 | < | float  res[3]; | 
| 285 | < | FVECT  org, dir; | 
| 286 | < | register struct rtproc  *rt; | 
| 287 | < | { | 
| 288 | < | register float  *fp; | 
| 289 | < |  | 
| 290 | < | if (rt->nrays == rt->bsiz) | 
| 291 | < | rayflush(rt); | 
| 292 | < | rt->dest[rt->nrays] = res; | 
| 293 | < | fp = rt->buf + 6*rt->nrays++; | 
| 294 | < | *fp++ = org[0]; *fp++ = org[1]; *fp++ = org[2]; | 
| 295 | < | *fp++ = dir[0]; *fp++ = dir[1]; *fp = dir[2]; | 
| 296 | < | } | 
| 297 | < |  | 
| 298 | < |  | 
| 299 | < | rayflush(rt)                    /* flush buffered rays */ | 
| 300 | < | register struct rtproc  *rt; | 
| 301 | < | { | 
| 302 | < | register int  i; | 
| 303 | < |  | 
| 304 | < | if (rt->nrays <= 0) | 
| 305 | < | return; | 
| 306 | < | bzero(rt->buf+6*rt->nrays, 6*sizeof(float)); | 
| 307 | < | errno = 0; | 
| 308 | < | if ( process(rt->pd, (char *)rt->buf, (char *)rt->buf, | 
| 309 | < | 3*sizeof(float)*(rt->nrays+1), | 
| 310 | < | 6*sizeof(float)*(rt->nrays+1)) < | 
| 311 | < | 3*sizeof(float)*(rt->nrays+1) ) | 
| 312 | < | error(SYSTEM, "error reading from rtrace process"); | 
| 313 | < | i = rt->nrays; | 
| 314 | < | while (i--) { | 
| 315 | < | rt->dest[i][0] += rt->buf[3*i]; | 
| 316 | < | rt->dest[i][1] += rt->buf[3*i+1]; | 
| 317 | < | rt->dest[i][2] += rt->buf[3*i+2]; | 
| 318 | < | } | 
| 319 | < | rt->nrays = 0; | 
| 320 | < | } | 
| 321 | < |  | 
| 322 | < |  | 
| 323 | < | mkaxes(u, v, n)                 /* compute u and v to go with n */ | 
| 324 | < | FVECT  u, v, n; | 
| 325 | < | { | 
| 326 | < | register int  i; | 
| 327 | < |  | 
| 328 | < | v[0] = v[1] = v[2] = 0.0; | 
| 329 | < | for (i = 0; i < 3; i++) | 
| 330 | < | if (n[i] < 0.6 && n[i] > -0.6) | 
| 331 | < | break; | 
| 332 | < | v[i] = 1.0; | 
| 333 | < | fcross(u, v, n); | 
| 334 | < | normalize(u); | 
| 335 | < | fcross(v, n, u); | 
| 336 | < | } | 
| 337 | < |  | 
| 338 | < |  | 
| 339 | < | rounddir(dv, alt, azi)          /* compute uniform spherical direction */ | 
| 340 | < | register FVECT  dv; | 
| 341 | < | double  alt, azi; | 
| 342 | < | { | 
| 343 | < | double  d1, d2; | 
| 344 | < |  | 
| 345 | < | dv[2] = 1. - 2.*alt; | 
| 346 | < | d1 = sqrt(1. - dv[2]*dv[2]); | 
| 347 | < | d2 = 2.*PI * azi; | 
| 348 | < | dv[0] = d1*cos(d2); | 
| 349 | < | dv[1] = d1*sin(d2); | 
| 350 | < | } | 
| 351 | < |  | 
| 352 | < |  | 
| 353 | < | flatdir(dv, alt, azi)           /* compute uniform hemispherical direction */ | 
| 354 | < | register FVECT  dv; | 
| 355 | < | double  alt, azi; | 
| 356 | < | { | 
| 357 | < | double  d1, d2; | 
| 358 | < |  | 
| 359 | < | d1 = sqrt(alt); | 
| 360 | < | d2 = 2.*PI * azi; | 
| 361 | < | dv[0] = d1*cos(d2); | 
| 362 | < | dv[1] = d1*sin(d2); | 
| 363 | < | dv[2] = sqrt(1. - alt); | 
| 654 | > | return(1); | 
| 655 |  | } |