INT PolyPeIntersect(RAY *pr, ELEMENT *pe, IRECORD *hit) { INT i; INT *vindex; /* Vertex index pointer. */ INT toright; /* Counter. */ INT sh, nsh; /* Sign holders. */ REAL Rd_dot_Pn; /* Polygon normal dot ray direction. */ REAL Ro_dot_Pn; /* Polygon normal dot ray origin. */ REAL tval; /* Intersection t distance value. */ REAL x[MAX_VERTS + 1]; /* Projection list. */ REAL y[MAX_VERTS + 1]; /* Projection list. */ REAL ix, iy; /* Intersection projection point. */ REAL dx, dy; /* Deltas between 2 vertices. */ REAL xint; /* Intersection value. */ VEC3 I; /* Intersection point. */ VEC3 *vlist, *vpos; /* Vertex list pointer. */ POLY *pp; /* Ptr to polygon data. */ pp = (POLY *)pe->data; Rd_dot_Pn = VecDot(pp->norm, pr->D); if (ABS(Rd_dot_Pn) < RAYEPS) /* Ray is parallel. */ return (0); Ro_dot_Pn = VecDot(pp->norm, pr->P); tval = -(pp->d + Ro_dot_Pn)/Rd_dot_Pn; /* Intersection distance. */ if (tval < RAYEPS) /* Intersects behind ray. */ return (0); RayPoint(I, pr, tval); /* Polygon containment. */ /* Project onto plane with greatest normal component. */ vlist = pp->vptr; vindex = pp->vindex; switch (pp->axis_proj) { case X_AXIS: for (i = 0; i < pp->nverts; i++) { vpos = vlist + (*vindex); x[i] = (*vpos)[1]; y[i] = (*vpos)[2]; vindex++; } ix = I[1]; iy = I[2]; break; case Y_AXIS: for (i = 0; i < pp->nverts; i++) { vpos = vlist + (*vindex); x[i] = (*vpos)[0]; y[i] = (*vpos)[2]; vindex++; } ix = I[0]; iy = I[2]; break; case Z_AXIS: for (i = 0; i < pp->nverts; i++) { vpos = vlist + (*vindex); x[i] = (*vpos)[0]; y[i] = (*vpos)[1]; vindex++; } ix = I[0]; iy = I[1]; break; } /* Translate to origin. */ for (i = 0; i < pp->nverts; i++) { x[i] -= ix; y[i] -= iy; if (ABS(y[i]) < RAYEPS) y[i] = 0.0; } x[pp->nverts] = x[0]; y[pp->nverts] = y[0]; /* * If intersection point crosses an odd number of line segments, * the point is inside the polygon */ if (y[0] < 0.0) sh = 0; else sh = 1; toright = 0; for (i = 0; i < pp->nverts; i++) { /* Check if segment crosses in y. */ if (y[i + 1] < 0.0) nsh = 0; else nsh = 1; if (nsh ^ sh) { dy = y[i + 1] - y[i]; if (ABS(dy) >= RAYEPS) { dx = x[i + 1] - x[i]; xint = x[i] - y[i]*dx / dy; if (xint > 0.0) toright++; } } sh = nsh; } if (toright%2 == 1) { IsectAdd(hit, tval, pe); return (1); } else return (0); }
VOID RayTrace(INT pid) { INT j; INT x, y; /* Pixel address. */ REAL xx, yy; VEC3 N; /* Normal at intersection. */ VEC3 Ipoint; /* Intersection point. */ COLOR c; /* Color for storing background. */ RAY *ray; /* Ray pointer. */ RAY rmsg; /* Ray message. */ RAYJOB job; /* Ray job from work pool. */ OBJECT *po; /* Ptr to object. */ BOOL hit; /* An object hit? */ IRECORD hitrecord; /* Intersection record. */ ray = &rmsg; while (GetJobs(&job, pid) != WPS_EMPTY) { while (GetRayJobFromBundle(&job, &x, &y)) { /* Convert the ray job to the ray message format. */ xx = (REAL)x; yy = (REAL)y; if (AntiAlias) for (j = 0; j < NumSubRays; j++) { ConvertPrimRayJobToRayMsg(ray, xx + frand(), yy + frand()); PushRayTreeStack(ray, pid); } else { ConvertPrimRayJobToRayMsg(ray, xx, yy); PushRayTreeStack(ray, pid); } while (PopRayTreeStack(ray, pid) != RTS_EMPTY) { /* Find which object is closest along the ray. */ switch (TraversalType) { case TT_LIST: hit = Intersect(ray, &hitrecord); break; case TT_HUG: hit = TraverseHierarchyUniform(ray, &hitrecord, pid); break; } /* Process the object ray hit. */ if (hit) { /* * Get parent object to be able to access * object operations. */ po = hitrecord.pelem->parent; /* Calculate intersection point. */ RayPoint(Ipoint, ray, hitrecord.t); /* Calculate normal at this point. */ ((void (*)(IRECORD *, VEC3, VEC3))(*po->procs->normal))(&hitrecord, Ipoint, N); /* Make sure normal is pointing toward ray origin. */ if ((VecDot(ray->D, N)) > 0.0) VecNegate(N, N); /* * Compute shade at this point - will process * shadow rays and add secondary reflection * and refraction rays to ray tree stack */ Shade(Ipoint, N, ray, &hitrecord, pid); } else { /* Add background as pixel contribution. */ VecCopy(c, View.bkg); VecScale(c, ray->weight, c); AddPixelColor(c, ray->x, ray->y); } } } } }