int t_func( /* compute texture for ray */ OBJREC *m, RAY *r ) { FVECT disp; double d; MFUNC *mf; int i; if (m->oargs.nsargs < 4) objerror(m, USER, "bad # arguments"); mf = getfunc(m, 3, 0x7, 1); setfunc(m, r); errno = 0; for (i = 0; i < 3; i++) { disp[i] = evalue(mf->ep[i]); if (errno == EDOM || errno == ERANGE) { objerror(m, WARNING, "compute error"); return(0); } } if (mf->fxp != &unitxf) multv3(disp, disp, mf->fxp->xfm); if (r->rox != NULL) { multv3(disp, disp, r->rox->f.xfm); d = 1.0 / (mf->fxp->sca * r->rox->f.sca); } else d = 1.0 / mf->fxp->sca; VSUM(r->pert, r->pert, disp, d); return(0); }
extern int o_instance( /* compute ray intersection with octree */ OBJREC *o, register RAY *r ) { RAY rcont; double d; register INSTANCE *ins; register int i; /* get the octree */ ins = getinstance(o, IO_ALL); /* copy and transform ray */ rcont = *r; multp3(rcont.rorg, r->rorg, ins->x.b.xfm); multv3(rcont.rdir, r->rdir, ins->x.b.xfm); for (i = 0; i < 3; i++) rcont.rdir[i] /= ins->x.b.sca; rcont.rmax *= ins->x.b.sca; /* clear and trace it */ rayclear(&rcont); if (!localhit(&rcont, &ins->obj->scube)) return(0); /* missed */ if (rcont.rot * ins->x.f.sca >= r->rot) return(0); /* not close enough */ if (o->omod != OVOID) { /* if we have modifier, use it */ r->ro = o; r->rox = NULL; } else { /* else use theirs */ r->ro = rcont.ro; if (rcont.rox != NULL) { newrayxf(r); /* allocate transformation */ /* NOTE: r->rox may equal rcont.rox! */ multmat4(r->rox->f.xfm, rcont.rox->f.xfm, ins->x.f.xfm); r->rox->f.sca = rcont.rox->f.sca * ins->x.f.sca; multmat4(r->rox->b.xfm, ins->x.b.xfm, rcont.rox->b.xfm); r->rox->b.sca = ins->x.b.sca * rcont.rox->b.sca; } else r->rox = &ins->x; } /* transform it back */ r->rot = rcont.rot * ins->x.f.sca; multp3(r->rop, rcont.rop, ins->x.f.xfm); multv3(r->ron, rcont.ron, ins->x.f.xfm); multv3(r->pert, rcont.pert, ins->x.f.xfm); d = 1./ins->x.f.sca; for (i = 0; i < 3; i++) { r->ron[i] *= d; r->pert[i] *= d; } r->rod = rcont.rod; r->uv[0] = rcont.uv[0]; r->uv[1] = rcont.uv[1]; /* return hit */ return(1); }
static void getacoords_as( /* set up coordinate system */ ASHIKDAT *np ) { MFUNC *mf; int i; mf = getfunc(np->mp, 3, 0x7, 1); setfunc(np->mp, np->rp); errno = 0; for (i = 0; i < 3; i++) np->u[i] = evalue(mf->ep[i]); if ((errno == EDOM) | (errno == ERANGE)) { objerror(np->mp, WARNING, "compute error"); np->specfl |= SPA_BADU; return; } if (mf->fxp != &unitxf) multv3(np->u, np->u, mf->fxp->xfm); fcross(np->v, np->pnorm, np->u); if (normalize(np->v) == 0.0) { objerror(np->mp, WARNING, "illegal orientation vector"); np->specfl |= SPA_BADU; return; } fcross(np->u, np->v, np->pnorm); }
static void getacoords( /* set up coordinate system */ ANISODAT *np ) { MFUNC *mf; int i; mf = getfunc(np->mp, 3, 0x7, 1); setfunc(np->mp, np->rp); errno = 0; for (i = 0; i < 3; i++) np->u[i] = evalue(mf->ep[i]); if ((errno == EDOM) | (errno == ERANGE)) np->u[0] = np->u[1] = np->u[2] = 0.0; if (mf->fxp != &unitxf) multv3(np->u, np->u, mf->fxp->xfm); fcross(np->v, np->pnorm, np->u); if (normalize(np->v) == 0.0) { if (fabs(np->u_alpha - np->v_alpha) > 0.001) objerror(np->mp, WARNING, "illegal orientation vector"); getperpendicular(np->u, np->pnorm); /* punting */ fcross(np->v, np->pnorm, np->u); np->u_alpha = np->v_alpha = sqrt( 0.5 * (np->u_alpha*np->u_alpha + np->v_alpha*np->v_alpha) ); } else fcross(np->u, np->v, np->pnorm); }
void xf_xfmvect(FVECT v1, FVECT v2) /* transform a vector using current matrix */ { if (xf_context == NULL) { VCOPY(v1, v2); return; } multv3(v1, v2, xf_context->xf.xfm); }
static int setbrdfunc( /* set up brdf function and variables */ BRDFDAT *np ) { FVECT vec; if (setfunc(np->mp, np->pr) == 0) return(0); /* it's OK, setfunc says we're done */ /* else (re)assign special variables */ multv3(vec, np->pnorm, funcxf.xfm); varset("NxP", '=', vec[0]/funcxf.sca); varset("NyP", '=', vec[1]/funcxf.sca); varset("NzP", '=', vec[2]/funcxf.sca); varset("RdotP", '=', np->pdot <= -1.0 ? -1.0 : np->pdot >= 1.0 ? 1.0 : np->pdot); varset("CrP", '=', colval(np->mcolor,RED)); varset("CgP", '=', colval(np->mcolor,GRN)); varset("CbP", '=', colval(np->mcolor,BLU)); return(1); }
static void dirbrdf( /* compute source contribution */ COLOR cval, /* returned coefficient */ void *nnp, /* material data */ FVECT ldir, /* light source direction */ double omega /* light source size */ ) { BRDFDAT *np = nnp; double ldot; double dtmp; COLOR ctmp; FVECT ldx; static double vldx[5], pt[MAXDIM]; char **sa; int i; #define lddx (vldx+1) setcolor(cval, 0.0, 0.0, 0.0); ldot = DOT(np->pnorm, ldir); if (ldot <= FTINY && ldot >= -FTINY) return; /* too close to grazing */ if (ldot < 0.0 ? np->trans <= FTINY : np->trans >= 1.0-FTINY) return; /* wrong side */ if (ldot > 0.0) { /* * Compute and add diffuse reflected component to returned * color. The diffuse reflected component will always be * modified by the color of the material. */ copycolor(ctmp, np->rdiff); dtmp = ldot * omega / PI; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } else { /* * Diffuse transmitted component. */ copycolor(ctmp, np->tdiff); dtmp = -ldot * omega / PI; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } if (ldot > 0.0 ? np->rspec <= FTINY : np->tspec <= FTINY) return; /* diffuse only */ /* set up function */ setbrdfunc(np); sa = np->mp->oargs.sarg; errno = 0; /* transform light vector */ multv3(ldx, ldir, funcxf.xfm); for (i = 0; i < 3; i++) lddx[i] = ldx[i]/funcxf.sca; lddx[3] = omega; /* compute BRTDF */ if (np->mp->otype == MAT_BRTDF) { if (sa[6][0] == '0') /* special case */ colval(ctmp,RED) = 0.0; else colval(ctmp,RED) = funvalue(sa[6], 4, lddx); if (sa[7][0] == '0') colval(ctmp,GRN) = 0.0; else if (!strcmp(sa[7],sa[6])) colval(ctmp,GRN) = colval(ctmp,RED); else colval(ctmp,GRN) = funvalue(sa[7], 4, lddx); if (!strcmp(sa[8],sa[6])) colval(ctmp,BLU) = colval(ctmp,RED); else if (!strcmp(sa[8],sa[7])) colval(ctmp,BLU) = colval(ctmp,GRN); else colval(ctmp,BLU) = funvalue(sa[8], 4, lddx); dtmp = bright(ctmp); } else if (np->dp == NULL) { dtmp = funvalue(sa[0], 4, lddx); setcolor(ctmp, dtmp, dtmp, dtmp); } else { for (i = 0; i < np->dp->nd; i++) pt[i] = funvalue(sa[3+i], 4, lddx); vldx[0] = datavalue(np->dp, pt); dtmp = funvalue(sa[0], 5, vldx); setcolor(ctmp, dtmp, dtmp, dtmp); } if ((errno == EDOM) | (errno == ERANGE)) { objerror(np->mp, WARNING, "compute error"); return; } if (dtmp <= FTINY) return; if (ldot > 0.0) { /* * Compute reflected non-diffuse component. */ if ((np->mp->otype == MAT_MFUNC) | (np->mp->otype == MAT_MDATA)) multcolor(ctmp, np->mcolor); dtmp = ldot * omega * np->rspec; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } else { /* * Compute transmitted non-diffuse component. */ if ((np->mp->otype == MAT_TFUNC) | (np->mp->otype == MAT_TDATA)) multcolor(ctmp, np->mcolor); dtmp = -ldot * omega * np->tspec; scalecolor(ctmp, dtmp); addcolor(cval, ctmp); } #undef lddx }
int o_cone( /* intersect ray with cone */ OBJREC *o, RAY *r ) { FVECT rox, rdx; double a, b, c; double root[2]; int nroots, rn; CONE *co; int i; /* get cone structure */ co = getcone(o, 1); /* * To intersect a ray with a cone, we transform the * ray into the cone's normalized space. This greatly * simplifies the computation. * For a cone or cup, normalization results in the * equation: * * x*x + y*y - z*z == 0 * * For a cylinder or tube, the normalized equation is: * * x*x + y*y - r*r == 0 * * A normalized ring obeys the following set of equations: * * z == 0 && * x*x + y*y >= r0*r0 && * x*x + y*y <= r1*r1 */ /* transform ray */ multp3(rox, r->rorg, co->tm); multv3(rdx, r->rdir, co->tm); /* compute intersection */ if (o->otype == OBJ_CONE || o->otype == OBJ_CUP) { a = rdx[0]*rdx[0] + rdx[1]*rdx[1] - rdx[2]*rdx[2]; b = 2.0*(rdx[0]*rox[0] + rdx[1]*rox[1] - rdx[2]*rox[2]); c = rox[0]*rox[0] + rox[1]*rox[1] - rox[2]*rox[2]; } else if (o->otype == OBJ_CYLINDER || o->otype == OBJ_TUBE) { a = rdx[0]*rdx[0] + rdx[1]*rdx[1]; b = 2.0*(rdx[0]*rox[0] + rdx[1]*rox[1]); c = rox[0]*rox[0] + rox[1]*rox[1] - CO_R0(co)*CO_R0(co); } else { /* OBJ_RING */ if (rdx[2] <= FTINY && rdx[2] >= -FTINY) return(0); /* parallel */ root[0] = -rox[2]/rdx[2]; if (root[0] <= FTINY || root[0] >= r->rot) return(0); /* distance check */ b = root[0]*rdx[0] + rox[0]; c = root[0]*rdx[1] + rox[1]; a = b*b + c*c; if (a < CO_R0(co)*CO_R0(co) || a > CO_R1(co)*CO_R1(co)) return(0); /* outside radii */ r->ro = o; r->rot = root[0]; VSUM(r->rop, r->rorg, r->rdir, r->rot); VCOPY(r->ron, co->ad); r->rod = -rdx[2]; r->rox = NULL; return(1); /* good */ } /* roots for cone, cup, cyl., tube */ nroots = quadratic(root, a, b, c); for (rn = 0; rn < nroots; rn++) { /* check real roots */ if (root[rn] <= FTINY) continue; /* too small */ if (root[rn] >= r->rot) break; /* too big */ /* check endpoints */ VSUM(rox, r->rorg, r->rdir, root[rn]); VSUB(rdx, rox, CO_P0(co)); b = DOT(rdx, co->ad); if (b < 0.0) continue; /* before p0 */ if (b > co->al) continue; /* after p1 */ r->ro = o; r->rot = root[rn]; VCOPY(r->rop, rox); /* get normal */ if (o->otype == OBJ_CYLINDER) a = CO_R0(co); else if (o->otype == OBJ_TUBE) a = -CO_R0(co); else { /* OBJ_CONE || OBJ_CUP */ c = CO_R1(co) - CO_R0(co); a = CO_R0(co) + b*c/co->al; if (o->otype == OBJ_CUP) { c = -c; a = -a; } } for (i = 0; i < 3; i++) r->ron[i] = (rdx[i] - b*co->ad[i])/a; if (o->otype == OBJ_CONE || o->otype == OBJ_CUP) for (i = 0; i < 3; i++) r->ron[i] = (co->al*r->ron[i] - c*co->ad[i]) / co->sl; a = DOT(r->ron, r->ron); if (a > 1.+FTINY || a < 1.-FTINY) { c = 1./(.5 + .5*a); /* avoid numerical error */ r->ron[0] *= c; r->ron[1] *= c; r->ron[2] *= c; } r->rod = -DOT(r->rdir, r->ron); r->pert[0] = r->pert[1] = r->pert[2] = 0.0; r->uv[0] = r->uv[1] = 0.0; r->rox = NULL; return(1); /* good */ } return(0); }
static int redirect( /* compute n'th ray redirection */ OBJREC *m, RAY *r, int n ) { MFUNC *mf; EPNODE **va; FVECT nsdir; RAY nr; double coef; int j; /* set up function */ mf = getdfunc(m); setfunc(m, r); /* assign direction variable */ if (r->rsrc >= 0) { SRCREC *sp = source + source[r->rsrc].sa.sv.sn; if (sp->sflags & SDISTANT) VCOPY(nsdir, sp->sloc); else { for (j = 0; j < 3; j++) nsdir[j] = sp->sloc[j] - r->rop[j]; normalize(nsdir); } multv3(nsdir, nsdir, funcxf.xfm); varset("DxA", '=', nsdir[0]/funcxf.sca); varset("DyA", '=', nsdir[1]/funcxf.sca); varset("DzA", '=', nsdir[2]/funcxf.sca); } else { varset("DxA", '=', 0.0); varset("DyA", '=', 0.0); varset("DzA", '=', 0.0); } /* compute coefficient */ errno = 0; va = mf->ep + 4*n; coef = evalue(va[0]); if ((errno == EDOM) | (errno == ERANGE)) goto computerr; setcolor(nr.rcoef, coef, coef, coef); if (rayorigin(&nr, TRANS, r, nr.rcoef) < 0) return(0); va++; /* compute direction */ for (j = 0; j < 3; j++) { nr.rdir[j] = evalue(va[j]); if (errno == EDOM || errno == ERANGE) goto computerr; } if (mf->fxp != &unitxf) multv3(nr.rdir, nr.rdir, mf->fxp->xfm); if (r->rox != NULL) multv3(nr.rdir, nr.rdir, r->rox->f.xfm); if (normalize(nr.rdir) == 0.0) goto computerr; /* compute value */ if (r->rsrc >= 0) nr.rsrc = source[r->rsrc].sa.sv.sn; rayvalue(&nr); multcolor(nr.rcol, nr.rcoef); addcolor(r->rcol, nr.rcol); if (r->ro != NULL && isflat(r->ro->otype)) r->rt = r->rot + nr.rt; return(1); computerr: objerror(m, WARNING, "compute error"); return(-1); }
static int dir_proj( /* compute a director's projection */ MAT4 pm, OBJREC *o, SRCREC *s, int n ) { RAY tr; OBJREC *m; MFUNC *mf; EPNODE **va; FVECT cent, newdir, nv, h; double coef, olddot, newdot, od; int i, j; /* initialize test ray */ getmaxdisk(cent, o); if (s->sflags & SDISTANT) for (i = 0; i < 3; i++) { tr.rdir[i] = -s->sloc[i]; tr.rorg[i] = cent[i] - tr.rdir[i]; } else { for (i = 0; i < 3; i++) { tr.rdir[i] = cent[i] - s->sloc[i]; tr.rorg[i] = s->sloc[i]; } if (normalize(tr.rdir) == 0.0) return(0); /* at source! */ } od = getplaneq(nv, o); olddot = DOT(tr.rdir, nv); if (olddot <= FTINY && olddot >= -FTINY) return(0); /* old dir parallels plane */ tr.rmax = 0.0; rayorigin(&tr, PRIMARY, NULL, NULL); if (!(*ofun[o->otype].funp)(o, &tr)) return(0); /* no intersection! */ /* compute redirection */ m = vsmaterial(o); mf = getdfunc(m); setfunc(m, &tr); varset("DxA", '=', 0.0); varset("DyA", '=', 0.0); varset("DzA", '=', 0.0); errno = 0; va = mf->ep + 4*n; coef = evalue(va[0]); if (errno == EDOM || errno == ERANGE) goto computerr; if (coef <= FTINY) return(0); /* insignificant */ va++; for (i = 0; i < 3; i++) { newdir[i] = evalue(va[i]); if (errno == EDOM || errno == ERANGE) goto computerr; } if (mf->fxp != &unitxf) multv3(newdir, newdir, mf->fxp->xfm); /* normalization unnecessary */ newdot = DOT(newdir, nv); if (newdot <= FTINY && newdot >= -FTINY) return(0); /* new dir parallels plane */ /* everything OK -- compute shear */ for (i = 0; i < 3; i++) h[i] = newdir[i]/newdot - tr.rdir[i]/olddot; setident4(pm); for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) pm[i][j] += nv[i]*h[j]; pm[3][j] = -od*h[j]; } if ((newdot > 0.0) ^ (olddot > 0.0)) /* add mirroring */ for (j = 0; j < 3; j++) { for (i = 0; i < 3; i++) pm[i][j] -= 2.*nv[i]*nv[j]; pm[3][j] += 2.*od*nv[j]; } return(1); computerr: objerror(m, WARNING, "projection compute error"); return(0); }