home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************/
- /* rad.c */
- /* */
- /* Radiosity solution step routines. Algorithms used: */
- /* */
- /* General: */
- /* Back face culling of source and receiver planes. */
- /* Receiver subdivision by: visibility, intensity gradients */
- /* Chen89: */
- /* progressive refinement */
- /* Wallace89, etc: */
- /* Hierarchical bounding volumes with object bv culling */
- /* Has ray casting for visiblity testing */
- /* Haines91: shaft culling */
- /* (see documentation) */
- /* */
- /* Initial program shell taken from E. Chen in Graphics Gems II, 1991 */
- /* */
- /* Copyright (C) 1992, Bernard Kwok */
- /* All rights reserved. */
- /* Revision 1.0 */
- /* May, 1992 */
- /**********************************************************************/
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include "geo.h"
- #include "struct.h"
- #include "rad.h"
- #include "display.h"
- #include "io.h"
- #include "misc.h"
- #include "ff.h"
- #include "bvol.h"
- #include "ray.h"
- #include "scull.h"
- #include "rtime.h"
-
- #include "radmisc.h"
-
- Polygon *shootPatch; /* Current shooting patch */
- Polygon *recPatch; /* Current receiver patch */
- Polygon *prev_Shooter = 0; /* Previous shooting patch */
- float avg_rec = 0.0; /* Average percent receivers per
- iteration */
- int num_src_samples; /* Number of source samples */
-
- /**********************************************************************/
- /* Initialize list of possible receivers */
- /**********************************************************************/
- void Init_ReceiverList(p)
- RadParams *p;
- {
- int i;
- Elist *el, *tmp;
-
- if (Option.debug) printf("\t> Initializing initial receiver list\n");
- el = p->elements;
- for (i=0;i<p->num_elements;i++) {
- tmp = el->next;
- free(el);
- el = tmp;
- }
- p->num_elements = p->num_receivers = 0;
- p->eltail = p->elements = 0;
- }
-
- /**********************************************************************/
- /* Initialize structures for ray traced form factors */
- /**********************************************************************/
- void Init_RayTrace()
- {
- if (Option.debug) printf("\t> Initializing for ray traced ff\n");
- StartIntersect();
- }
-
- /**********************************************************************/
- /* Find initial set of elements to display */
- /**********************************************************************/
- void Create_Initial_ReceiverList(theScene)
- Scene *theScene;
- {
- int i,j,k;
- Scene *sptr = theScene;
- Objectt *optr;
- Mesh *mptr;
- Polygon *pptr;
-
- Init_ReceiverList(&ReadLog);
- for(i=0, optr=sptr->objects;i<sptr->num_objects;i++, optr++)
- for(j=0, mptr=optr->meshes;j<optr->num_meshes;j++, mptr++)
- for(k=0, pptr=mptr->polys;k<mptr->num_polys;k++, pptr++)
- Find_Receivers(pptr,(Polygon *)INITIAL_DISPLAY,1);
- }
-
- /**********************************************************************/
- /* Initialize radioisity parameters, not set when reading scene */
- /**********************************************************************/
- void Init_Rad(theScene)
- Scene *theScene;
- {
- if (Option.debug) printf("\n\t*** Initializing radiosity structures ***\n");
-
- /* Prepare the original scene */
- Create_Initial_ReceiverList(theScene);
-
- /* Initialize for ray traced or hemicube form-factor calcs */
- if (Option.ff_raytrace) {
- Init_RayTrace();
- if (FF_Options.shaft_cull)
- Init_ShaftStats();
- } else
- InitHemicube();
-
- /* Prepare for display of intermediate PR steps if option set */
- if (Option.show_pr_steps) {
- if (Option.debug) {
- print_View(stderr,&(ReadLog.displayView));
- printf("\t> Displaying initial results\n");
- }
- Create_Display_Buffer(ReadLog.displayView.xRes,ReadLog.displayView.yRes);
- if (Option.ambient) /* Find initial ambient term */
- ReadLog.ambient_term = Pr_Ambient_Term();
- DisplayResults(ReadLog.displayView);
- } else {
- if (Option.debug)
- print_View(stderr,&(ReadLog.displayView));
- }
- }
-
- int iteration = 1;
- /**********************************************************************/
- /* Print current iteration */
- /**********************************************************************/
- int Print_Iter()
- {
- int i;
-
- /* Print out intermediate results if specified */
- if (Option.write_result) {
- for(i=0;i<num_inter;i++)
- if ((iteration-1) == intermed[i]) {
- if (test_optik)
- Write_RadOptik(ReadLog, Option.OutSceneFilename, iteration);
- else
- Write_Rad(ReadLog, Option.OutSceneFilename, iteration);
- i = num_inter+1;
- }
- }
-
- /* LogConv_Pt(iteration, ReadLog.totalEnergyLeft); */
- LogConv_Pt(iteration, ReadLog.totalEnergyLeft / ReadLog.totalEnergy);
- printf("\n\t*** Iteration %d. Energy Left = %g (%g %%) ***\n",
- iteration, ReadLog.totalEnergyLeft,
- ReadLog.totalEnergyLeft / ReadLog.totalEnergy * 100.0);
-
- if (Option.device == FILES)
- fprintf(Option.StatFile,
- "\n\t*** Iteration %d. Energy Left = %g (%g %%) ***\n",
- iteration, ReadLog.totalEnergyLeft,
- ReadLog.totalEnergyLeft / ReadLog.totalEnergy * 100.0);
- iteration++;
- return iteration;
- }
-
- /**********************************************************************/
- /* Form linkage between this patch and all others [Hanrahan91] (not */
- /* implemented) */
- /**********************************************************************/
- void Form_Linkages(pptr)
- Polygon *pptr;
- {
- if (Option.debug)
- printf("\t> Linkages for %s%d\n", pptr->name, pptr->id);
- }
-
- /**********************************************************************/
- /* Forming of linkages between patches using BF_Refinement [Hanra91] */
- /* (not used) */
- /**********************************************************************/
- void Do_Linkage()
- {
- int i;
- Elist *Int_List;
- int Int_ListSize;
- Elist *elptr;
- Polygon *pptr;
-
- if (Option.debug) {
- printf("\n\t*** Forming patch linkages ***\n");
- }
- /* Setup list of patches to compare against others */
- Create_Initial_ReceiverList(&RadScene);
- Int_List = ReadLog.elements; /* This is wrong ! Need to fix ! */
- Int_ListSize = ReadLog.num_elements;
-
- elptr = Int_List;
- for(i=0;i<Int_ListSize;i++) {
- pptr = elptr->element;
- Init_ObjectList();
- Make_ObjectList(pptr, &Scene_BVH, 1);
- Make_ReceiverList(pptr);
- Form_Linkages(pptr);
- }
- }
-
- /**********************************************************************/
- /* Cleanup stuff, and log statistics */
- /**********************************************************************/
- void Do_Cleanup()
- {
- /* Collect statistics for rays and shaft */
- if (Option.tablelog) {
- fprintf(rlogfile,"%d \\\\\n%g \\\\\n%g \\\\\n",
- iteration-1, ReadLog.totalEnergyLeft,
- ReadLog.totalEnergyLeft / ReadLog.totalEnergy * 100.0);
- }
- /* Log CPU times */
- Print_Times(Option.StatFile, FF_Options.shaft_cull);
-
- if (Option.device == PRINT)
- EndIntersect(stdout);
- else
- EndIntersect(Option.StatFile);
- if (FF_Options.shaft_cull)
- EndShaft(TRUE, Option.StatFile);
-
- /* Log percent receivers per iteration */
- if (Option.tablelog)
- fprintf(rlogfile,"AR:%g \\\\\n", avg_rec);
-
- /* Log convergence results */
- LogConv(1,"");
-
- /* Save final image, if any (only on IRIS) */
- if (Option.show_pr_steps) {
- if (Option.write_result) {
- /* getsize(&xsize, &ysize);
- Save_Screen_Image(xsize, ysize, 3, "rad.img"); */
- }
- /* Cleanup display buffers */
- CleanUpBuffers();
- }
- }
-
- /**********************************************************************/
- /* Radiosity main algorithm */
- /**********************************************************************/
- void Do_Rad()
- {
- int xsize, ysize;
- float iter_start, iter_end;
-
- if (Option.debug) printf("\n\t*** Doing radiosity computations ***\n");
-
- LogConv(1,Option.meshfilename); /* Start logging convergence data */
-
- /* Start recording iteration */
- iter_start = Cpu_Time(&tstats.utime, &tstats.stime);
-
- while(((shootPatch = FindShootPatch()) != 0) &&
- (Print_Iter() <= ReadLog.max_iterations+1)) {
- prev_Shooter = shootPatch;
- Init_ObjectList();
- if (Option.grid) {
- Make_ObjectList(shootPatch, &Scene_BVH, 1);
- if (Option.debug)
- Print_ObjectList();
- }
- Make_ReceiverList(shootPatch);
- ComputeFormfactors(shootPatch);
- Distribute_Rad(shootPatch);
-
- if (ReadLog.num_receivers > 0) { /* Need at least 1 receiver */
- if (Option.show_pr_steps) {
- if (Option.ambient) {
- ReadLog.ambient_term = Pr_Ambient_Term();
- print_Spectra(stdout, "Ambient term", ReadLog.ambient_term);
- }
- DisplayResults(ReadLog.displayView);
- }
- } /* At least 1 receiver */
-
- Subdivide_Elements();
-
- if (Option.ff_raytrace) {
- if (Option.device == PRINT)
- EndIntersect(stdout);
- } else
- FreeSumFactors();
- }
-
- /* Stop recording iteration */
- iter_end = Cpu_Time(&tstats.utime, &tstats.stime);
- tstats.tot_time += (iter_end - iter_start);
- tstats.avg_iter += (iter_end - iter_start) / (float) (iteration-1);
- tstats.avg_ff = tstats.avg_ff / (float) (iteration-1);
- tstats.avg_shaft /= (float) (iteration-1);
- tstats.avg_ray /= (float) (iteration-1);
- avg_rec /= (float) (iteration-1);
-
- if (Option.UseVCR) { /* Stop the video */
- vcr_end_video();
- }
-
- /* Cleanup program */
- Do_Cleanup();
- }
-
- /**********************************************************************/
- /* Check if at bottom of poly tri-quad tree, i.e. poly is leaf node */
- /**********************************************************************/
- int IsLeaf(pptr, children)
- Polygon *pptr;
- int children[MAX_PATCH_CHILDREN];
- {
- int i;
- int no_children = 1; /* Assume no children */
-
- for(i=0;i<MAX_PATCH_CHILDREN;i++)
- if (pptr->child[i] != 0) {
- no_children = 0;
- children[i] = 1;
- } else {
- children[i] = 0;
- }
- return(no_children);
- }
-
- /**********************************************************************/
- /* Add polygon to element list as possible receiver */
- /**********************************************************************/
- void AddTo_ReceiverList(pptr,patches_seen)
- Polygon *pptr;
- int patches_seen;
- {
- Elist *elptr;
-
- /* printf("\t> Adding reciever[%d] %s%d = %d\n", ReadLog.num_receivers,
- pptr->name, pptr->id, patches_seen); */
- elptr = (Elist *) malloc(sizeof(Elist));
- elptr->element = pptr;
- elptr->next = 0;
- elptr->ff = 0.0; /* Reset form-factor */
- elptr->is_subdivided = 0; /* Reset subdivision flag */
- elptr->is_receiver = patches_seen; /* Mark if element is a receiver */
-
- if (ReadLog.num_elements == 0) { /* First possible receiver */
- ReadLog.elements = elptr;
- ReadLog.eltail = elptr;
- } else {
- ReadLog.eltail->next = elptr;
- ReadLog.eltail = elptr;
- }
- ReadLog.num_elements++; /* Count total # of elements */
- if (patches_seen)
- ReadLog.num_receivers++; /* Count # of receivers */
- }
-
- /**********************************************************************/
- /* Check if any of sources unshot energy will be reflected by the */
- /* receiver */
- /**********************************************************************/
- int Receiver_ReflectsEnergy(rec, src)
- Polygon *rec, *src;
- {
- int i;
- Spectra rec_p;
- Spectra src_uB;
- double pB_sum = 0.0;
- double p_sum = 0.0;
-
- rec_p = poly_reflect(rec);
- src_uB = src->unshot_B;
- pB_sum = 0.0;
- for (i=0;i<MAX_SPECTRA_SAMPLES;i++) {
- pB_sum += rec_p.samples[i] * src_uB.samples[i];
- p_sum += rec_p.samples[i];
- }
-
- /* If reflects no unshot or has no reflectance, then it is
- not a receiver. */
- if ((pB_sum == 0.0) || (p_sum == 0.0))
- return 0;
- else
- return 1;
- }
-
- /**********************************************************************/
- /* Find all elements for a poly = all leaves in tri/quad polygon tree */
- /**********************************************************************/
- void Find_Receivers(pptr,src,patches_seen)
- Polygon *pptr;
- Polygon *src;
- int patches_seen;
- {
- int i;
- int children[MAX_PATCH_CHILDREN];
- BoundingBoxType pbox;
-
- if (IsLeaf(pptr,children)) {
-
- if (src == INITIAL_DISPLAY) { /* Display all, flag is meaningless */
- AddTo_ReceiverList(pptr,1);
- }
-
- /* Do checks on geometry to see if patch is a potential receiver
- for source (only if still a possible receiver) */
- else if (patches_seen == 0) {
- AddTo_ReceiverList(pptr,0);
- }
-
- else {
- pbox = BoxPoly(pptr);
-
- if (src == pptr) { /* Can't see yourself ! */
- AddTo_ReceiverList(pptr,0);
- }
-
- else if ((pptr->Pfather != 0) &&
- (src->Pfather == pptr->Pfather || pptr->Pfather == src)) {
- AddTo_ReceiverList(pptr,0); /* Can't see your own patch */
- }
-
- /* If receiver is behind, or on the plane of the source then
- the source cannot "see" it */
- else if (Bounds_Behind_Plane(&pbox, src->normal[0], src->d)) {
- AddTo_ReceiverList(pptr,0);
- }
-
- else
- AddTo_ReceiverList(pptr,patches_seen);
- }
-
- } else {
- for(i=0;i<MAX_PATCH_CHILDREN;i++) {
- if (children[i]) Find_Receivers(pptr->child[i],src,
- patches_seen);
- }
- }
- }
-
- /**********************************************************************/
- /* Check if any of sources unshot energy will be reflected by the */
- /* receiver */
- /**********************************************************************/
- int Object_ReflectsEnergy(rec_p, src)
- Spectra rec_p;
- Polygon *src;
- {
- int i;
- Spectra src_uB;
- double pB_sum = 0.0;
-
- src_uB = src->unshot_B;
- pB_sum = 0.0;
- for (i=0;i<MAX_SPECTRA_SAMPLES;i++)
- pB_sum += rec_p.samples[i] * src_uB.samples[i];
-
- /* If reflects no unshot or has no reflectance, then is
- not a receiver ! */
- if (pB_sum == 0.0)
- return 0;
- else
- return 1;
- }
-
- /**********************************************************************/
- /* Find potential receivers. Use some culling to speed up stuff */
- /**********************************************************************/
- void Make_ReceiverList(shootPatch)
- Polygon *shootPatch;
- {
- int i,j,k;
- int patches_seen;
- Scene *sptr = &RadScene;
- Objectt *optr;
- Object_List *olptr;
- Mesh *mptr;
- Polygon *pptr;
- Spectra rec_p;
-
- if (Option.debug) printf("\n\t> Finding receivers\n");
-
- /* Empty list of potential receivers, and then scan all
- polygons for potential receivers */
-
- Init_ReceiverList(&ReadLog);
-
- /* Use bounding volumes to try and reduce number of receivers */
- if (Option.grid) {
- for(i=0, olptr=objlist;i<objlist_size;i++, olptr = olptr->next) {
- optr = olptr->hbox->object;
-
- /* If object's bounding volume can be seen, and object will
- reflect some energy then assume polygon is a receiver */
- if (olptr->is_receiver) {
- rec_p = obj_reflect(optr);
- olptr->is_receiver = Object_ReflectsEnergy(rec_p, shootPatch);
- }
- patches_seen = olptr->is_receiver;
- for(j=0, mptr=optr->meshes; j<optr->num_meshes;j++,mptr++)
- for(k=0, pptr=mptr->polys;k<mptr->num_polys;k++, pptr++) {
-
- /* Find potential receivers = elements of patches */
- Find_Receivers(pptr,shootPatch,patches_seen);
- }
- }
- }
-
- /* Don't use bounding volumes. Must scan all objects */
- else {
- for(i=0, optr=sptr->objects;i<sptr->num_objects;i++, optr++) {
-
- /* if object can reflect some energy then assume polygon
- is a receiver */
- rec_p = obj_reflect(optr);
- patches_seen = Object_ReflectsEnergy(rec_p, shootPatch);
-
- for(j=0, mptr=optr->meshes;j<optr->num_meshes;j++, mptr++)
- for(k=0, pptr=mptr->polys;k<mptr->num_polys;k++, pptr++) {
-
- /* Find potential receivers = elements of patches */
- Find_Receivers(pptr,shootPatch,patches_seen);
- }
- }
- }
- printf("\tNumber of receivers / total = %d / %d\n",
- ReadLog.num_receivers, ReadLog.num_elements);
- if (Option.statistics) {
- if (Option.device == FILES)
- fprintf(Option.StatFile,"\tNumber of receivers / total = %d / %d\n",
- ReadLog.num_receivers, ReadLog.num_elements);
- avg_rec += (float) ReadLog.num_receivers / (float)ReadLog.num_elements;
- }
- }
-
- /**********************************************************************/
- /* Print current shooting patch */
- /**********************************************************************/
- void Print_ShootPatch(pptr, fptr, energySum)
- Polygon *pptr;
- FILE *fptr;
- double energySum;
- {
- FILE *fp;
-
- if (Option.device == PRINT)
- fp = stdout;
- else fp = fptr;
- fprintf(fp,"\tShooter %s%d unshot: %g %g %g -> %g\n",
- pptr->name, pptr->id, pptr->unshot_B.samples[0],
- pptr->unshot_B.samples[1], pptr->unshot_B.samples[2], energySum);
- }
-
- /**********************************************************************/
- /* Find next shooting patch based on unshot energy for each patch */
- /* Return 0 if convergence is reached, otherwise return 1 */
- /**********************************************************************/
- Polygon *FindShootPatch()
- {
- Polygon *shootPatch;
- int i,j,k,l;
- double energySum, error, maxEnergySum;
- Scene *sptr = &RadScene;
- Objectt *optr;
- Mesh *mptr;
- Polygon *pptr;
-
- if (Option.debug) printf("\n\t> Finding shooting patch\n");
-
- maxEnergySum = 0.0;
- shootPatch = 0;
-
- /* Scan all polygons for energy levels, and potential receivers */
- ReadLog.totalEnergyLeft = 0.0;
- for(i=0, optr=sptr->objects;i<sptr->num_objects;i++, optr++)
- for(j=0, mptr=optr->meshes;j<optr->num_meshes;j++, mptr++)
- for(k=0, pptr=mptr->polys;k<mptr->num_polys;k++, pptr= pptr->next) {
-
- /* Find patch with maximum energy to shoot
- and compute total energy left in scene */
- energySum = 0.0;
- for (l=0;l<MAX_SPECTRA_SAMPLES; l++) {
- energySum = energySum + (pptr->unshot_B.samples[l] * pptr->area);
- }
- ReadLog.totalEnergyLeft += energySum;
-
- if (energySum > maxEnergySum) {
- if (pptr != prev_Shooter) {
- shootPatch = pptr;
- maxEnergySum = energySum;
- }
- }
- }
-
- if (shootPatch == 0) /* No shooting patch found */
- return(0);
-
- /* Check for convergence */
- error = maxEnergySum / ReadLog.totalEnergy;
- if (error < ReadLog.threshold)
- return(0);
- else {
- Print_ShootPatch(shootPatch, Option.StatFile, maxEnergySum);
- printf("\t\tShooting patch has energy %g\n", maxEnergySum);
- if (Option.debug) {
- fprintf(stdout,"\t> Shooting Patch is:\n");
- print_Polygon(stdout,"",shootPatch);
- }
- return(shootPatch);
- }
- }
-
- /**********************************************************************/
- /* Find approximate centre of a polygon. Average of vertices used. */
- /**********************************************************************/
- Vector Poly_Center(pptr)
- Polygon *pptr;
- {
- int i;
- Vector center;
- double ratio;
-
- center.x = center.y = center.z = 0.0;
- ratio = 1.0 / (double) pptr->numVert;
- for(i=0;i<pptr->numVert;i++) {
- center.x += pptr->vert[i]->pos.x;
- center.y += pptr->vert[i]->pos.y;
- center.z += pptr->vert[i]->pos.z;
- }
- center.x = center.x * ratio;
- center.y = center.y * ratio;
- center.z = center.z * ratio;
- return(center);
- }
-
- /**********************************************************************/
- /* Check for receiver subdivision due to: */
- /* 1) Form factor > unity. */
- /* 2) Form factor gradient > gradient threshold. */
- /* Return whether did subdivision or not. */
- /**********************************************************************/
- int Receiver_Subdivision(ff, eptr, vtx_ff)
- double *ff;
- Polygon *eptr;
- double vtx_ff[MAX_PATCH_VTX];
- {
- int i,ii;
- int do_subdiv = 0;
- double ff_diff;
- int level_area = 0;
-
- if (Option.debug) printf("\tDoing subdivision tests...\n");
-
- /* TEST 1 : Is ff > one */
- if (*ff > 1.0) {
- if (Option.debug)
- printf("\t++ Form factor %g > 1. Subdividing poly\n", *ff);
- *ff = 1.0;
- do_subdiv = 1; /* Do subdivision */
- }
-
- if (eptr->level >= FF_Options.max_levels) /* Only to max level */
- return 0;
- if (eptr->area <= FF_Options.min_element_area) /* Only to min area */
- return 0;
-
- /* Only for ray cast ff computations. */
- if ((Option.ff_raytrace) && (do_subdiv==0) &&
- (eptr->level < FF_Options.max_levels)) {
- i = 0;
- while ((do_subdiv==0) && (i<eptr->numVert)) {
- ii = (i + 1) % eptr->numVert;
-
- /* TEST 2 : ff gradient is too large between vertices of
- edges on the polygon, stop if too small */
- ff_diff = fabs(vtx_ff[i] - vtx_ff[ii]);
- if (ff_diff > FF_Options.F_diff_edge) {
- if (Option.debug)
- printf("\t++ F diff = %g - %g = %g. Subdividing poly\n",
- vtx_ff[i], vtx_ff[ii], ff_diff);
- do_subdiv = 1; /* Do subdivision */
- }
-
- else {
- i++;
- }
- }
- }
- return (do_subdiv);
- }
-
- /**********************************************************************/
- /* Use hemicube to calculate form-factor from shooting patch to */
- /* receiver elements. */
- /* (Modified from Eric Chen (Graphics Gems II), 1991) */
- /**********************************************************************/
- void ff_Hemicube(shootPatch)
- Polygon *shootPatch;
- {
- long i;
- Vector up[5];
- Vector lookat[5];
- Vector center;
- Vector normal, tangentU, tangentV, vec;
- int face;
- double norm_length;
- Polygon *sp; /* Shooting patch */
- Elist *elptr; /* Receiving elements */
- double *fp;
- long receiver_num = 0;
-
- /* Get center of shootPatch */
- sp = shootPatch;
- center = Poly_Center(sp);
- if (Option.debug)
- printf("\t ** Poly center is %g,%g,%g\n",center.x, center.y, center.z);
- normal = sp->normal[0];
-
- /* rotate hemicube along normal axis of patch randomly */
- /* will reduce hemicube aliasing artifacts */
- do {
- vec.x = RandomFloat;
- vec.y = RandomFloat;
- vec.z = RandomFloat;
- tangentU = cross(&normal, &vec);
- norm_length = norm(&tangentU);
- } while(norm_length == 0);
-
- /* compute tangentV */
- tangentV = cross(&normal, &tangentU);
-
- /* assign lookats, and ups for each hemicube face */
- lookat[0] = *vadd(¢er, &normal);
- up[0] = tangentU;
- lookat[1] = *vadd(¢er, &tangentU);
- up[1] = normal;
- lookat[2] = *vadd(¢er, &tangentV);
- up[2] = normal;
- lookat[3] = *vsub(¢er, &tangentU);
- up[3] = normal;
- lookat[4] = *vsub(¢er, &tangentV);
- up[4] = normal;
-
- /* place cube at center of shooting patch */
- hemicube.view.lookfrom = center;
-
- /* Allocate temporary ff space of size of (number of receivers in scene) */
- /* Note: this # changes with subdivision */
- InitSumFactors(ReadLog.num_receivers);
-
- for (face=0;face<5;face++) {
- hemicube.view.lookat = lookat[face];
- hemicube.view.lookup = up[face];
-
- /* Only draw receiver elements */
- receiver_num = 0;
- if (Option.show_pr_steps)
- Begin_DrawHC(hemicube.view, kBackgroundItem, face);
- for (i=0, elptr=ReadLog.elements;i<ReadLog.num_elements;i++) {
- if (elptr->is_receiver) {
- Draw_Element(elptr->element, (unsigned long) receiver_num++);
- }
- elptr = elptr->next;
- }
- if (Option.show_pr_steps)
- End_DrawHC();
-
- /* if (Option.debug) printf("+ summing delta ff\n"); */
- if (face==0)
- SumFactors(hemicube.view.xRes, hemicube.view.yRes,
- hemicube.view.buffer, hemicube.topFactors);
- else
- SumFactors(hemicube.view.xRes, hemicube.view.yRes/2,
- hemicube.view.buffer, hemicube.topFactors);
- }
-
- /* Compute reciprocal form-factors, save in receiver list. */
- elptr = ReadLog.elements;
- fp = formfactors;
-
- for (i=0;i<ReadLog.num_elements; i++) {
- if (elptr->is_receiver) {
- elptr->ff = *fp * sp->area / elptr->element->area;
-
- /* Check for receiver subdivision */
- elptr->is_subdivided =
- Receiver_Subdivision(&elptr->ff, elptr->element, (double *)0);
- fp++;
- }
- elptr = elptr->next;
- }
- }
-
- /**********************************************************************/
- /* Use ray tracing to compute form factors */
- /**********************************************************************/
- void ff_RayTrace(shootPatch)
- Polygon*shootPatch;
- {
- int i;
- Elist *elptr; /* Receiving elements */
- Polygon *recPatch;
- BoundingBoxType sbox, rbox; /* Source / Receiver bboxes */
- Sampletype src_samples[MAX_SAMPLES]; /* Samples of source */
- Vector src_corners[MAX_PATCH_VTX];
- int patches_close = 0;
- int tmp;
- float shaft_start, shaft_end;
-
- /* Find corners of source area, and generate sample points on
- source patch */
- for(i=0;i<shootPatch->numVert;i++)
- src_corners[i] = shootPatch->vert[i]->pos;
- num_src_samples =
- ff_Generate_Patch_Samples(shootPatch,src_samples,
- src_corners, shootPatch->area,
- shootPatch->normal[0]);
-
- /* Create source bbox if shaft culling */
- if (FF_Options.shaft_cull) {
- StartShaft();
- sbox = BoxPoly(shootPatch);
- }
-
- /* Calculate element to shooting patch form factors for
- all potential receivers */
- elptr = ReadLog.elements;
- for (i=0;i<ReadLog.num_elements;i++) {
- if (elptr->is_receiver) {
- recPatch = elptr->element;
-
- /* Shaft cull bounding volume hierarchy of scene */
- if (FF_Options.shaft_cull) {
- Init_ObjectList();
- rbox = BoxPoly(recPatch);
-
- shaft_start = Cpu_Time(&tstats.utime, &tstats.stime);
- ShaftCull(shootPatch, recPatch, sbox, rbox, &Scene_BVH);
- shaft_end = Cpu_Time(&tstats.utime, &tstats.stime);
- tstats.avg_shaft += (shaft_end - shaft_start);
-
- if (Option.debug) {
- Print_Shaft(shootPatch, recPatch, stdout);
- Print_CandidateList();
- }
- }
-
- /* Only do source, receiver plane culling */
- else if (FF_Options.src_rec_cull)
- Cull_ObjectList(recPatch);
-
- if (FF_Options.use_analytic)
- if (patches_close = Patches_Abut(shootPatch, recPatch)) {
- tmp = FF_Options.fftype; FF_Options.fftype = ANALYTIC_FF;
- }
-
- /* Use equal weight per vtx ff to get patch ff */
- elptr->ff = ff_patches(shootPatch, recPatch,
- elptr->vtx_ff, num_src_samples,
- src_samples, src_corners) /
- (double) elptr->element->numVert;
- if (FF_Options.use_analytic)
- if (patches_close) FF_Options.fftype = tmp;
-
- /* Check for receiver subdivision */
- if (elptr->ff < 0.0) elptr->ff = 0.0;
- elptr->is_subdivided =
- Receiver_Subdivision(&elptr->ff, recPatch, elptr->vtx_ff);
- if (elptr->ff > 1.0) elptr->ff = 1.0;
- }
- elptr = elptr->next;
- }
-
- if (FF_Options.shaft_cull) EndShaft(FALSE, Option.StatFile);
- }
-
- /**********************************************************************/
- /* Use ray tracing to compute form factors */
- /**********************************************************************/
- void Subdivide_Elements()
- {
- int i;
- Elist *elptr; /* Receiving elements */
-
- elptr = ReadLog.elements;
- for (i=0;i<ReadLog.num_elements;i++, elptr=elptr->next) {
- if (elptr->is_receiver)
- if (elptr->is_subdivided)
- Subdivide_Polygon(elptr->element);
- }
- }
-
- /**********************************************************************/
- /* Calc form-factors from shooting patch to every element */
- /**********************************************************************/
- void ComputeFormfactors(shootPatch)
- Polygon *shootPatch;
- {
- if (Option.debug) printf("\n\t> Computing form factors\n");
-
- /* Compute form-factors */
- if (Option.ff_raytrace)
- ff_RayTrace(shootPatch); /* Element to shooting patch factors */
- else
- ff_Hemicube(shootPatch); /* Shooting patch to element factors */
- }
-
- /**********************************************************************/
- /* Distribute energy to elements */
- /**********************************************************************/
- void Distribute_Rad(shootPatch)
- Polygon *shootPatch;
- {
- long i,j,k;
- Polygon *ep; /* Receiver to update */
- Elist *elptr; /* List of receivers */
- Spectra delta_B; /* Change in patch radiosity */
- Spectra vtx_delta_B[MAX_PATCH_VTX]; /* Change in vertex radiosity */
- double weight; /* Weight of element to patch */
- Spectra element_p; /* Elements reflectance */
- double element_ff; /* Elements form factor */
-
- if (Option.debug) printf("\n\t> Distributing energy\n");
-
- /* Distribute unshot radiosity to every element */
- elptr = ReadLog.elements;
- for (i=0;i<ReadLog.num_elements;i++, elptr=elptr->next) {
- if (elptr->is_receiver) {
- ep = elptr->element;
- element_ff = elptr->ff;
-
- if (element_ff != 0.0) {
- element_p = poly_reflect(ep);
-
- /* Store vertex radiosity changes, and compute patch changes */
- if (Option.ff_raytrace) {
- weight = 1.0; /* (1.0 / ep->numVert); */
- for(k=0;k<ep->numVert;k++) {
- for (j=0;j<MAX_SPECTRA_SAMPLES;j++) {
- delta_B.samples[j] = 0.0;
- vtx_delta_B[k].samples[j] = shootPatch->unshot_B.samples[j] *
- elptr->vtx_ff[k] * element_p.samples[j];
- }
- for (j=0;j<MAX_SPECTRA_SAMPLES;j++) {
- delta_B.samples[j] += (weight * vtx_delta_B[k].samples[j]);
- }
- }
- }
-
- /* Used hemicube: store patch changes only */
- else {
- for (j=0;j<MAX_SPECTRA_SAMPLES;j++) {
- delta_B.samples[j] = shootPatch->unshot_B.samples[j] *
- element_ff * element_p.samples[j];
- for(k=0;k<ep->numVert;k++)
- vtx_delta_B[k].samples[j] = shootPatch->unshot_B.samples[j] *
- elptr->vtx_ff[k] * element_p.samples[j];
- }
- }
-
- /* Update element's radiosity and patch's unshot radiosity */
- if (ep->Pfather != 0)
- weight = ep->area / ep->Pfather->area;
- else
- weight = 1.0;
- for (j=0;j<MAX_SPECTRA_SAMPLES; j++) {
- ep->B.samples[j] += delta_B.samples[j];
-
- for(k=0;k<ep->numVert;k++) {
- ep->vtx_B[k].samples[j] += vtx_delta_B[k].samples[j];
- }
-
- if (ep->Pfather != 0) {
- ep->Pfather->unshot_B.samples[j] +=
- (delta_B.samples[j] * weight);
- } else {
- ep->unshot_B.samples[j] += delta_B.samples[j];
- }
- }
-
- /* Some debugging statistics */
- if (Option.debug) {
- printf("\t+ Rec %s%d: p = %g,%g,%g; ff = %g\n", ep->name, ep->id,
- element_p.samples[0], element_p.samples[1],
- element_p.samples[2], element_ff);
-
- if (Option.ff_raytrace == 0) {
- printf("\t++ delta_B = %g,%g,%g; Shoot unshot = %g,%g,%g\n",
- delta_B.samples[0], delta_B.samples[1], delta_B.samples[2],
- shootPatch->unshot_B.samples[0],
- shootPatch->unshot_B.samples[1],
- shootPatch->unshot_B.samples[2]);
- } else {
- for(k=0;k<ep->numVert;k++) {
- printf("\t++ v[%d]: delta_B = %g,%g,%g, B = %g,%g,%g\n",
- k, vtx_delta_B[k].samples[0], vtx_delta_B[k].samples[1],
- vtx_delta_B[k].samples[2], ep->vtx_B[k].samples[0],
- ep->vtx_B[k].samples[1], ep->vtx_B[k].samples[2]);
- }
- }
- }
-
- } /* ff != 0 */
- } /* is receiver */
- }
-
- /* reset shooting patch's unshot rad */
- for(i=0;i<MAX_SPECTRA_SAMPLES;i++)
- shootPatch->unshot_B.samples[i] = 0.0;
- }
-
- /**********************************************************************/
- /* Clean up */
- /**********************************************************************/
- void CleanUp_Rad()
- {
- if (Option.debug) printf("\t*** Cleaning up radiosity structures ***\n");
-
- if (Option.ff_raytrace == 0) {
- free(hemicube.topFactors);
- free(hemicube.sideFactors);
- free(hemicube.view.buffer);
- free(formfactors);
- }
- }
-