/* Build our triangle mesh from recorded RBFs */ void build_mesh(void) { int nrbfs = 0, nmigs = 0; double best2 = M_PI*M_PI; RBFNODE *shrt_edj[2]; RBFNODE *rbf0, *rbf1; const MIGRATION *ej; /* average specular peak */ comp_bsdf_spec(); /* add normal if needed */ check_normal_incidence(); /* check if isotropic */ if (single_plane_incident) { for (rbf0 = dsf_list; rbf0 != NULL; rbf0 = rbf0->next) if (rbf0->next != NULL) create_migration(rbf0, rbf0->next); await_children(nchild); return; } shrt_edj[0] = shrt_edj[1] = NULL; /* start w/ shortest edge */ for (rbf0 = dsf_list; rbf0 != NULL; rbf0 = rbf0->next) { for (rbf1 = rbf0->next; rbf1 != NULL; rbf1 = rbf1->next) { double dist2 = 2. - 2.*DOT(rbf0->invec,rbf1->invec); if (dist2 < best2) { shrt_edj[0] = rbf0; shrt_edj[1] = rbf1; best2 = dist2; } } ++nrbfs; } if (shrt_edj[0] == NULL) { fprintf(stderr, "%s: Cannot find shortest edge\n", progname); exit(1); } /* build mesh from this edge */ if (shrt_edj[0]->ord < shrt_edj[1]->ord) mesh_from_edge(create_migration(shrt_edj[0], shrt_edj[1])); else mesh_from_edge(create_migration(shrt_edj[1], shrt_edj[0])); /* count up edges */ for (ej = mig_list; ej != NULL; ej = ej->next) ++nmigs; if (nmigs < nrbfs-1) /* did meshing fail? */ fprintf(stderr, "%s: warning - %d incident directions but only %d interpolant(s)\n", progname, nrbfs, nmigs); /* complete migrations */ await_children(nchild); }
/* Build our triangle mesh from recorded RBFs */ void build_mesh(void) { double best2 = M_PI*M_PI; RBFNODE *shrt_edj[2]; RBFNODE *rbf0, *rbf1; /* average specular peak */ comp_bsdf_spec(); /* add normal if needed */ check_normal_incidence(); /* check if isotropic */ if (single_plane_incident) { for (rbf0 = dsf_list; rbf0 != NULL; rbf0 = rbf0->next) if (rbf0->next != NULL) create_migration(rbf0, rbf0->next); await_children(nchild); return; } shrt_edj[0] = shrt_edj[1] = NULL; /* start w/ shortest edge */ for (rbf0 = dsf_list; rbf0 != NULL; rbf0 = rbf0->next) for (rbf1 = rbf0->next; rbf1 != NULL; rbf1 = rbf1->next) { double dist2 = 2. - 2.*DOT(rbf0->invec,rbf1->invec); if (dist2 < best2) { shrt_edj[0] = rbf0; shrt_edj[1] = rbf1; best2 = dist2; } } if (shrt_edj[0] == NULL) { fprintf(stderr, "%s: Cannot find shortest edge\n", progname); exit(1); } /* build mesh from this edge */ if (shrt_edj[0]->ord < shrt_edj[1]->ord) mesh_from_edge(create_migration(shrt_edj[0], shrt_edj[1])); else mesh_from_edge(create_migration(shrt_edj[1], shrt_edj[0])); /* complete migrations */ await_children(nchild); }
/* Create new migration edge and grow mesh recursively around it */ static void mesh_from_edge(MIGRATION *edge) { MIGRATION *ej0, *ej1; RBFNODE *tvert[2]; if (edge == NULL) return; /* triangle on either side? */ get_triangles(tvert, edge); if (tvert[0] == NULL) { /* grow mesh on right */ tvert[0] = find_chull_vert(edge->rbfv[0], edge->rbfv[1]); if (tvert[0] != NULL) { if (tvert[0]->ord > edge->rbfv[0]->ord) ej0 = create_migration(edge->rbfv[0], tvert[0]); else ej0 = create_migration(tvert[0], edge->rbfv[0]); if (tvert[0]->ord > edge->rbfv[1]->ord) ej1 = create_migration(edge->rbfv[1], tvert[0]); else ej1 = create_migration(tvert[0], edge->rbfv[1]); mesh_from_edge(ej0); mesh_from_edge(ej1); return; } } if (tvert[1] == NULL) { /* grow mesh on left */ tvert[1] = find_chull_vert(edge->rbfv[1], edge->rbfv[0]); if (tvert[1] != NULL) { if (tvert[1]->ord > edge->rbfv[0]->ord) ej0 = create_migration(edge->rbfv[0], tvert[1]); else ej0 = create_migration(tvert[1], edge->rbfv[0]); if (tvert[1]->ord > edge->rbfv[1]->ord) ej1 = create_migration(edge->rbfv[1], tvert[1]); else ej1 = create_migration(tvert[1], edge->rbfv[1]); mesh_from_edge(ej0); mesh_from_edge(ej1); } } }
/* Add normal direction if missing */ static void check_normal_incidence(void) { static FVECT norm_vec = {.0, .0, 1.}; const int saved_nprocs = nprocs; RBFNODE *near_rbf, *mir_rbf, *rbf; double bestd; int n; if (dsf_list == NULL) return; /* XXX should be error? */ near_rbf = dsf_list; bestd = input_orient*near_rbf->invec[2]; if (single_plane_incident) { /* ordered plane incidence? */ if (bestd >= 1.-2.*FTINY) return; /* already have normal */ } else { switch (inp_coverage) { case INP_QUAD1: case INP_QUAD2: case INP_QUAD3: case INP_QUAD4: break; /* quadrilateral symmetry? */ default: return; /* else we can interpolate */ } for (rbf = dsf_list; rbf != NULL; rbf = rbf->next) { const double d = input_orient*rbf->invec[2]; if (d >= 1.-2.*FTINY) return; /* seems we have normal */ if (d > bestd) { near_rbf = rbf; bestd = d; } } } if (mig_list != NULL) { /* need to be called first */ fprintf(stderr, "%s: Late call to check_normal_incidence()\n", progname); exit(1); } #ifdef DEBUG fprintf(stderr, "Interpolating normal incidence by mirroring (%.1f,%.1f)\n", get_theta180(near_rbf->invec), get_phi360(near_rbf->invec)); #endif /* mirror nearest incidence */ n = sizeof(RBFNODE) + sizeof(RBFVAL)*(near_rbf->nrbf-1); mir_rbf = (RBFNODE *)malloc(n); if (mir_rbf == NULL) goto memerr; memcpy(mir_rbf, near_rbf, n); mir_rbf->ord = near_rbf->ord - 1; /* not used, I think */ mir_rbf->next = NULL; mir_rbf->ejl = NULL; rev_rbf_symmetry(mir_rbf, MIRROR_X|MIRROR_Y); nprocs = 1; /* compute migration matrix */ if (create_migration(mir_rbf, near_rbf) == NULL) exit(1); /* XXX should never happen! */ norm_vec[2] = input_orient; /* interpolate normal dist. */ rbf = e_advect_rbf(mig_list, norm_vec, 0); nprocs = saved_nprocs; /* final clean-up */ free(mir_rbf); free(mig_list); mig_list = near_rbf->ejl = NULL; insert_dsf(rbf); /* insert interpolated normal */ return; memerr: fprintf(stderr, "%s: Out of memory in check_normal_incidence()\n", progname); exit(1); }