ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/virtuals.c
(Generate patch)

Comparing ray/src/rt/virtuals.c (file contents):
Revision 1.1 by greg, Wed Jun 19 16:36:14 1991 UTC vs.
Revision 1.6 by greg, Fri Jun 21 13:25:42 1991 UTC

# Line 11 | Line 11 | static char SCCSid[] = "$SunId$ LBL";
11  
12   #include  "ray.h"
13  
14 #include  "source.h"
15
14   #include  "otypes.h"
15  
16 < #include  "cone.h"
16 > #include  "source.h"
17  
20 #include  "face.h"
18  
19 < extern int  directrelay;                /* maximum number of source relays */
19 > double  intercircle(), getdisk();
20  
24 double  getplaneq();
25 double  getmaxdisk();
26 double  intercircle();
27 SRCREC  *makevsrc();
28
21   static OBJECT  *vobject;                /* virtual source objects */
22   static int  nvobjects = 0;              /* number of virtual source objects */
23  
# Line 40 | Line 32 | markvirtuals()                 /* find and mark virtual sources */
32                                          /* find virtual source objects */
33          for (i = 0; i < nobjects; i++) {
34                  o = objptr(i);
35 <                if (o->omod == OVOID)
35 >                if (!issurface(o->otype) || o->omod == OVOID)
36                          continue;
37                  if (!isvlight(objptr(o->omod)->otype))
38                          continue;
39 +                if (sfun[o->otype].of == NULL ||
40 +                                sfun[o->otype].of->getpleq == NULL)
41 +                        objerror(o, USER, "illegal material");
42                  if (nvobjects == 0)
43                          vobject = (OBJECT *)malloc(sizeof(OBJECT));
44                  else
# Line 55 | Line 50 | markvirtuals()                 /* find and mark virtual sources */
50          }
51          if (nvobjects == 0)
52                  return;
53 + #ifdef DEBUG
54 +        fprintf(stderr, "found %d virtual source objects\n", nvobjects);
55 + #endif
56                                          /* append virtual sources */
57          for (i = nsources; i-- > 0; )
58                  if (!(source[i].sflags & SSKIP))
59 <                        addvirtuals(&source[i], directrelay);
59 >                        addvirtuals(i, directrelay);
60                                          /* done with our object list */
61          free((char *)vobject);
62          nvobjects = 0;
63   }
64  
65  
66 < addvirtuals(sr, nr)             /* add virtual sources associated with sr */
67 < SRCREC  *sr;
66 > addvirtuals(sn, nr)             /* add virtuals associated with source */
67 > int  sn;
68   int  nr;
69   {
70          register int  i;
# Line 75 | Line 73 | int  nr;
73                  return;
74                                  /* check each virtual object for projection */
75          for (i = 0; i < nvobjects; i++)
76 <                vproject(objptr(i), sr, nr-1);  /* calls us recursively */
76 >                                        /* vproject() calls us recursively */
77 >                vproject(objptr(vobject[i]), sn, nr-1);
78   }
79  
80  
81 < SRCREC *
82 < makevsrc(op, sp, pm)            /* make virtual source if reasonable */
81 > vproject(o, sn, n)              /* create projected source(s) if they exist */
82 > OBJREC  *o;
83 > int  sn;
84 > int  n;
85 > {
86 >        register int  i;
87 >        register VSMATERIAL  *vsmat;
88 >        MAT4  proj;
89 >        int  ns;
90 >
91 >        if (o == source[sn].so) /* objects cannot project themselves */
92 >                return;
93 >                                /* get virtual source material */
94 >        vsmat = sfun[objptr(o->omod)->otype].mf;
95 >                                /* project virtual sources */
96 >        for (i = 0; i < vsmat->nproj; i++)
97 >                if ((*vsmat->vproj)(proj, o, &source[sn], i))
98 >                        if ((ns = makevsrc(o, sn, proj)) >= 0) {
99 > #ifdef DEBUG
100 >                                virtverb(ns, stderr);
101 > #endif
102 >                                addvirtuals(ns, n);
103 >                        }
104 > }
105 >
106 >
107 > int
108 > makevsrc(op, sn, pm)            /* make virtual source if reasonable */
109   OBJREC  *op;
110 < register SRCREC  *sp;
110 > register int  sn;
111   MAT4  pm;
112   {
113 <        register SRCREC  *newsrc;
89 <        FVECT  nsloc, ocent, nsnorm;
113 >        FVECT  nsloc, nsnorm, ocent;
114          double  maxrad2;
115 <        double  d1, d2;
115 >        int  nsflags;
116 >        double  d1;
117          SPOT  theirspot, ourspot;
118          register int  i;
119 +
120 +        nsflags = source[sn].sflags | (SVIRTUAL|SSPOT|SFOLLOW);
121                                          /* get object center and max. radius */
122 <        maxrad2 = getmaxdisk(ocent, op);
122 >        maxrad2 = getdisk(ocent, op, sn);
123          if (maxrad2 <= FTINY)                   /* too small? */
124 <                return(NULL);
124 >                return(-1);
125                                          /* get location and spot */
126 <        if (sp->sflags & SDISTANT) {            /* distant source */
127 <                if (sp->sflags & SPROX)
128 <                        return(NULL);           /* should never get here! */
129 <                multv3(nsloc, sp->sloc, pm);
126 >        if (source[sn].sflags & SDISTANT) {             /* distant source */
127 >                if (source[sn].sflags & SPROX)
128 >                        return(-1);             /* should never get here! */
129 >                multv3(nsloc, source[sn].sloc, pm);
130                  VCOPY(ourspot.aim, ocent);
131                  ourspot.siz = PI*maxrad2;
132                  ourspot.flen = 0.;
133 <                if (sp->sflags & SSPOT) {
134 <                        copystruct(&theirspot, sp->sl.s);
135 <                        multp3(theirspot.aim, sp->sl.s->aim, pm);
133 >                if (source[sn].sflags & SSPOT) {
134 >                        copystruct(&theirspot, source[sn].sl.s);
135 >                        multp3(theirspot.aim, source[sn].sl.s->aim, pm);
136                          if (!commonbeam(&ourspot, &theirspot, nsloc))
137 <                                return(NULL);           /* no overlap */
137 >                                return(-1);             /* no overlap */
138                  }
139          } else {                                /* local source */
140 <                multp3(nsloc, sp->sloc, pm);
114 <                if (sp->sflags & SPROX) {
115 <                        d2 = 0.;
116 <                        for (i = 0; i < 3; i++) {
117 <                                d1 = ocent[i] - nsloc[i];
118 <                                d2 += d1*d1;
119 <                        }
120 <                        if (d2 > sp->sl.prox*sp->sl.prox)
121 <                                return(NULL);   /* too far away */
122 <                }
140 >                multp3(nsloc, source[sn].sloc, pm);
141                  for (i = 0; i < 3; i++)
142                          ourspot.aim[i] = ocent[i] - nsloc[i];
143                  if ((d1 = normalize(ourspot.aim)) == 0.)
144 <                        return(NULL);           /* at source!! */
144 >                        return(-1);             /* at source!! */
145 >                if (source[sn].sflags & SPROX && d1 > source[sn].sl.prox)
146 >                        return(-1);             /* too far away */
147                  ourspot.siz = 2.*PI*(1. - d1/sqrt(d1*d1+maxrad2));
148                  ourspot.flen = 0.;
149 <                if (sp->sflags & SSPOT) {
150 <                        copystruct(&theirspot, sp->sl.s);
151 <                        multv3(theirspot.aim, sp->sl.s->aim, pm);
149 >                if (source[sn].sflags & SSPOT) {
150 >                        copystruct(&theirspot, source[sn].sl.s);
151 >                        multv3(theirspot.aim, source[sn].sl.s->aim, pm);
152                          if (!commonspot(&ourspot, &theirspot, nsloc))
153 <                                return(NULL);           /* no overlap */
153 >                                return(-1);     /* no overlap */
154                          ourspot.flen = theirspot.flen;
155                  }
156 <                if (sp->sflags & SFLAT) {       /* check for behind source */
157 <                        multv3(nsnorm, sp->snorm, pm);
156 >                if (source[sn].sflags & SFLAT) {        /* behind source? */
157 >                        multv3(nsnorm, source[sn].snorm, pm);
158                          if (checkspot(&ourspot, nsnorm) < 0)
159 <                                return(NULL);
159 >                                return(-1);
160                  }
161          }
162                                          /* everything is OK, make source */
163 <        if ((newsrc = newsource()) == NULL)
163 >        if ((i = newsource()) < 0)
164                  goto memerr;
165 <        newsrc->sflags = sp->sflags | (SVIRTUAL|SSPOT|SFOLLOW);
166 <        VCOPY(newsrc->sloc, nsloc);
167 <        if (newsrc->sflags & SFLAT)
168 <                VCOPY(newsrc->snorm, nsnorm);
169 <        newsrc->ss = sp->ss; newsrc->ss2 = sp->ss2;
170 <        if ((newsrc->sl.s = (SPOT *)malloc(sizeof(SPOT))) == NULL)
165 >        source[i].sflags = nsflags;
166 >        VCOPY(source[i].sloc, nsloc);
167 >        if (nsflags & SFLAT)
168 >                VCOPY(source[i].snorm, nsnorm);
169 >        source[i].ss = source[sn].ss; source[i].ss2 = source[sn].ss2;
170 >        if ((source[i].sl.s = (SPOT *)malloc(sizeof(SPOT))) == NULL)
171                  goto memerr;
172 <        copystruct(newsrc->sl.s, &ourspot);
173 <        if (newsrc->sflags & SPROX)
174 <                newsrc->sl.prox = sp->sl.prox;
175 <        newsrc->sa.svnext = sp - source;
176 <        return(newsrc);
172 >        copystruct(source[i].sl.s, &ourspot);
173 >        if (nsflags & SPROX)
174 >                source[i].sl.prox = source[sn].sl.prox;
175 >        source[i].sa.svnext = sn;
176 >        source[i].so = op;
177 >        return(i);
178   memerr:
179          error(SYSTEM, "out of memory in makevsrc");
180   }
181  
182  
183 + double
184 + getdisk(oc, op, sn)             /* get visible object disk */
185 + FVECT  oc;
186 + OBJREC  *op;
187 + register int  sn;
188 + {
189 +        double  rad2, roffs, offs, d, rd, rdoto;
190 +        FVECT  rnrm, nrm;
191 +                                /* first, use object getdisk function */
192 +        rad2 = (*sfun[op->otype].of->getdisk)(oc, op);
193 +        if (!(source[sn].sflags & SVIRTUAL))
194 +                return(rad2);           /* all done for normal source */
195 +                                /* check for correct side of relay surface */
196 +        roffs = (*sfun[source[sn].so->otype].of->getpleq)(rnrm, source[sn].so);
197 +        rd = DOT(rnrm, source[sn].sloc);        /* source projection */
198 +        if (!(source[sn].sflags & SDISTANT))
199 +                rd -= roffs;
200 +        d = DOT(rnrm, oc) - roffs;      /* disk distance to relay plane */
201 +        if ((d > 0.) ^ (rd > 0.))
202 +                return(rad2);           /* OK if opposite sides */
203 +        if (d*d >= rad2)
204 +                return(.0);             /* no relay is possible */
205 +                                /* we need a closer look */
206 +        offs = (*sfun[op->otype].of->getpleq)(nrm, op);
207 +        rdoto = DOT(rnrm, nrm);
208 +        if (d*d >= rad2*(1.-rdoto*rdoto))
209 +                return(0.);             /* disk entirely on projection side */
210 +                                /* should shrink disk but I'm lazy */
211 +        return(rad2);
212 + }
213 +
214 +
215   commonspot(sp1, sp2, org)       /* set sp1 to intersection of sp1 and sp2 */
216   register SPOT  *sp1, *sp2;
217   FVECT  org;
218   {
219          FVECT  cent;
220 <        double  rad2, d1r2, d2r2;
220 >        double  rad2, cos1, cos2;
221  
222 <        d1r2 = 1. - sp1->siz/(2.*PI);
223 <        d2r2 = 1. - sp2->siz/(2.*PI);
222 >        cos1 = 1. - sp1->siz/(2.*PI);
223 >        cos2 = 1. - sp2->siz/(2.*PI);
224          if (sp2->siz >= 2.*PI-FTINY)            /* BIG, just check overlap */
225 <                return(DOT(sp1->aim,sp2->aim) >= d1r2*d2r2 -
226 <                                        sqrt((1.-d1r2*d1r2)*(1.-d2r2*d2r2)));
225 >                return(DOT(sp1->aim,sp2->aim) >= cos1*cos2 -
226 >                                        sqrt((1.-cos1*cos1)*(1.-cos2*cos2)));
227                                  /* compute and check disks */
228 <        d1r2 = 1./(d1r2*d1r2) - 1.;
229 <        d2r2 = 1./(d2r2*d2r2) - 1.;
177 <        rad2 = intercircle(cent, sp1->aim, sp2->aim, d1r2, d2r2);
228 >        rad2 = intercircle(cent, sp1->aim, sp2->aim,
229 >                        1./(cos1*cos1) - 1.,  1./(cos2*cos2) - 1.);
230          if (rad2 <= FTINY || normalize(cent) == 0.)
231                  return(0);
232          VCOPY(sp1->aim, cent);
# Line 193 | Line 245 | FVECT  dir;
245                                          /* move centers to common plane */
246          d = DOT(sp1->aim, dir);
247          for (i = 0; i < 3; i++)
248 <                c1[i] = sp2->aim[i] - d*dir[i];
248 >                c1[i] = sp1->aim[i] - d*dir[i];
249          d = DOT(sp2->aim, dir);
250          for (i = 0; i < 3; i++)
251                  c2[i] = sp2->aim[i] - d*dir[i];
# Line 222 | Line 274 | FVECT  nrm;
274   }
275  
276  
225 mirrorproj(m, nv, offs)         /* get mirror projection for surface */
226 register MAT4  m;
227 FVECT  nv;
228 double  offs;
229 {
230        register int  i, j;
231                                        /* assign matrix */
232        setident4(m);
233        for (i = 0; i < 3; i++)
234                for (j = 0; j < 3; j++)
235                        m[i][j] -= 2.*nv[i]*nv[j];
236        for (j = 0; j < 3; j++)
237                m[3][j] = 2.*offs*nv[j];
238 }
239
240
277   double
278   intercircle(cc, c1, c2, r1s, r2s)       /* intersect two circles */
279   FVECT  cc;                      /* midpoint (return value) */
# Line 267 | Line 303 | double  r1s, r2s;              /* radii squared */
303                                          /* no overlap? */
304          if (a2 <= 0.)
305                  return(0.);
306 +                                        /* overlap, compute center */
307          l = sqrt((r1s - a2)/d2);
308          for (i = 0; i < 3; i++)
309                  cc[i] = c1[i] + l*disp[i];
# Line 274 | Line 311 | double  r1s, r2s;              /* radii squared */
311   }
312  
313  
277 /*
278 * The following routines depend on the supported OBJECTS:
279 */
280
281
282 double
283 getmaxdisk(ocent, op)           /* get object center and squared radius */
284 FVECT  ocent;
285 register OBJREC  *op;
286 {
287        double  maxrad2;
288
289        switch (op->otype) {
290        case OBJ_FACE:
291                {
292                        double  d1, d2;
293                        register int  i, j;
294                        register FACE  *f = getface(op);
295
296                        for (i = 0; i < 3; i++) {
297                                ocent[i] = 0.;
298                                for (j = 0; j < f->nv; j++)
299                                        ocent[i] += VERTEX(f,j)[i];
300                                ocent[i] /= (double)f->nv;
301                        }
302                        maxrad2 = 0.;
303                        for (j = 0; j < f->nv; j++) {
304                                d2 = 0.;
305                                for (i = 0; i < 3; i++) {
306                                        d1 = VERTEX(f,j)[i] - ocent[i];
307                                        d2 += d1*d1;
308                                }
309                                if (d2 > maxrad2)
310                                        maxrad2 = d2;
311                        }
312                }
313                return(maxrad2);
314        case OBJ_RING:
315                {
316                        register CONE  *co = getcone(op, 0);
317
318                        VCOPY(ocent, CO_P0(co));
319                        maxrad2 = CO_R1(co);
320                        maxrad2 *= maxrad2;
321                }
322                return(maxrad2);
323        }
324        objerror(op, USER, "illegal material");
325 }
326
327
328 double
329 getplaneq(nvec, op)                     /* get plane equation for object */
330 FVECT  nvec;
331 OBJREC  *op;
332 {
333        register FACE  *fo;
334        register CONE  *co;
335
336        switch (op->otype) {
337        case OBJ_FACE:
338                fo = getface(op);
339                VCOPY(nvec, fo->norm);
340                return(fo->offset);
341        case OBJ_RING:
342                co = getcone(op, 0);
343                VCOPY(nvec, co->ad);
344                return(DOT(nvec, CO_P0(co)));
345        }
346        objerror(op, USER, "illegal material");
347 }
348
349
350 /*
351 * The following routines depend on the supported MATERIALS:
352 */
353
354
355 vproject(o, s, n)               /* create projected source(s) if they exist */
356 OBJREC  *o;
357 SRCREC  *s;
358 int  n;
359 {
360        SRCREC  *ns;
361        FVECT  norm;
362        double  offset;
363        MAT4  proj;
364                                /* get surface normal and offset */
365        offset = getplaneq(norm, o);
366        switch (objptr(o->omod)->otype) {
367        case MAT_MIRROR:                        /* mirror source */
368                if (DOT(s->sloc, norm) <= (s->sflags & SDISTANT ?
369                                        FTINY : offset+FTINY))
370                        return;                 /* behind mirror */
371                mirrorproj(proj, norm, offset);
372                if ((ns = makevsrc(o, s, proj)) != NULL)
373                        addvirtuals(ns, n);
374                break;
375        }
376 }
377
378
379 vsrcrelay(rn, rv)               /* relay virtual source ray */
380 register RAY  *rn, *rv;
381 {
382        int  snext;
383        register int  i;
384                                        /* source we're aiming for here */
385        snext = source[rv->rsrc].sa.svnext;
386                                        /* compute relayed ray direction */
387        switch (objptr(rv->ro->omod)->otype) {
388        case MAT_MIRROR:                /* mirror: singular reflection */
389                rayorigin(rn, rv, REFLECTED, 1.);
390                                        /* ignore textures */
391                for (i = 0; i < 3; i++)
392                        rn->rdir[i] = rv->rdir[i] + 2.*rv->rod*rv->ron[i];
393                break;
314   #ifdef DEBUG
315 <        default:
316 <                error(CONSISTENCY, "inappropriate material in vsrcrelay");
317 < #endif
398 <        }
399 <        rn->rsrc = snext;
400 < }
401 <
402 <
403 < m_mirror(m, r)                  /* shade mirrored ray */
404 < register OBJREC  *m;
405 < register RAY  *r;
315 > virtverb(sn, fp)        /* print verbose description of virtual source */
316 > register int  sn;
317 > FILE  *fp;
318   {
407        COLOR  mcolor;
408        RAY  nr;
319          register int  i;
320  
321 <        if (m->oargs.nfargs != 3 || m->oargs.nsargs > 1)
322 <                objerror(m, USER, "bad number of arguments");
323 <        if (r->rsrc >= 0) {                     /* aiming for somebody */
324 <                if (source[r->rsrc].so != r->ro)
325 <                        return;                         /* but not us */
326 <        } else if (m->oargs.nsargs > 0) {       /* else call substitute? */
327 <                rayshade(r, modifier(m->oargs.sarg[0]));
321 >        fprintf(fp, "%s virtual source %d in %s %s\n",
322 >                        source[sn].sflags & SDISTANT ? "distant" : "local",
323 >                        sn, ofun[source[sn].so->otype].funame,
324 >                        source[sn].so->oname);
325 >        fprintf(fp, "\tat (%f,%f,%f)\n",
326 >                source[sn].sloc[0], source[sn].sloc[1], source[sn].sloc[2]);
327 >        fprintf(fp, "\tlinked to source %d (%s)\n",
328 >                source[sn].sa.svnext, source[source[sn].sa.svnext].so->oname);
329 >        if (source[sn].sflags & SFOLLOW)
330 >                fprintf(fp, "\talways followed\n");
331 >        else
332 >                fprintf(fp, "\tnever followed\n");
333 >        if (!(source[sn].sflags & SSPOT))
334                  return;
335 <        }
336 <        if (r->rod < 0.)                        /* back is black */
337 <                return;
422 <                                        /* get modifiers */
423 <        raytexture(r, m->omod);
424 <                                        /* assign material color */
425 <        setcolor(mcolor, m->oargs.farg[0],
426 <                        m->oargs.farg[1],
427 <                        m->oargs.farg[2]);
428 <        multcolor(mcolor, r->pcol);
429 <                                        /* compute reflected ray */
430 <        if (r->rsrc >= 0)                       /* relayed light source */
431 <                vsrcrelay(&nr, r);
432 <        else {                                  /* ordinary reflection */
433 <                FVECT  pnorm;
434 <                double  pdot;
435 <
436 <                if (rayorigin(&nr, r, REFLECTED, bright(mcolor)) < 0)
437 <                        return;
438 <                pdot = raynormal(pnorm, r);     /* use textures */
439 <                for (i = 0; i < 3; i++)
440 <                        nr.rdir[i] = r->rdir[i] + 2.*pdot*pnorm[i];
441 <        }
442 <        rayvalue(&nr);
443 <        multcolor(nr.rcol, mcolor);
444 <        addcolor(r->rcol, nr.rcol);
335 >        fprintf(fp, "\twith spot aim (%f,%f,%f) and size %f\n",
336 >                        source[sn].sl.s->aim[0], source[sn].sl.s->aim[1],
337 >                        source[sn].sl.s->aim[2], source[sn].sl.s->siz);
338   }
339 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines