/* refine.c: hierarchical element refinement */ #include "mcradP.h" #include "hierarchy.h" #include "statistics.h" #include "error.h" /* refinement action 1: do nothing (link is accurate enough) */ LINK *DontRefine(LINK *link, ELEMENT *rcvtop, double *ur, double *vr, ELEMENT *srctop, double *us, double *vs) { /* doesn't do anything */ return link; } /* refinement action 2: subdivide the receiver using regular quadtree subdivision */ static LINK *SubdivideReceiver(LINK *link, ELEMENT *rcvtop, double *ur, double *vr, ELEMENT *srctop, double *us, double *vs) { ELEMENT *rcv = link->rcv; if (rcv->iscluster) { rcv = ClusterChildContainingElement(rcv, rcvtop); } else { if (!rcv->regular_subelements) McrRegularSubdivideElement(rcv); rcv = McrRegularSubelementAtPoint(rcv, ur, vr); } link->rcv = rcv; return link; } /* refinement action 3: subdivide the source using regular quadtree subdivision */ static LINK *SubdivideSource(LINK *link, ELEMENT *rcvtop, double *ur, double *vr, ELEMENT *srctop, double *us, double *vs) { ELEMENT *src = link->src; if (src->iscluster) { src = ClusterChildContainingElement(src, srctop); } else { if (!src->regular_subelements) McrRegularSubdivideElement(src); src = McrRegularSubelementAtPoint(src, us, vs); } link->src = src; return link; } static int SelfLink(LINK *link) { return (link->rcv == link->src); } static int LinkInvolvingClusters(LINK *link) { return (link->rcv->iscluster || link->src->iscluster); } static int DisjunctElements(ELEMENT *rcv, ELEMENT *src) { BOUNDINGBOX rcvbounds, srcbounds; ElementBounds(rcv, rcvbounds); ElementBounds(src, srcbounds); return DisjunctBounds(rcvbounds, srcbounds); } /* Cheap form factor estimate to drive hierarchical refinement * as in Hanrahan SIGGRAPH'91. */ static float formfactor_estimate(ELEMENT *rcv, ELEMENT *src) { VECTOR D; double d, c1, c2, f, f2; VECTORSUBTRACT(src->midpoint, rcv->midpoint, D); d = VECTORNORM(D); f = src->area / (M_PI * d * d + src->area); f2 = 2.*f; c1 = rcv->iscluster ? 1. /*0.25*/ : fabs(VECTORDOTPRODUCT(D, rcv->pog.patch->normal)) / d; if (c1 < f2) c1 = f2; c2 = src->iscluster ? 1. /*0.25*/ : fabs(VECTORDOTPRODUCT(D, src->pog.patch->normal)) / d; if (c2 < f2) c2 = f2; return f * c1 * c2; } static int LowPowerLink(LINK *link) { ELEMENT *rcv = link->rcv; ELEMENT *src = link->src; COLOR rhosrcrad; float ff = formfactor_estimate(rcv, src); float threshold, propagated_power; /* compute receiver reflectance times source radiosity */ COLORSCALE(M_PI, src->rad[0], rhosrcrad); if (!rcv->iscluster) { COLOR Rd = REFLECTANCE(rcv->pog.patch); COLORPROD(Rd, rhosrcrad, rhosrcrad); } threshold = hierarchy.epsilon * COLORMAXCOMPONENT(max_selfemitted_power); propagated_power = rcv->area * ff * COLORMAXCOMPONENT(rhosrcrad); #ifdef IDMCR if (mcr.importance_driven) { propagated_power *= rcv->imp; if (!rcv->iscluster) propagated_power *= ElementScalarReflectance(rcv); } #endif return (propagated_power < threshold); } static REFINE_ACTION SubdivideLargest(LINK *link) { ELEMENT *rcv = link->rcv; ELEMENT *src = link->src; if (rcv->area < hierarchy.minarea && src->area < hierarchy.minarea) return DontRefine; else return (rcv->area > src->area) ? SubdivideReceiver : SubdivideSource; } REFINE_ACTION PowerOracle(LINK *link) { if (SelfLink(link)) return SubdivideReceiver; else if (LinkInvolvingClusters(link) && !DisjunctElements(link->rcv, link->src)) return SubdivideLargest(link); else if (LowPowerLink(link)) return DontRefine; else return SubdivideLargest(link); } LINK TopLink(ELEMENT *rcvtop, ELEMENT *srctop) { ELEMENT *rcv, *src; LINK link; if (hierarchy.do_h_meshing && hierarchy.clustering != NO_CLUSTERING) { src = rcv = hierarchy.topcluster; } else { src = srctop; rcv = rcvtop; } link.rcv = rcv; link.src = src; return link; } /* (ur,vr) are the coordinates of the point on the receiver patch, * (us,vs) coordinates of the point on the source patch. */ LINK *Refine(LINK *link, ELEMENT *rcvtop, double *ur, double *vr, ELEMENT *srctop, double *us, double *vs, ORACLE evaluate_link) { if (!hierarchy.do_h_meshing) { link->rcv = rcvtop; link->src = srctop; } else { REFINE_ACTION action; while ((action = evaluate_link(link)) != DontRefine) link = action(link, rcvtop, ur, vr, srctop, us, vs); } return link; }