bool Face::triangle_intersect(const Ray &r, Hit &h, Vertex *a, Vertex *b, Vertex *c, bool intersect_backfacing) const { // compute the intersection with the plane of the triangle Hit h2 = Hit(h); if (!plane_intersect(r,h2,intersect_backfacing)) return 0; // figure out the barycentric coordinates: glm::vec3 Ro = r.getOrigin(); glm::vec3 Rd = r.getDirection(); // [ ax-bx ax-cx Rdx ][ beta ] [ ax-Rox ] // [ ay-by ay-cy Rdy ][ gamma ] = [ ay-Roy ] // [ az-bz az-cz Rdz ][ t ] [ az-Roz ] // solve for beta, gamma, & t using Cramer's rule glm::mat3 detA_mat(a->get().x-b->get().x,a->get().x-c->get().x,Rd.x, a->get().y-b->get().y,a->get().y-c->get().y,Rd.y, a->get().z-b->get().z,a->get().z-c->get().z,Rd.z); float detA = glm::determinant(detA_mat); if (fabs(detA) <= 0.000001) return 0; assert (fabs(detA) >= 0.000001); glm::mat3 beta_mat(a->get().x-Ro.x,a->get().x-c->get().x,Rd.x, a->get().y-Ro.y,a->get().y-c->get().y,Rd.y, a->get().z-Ro.z,a->get().z-c->get().z,Rd.z); glm::mat3 gamma_mat(a->get().x-b->get().x,a->get().x-Ro.x,Rd.x, a->get().y-b->get().y,a->get().y-Ro.y,Rd.y, a->get().z-b->get().z,a->get().z-Ro.z,Rd.z); float beta = glm::determinant(beta_mat) / detA; float gamma = glm::determinant(gamma_mat) / detA; if (beta >= -0.00001 && beta <= 1.00001 && gamma >= -0.00001 && gamma <= 1.00001 && beta + gamma <= 1.00001) { h = h2; // interpolate the texture coordinates float alpha = 1 - beta - gamma; float t_s = alpha * a->get_s() + beta * b->get_s() + gamma * c->get_s(); float t_t = alpha * a->get_t() + beta * b->get_t() + gamma * c->get_t(); h.setTextureCoords(t_s,t_t); assert (h.getT() >= EPSILON); return 1; } return 0; }
GimpRGB get_ray_color_plane (GimpVector3 *pos) { GimpRGB color = background; static gint inside = FALSE; static GimpVector3 ray, spos; static gdouble vx, vy; /* Construct a line from our VP to the point */ /* ========================================= */ gimp_vector3_sub (&ray, pos, &mapvals.viewpoint); gimp_vector3_normalize (&ray); /* Check for intersection. This is a quasi ray-tracer. */ /* =================================================== */ if (plane_intersect (&ray, &mapvals.viewpoint, &spos, &vx, &vy) == TRUE) { color = get_image_color (vx, vy, &inside); if (color.a != 0.0 && inside == TRUE && mapvals.lightsource.type != NO_LIGHT) { /* Compute shading at this point */ /* ============================= */ color = phong_shade (&spos, &mapvals.viewpoint, &mapvals.normal, &mapvals.lightsource.position, &color, &mapvals.lightsource.color, mapvals.lightsource.type); gimp_rgb_clamp (&color); } } if (mapvals.transparent_background == FALSE && color.a < 1.0) { gimp_rgb_composite (&color, &background, GIMP_RGB_COMPOSITE_BEHIND); } return color; }
bool Face::triangle_intersect(const Ray &r, Hit &h, Vertex *a, Vertex *b, Vertex *c, bool intersect_backfacing, bool* backfacing_hit) { *backfacing_hit = false; // compute the intersection with the plane of the triangle Hit h2 = Hit(h); if (!plane_intersect(r,h2,intersect_backfacing, backfacing_hit)) return 0; // figure out the barycentric coordinates: Vec3f Ro = r.getOrigin(); Vec3f Rd = r.getDirection(); // [ ax-bx ax-cx Rdx ][ beta ] [ ax-Rox ] // [ ay-by ay-cy Rdy ][ gamma ] = [ ay-Roy ] // [ az-bz az-cz Rdz ][ t ] [ az-Roz ] // solve for beta, gamma, & t using Cramer's rule double detA = Matrix::det3x3(a->get().x()-b->get().x(),a->get().x()-c->get().x(),Rd.x(), a->get().y()-b->get().y(),a->get().y()-c->get().y(),Rd.y(), a->get().z()-b->get().z(),a->get().z()-c->get().z(),Rd.z()); if (fabs(detA) <= 0.000001) return 0; assert (fabs(detA) >= 0.000001); double beta = Matrix::det3x3(a->get().x()-Ro.x(),a->get().x()-c->get().x(),Rd.x(), a->get().y()-Ro.y(),a->get().y()-c->get().y(),Rd.y(), a->get().z()-Ro.z(),a->get().z()-c->get().z(),Rd.z()) / detA; double gamma = Matrix::det3x3(a->get().x()-b->get().x(),a->get().x()-Ro.x(),Rd.x(), a->get().y()-b->get().y(),a->get().y()-Ro.y(),Rd.y(), a->get().z()-b->get().z(),a->get().z()-Ro.z(),Rd.z()) / detA; //Case of an intersection if (beta >= -0.00001 && beta <= 1.00001 && gamma >= -0.00001 && gamma <= 1.00001 && beta + gamma <= 1.00001) { h = h2; // interpolate the texture coordinates double alpha = 1 - beta - gamma; double t_s = alpha * a->get_s() + beta * b->get_s() + gamma * c->get_s(); double t_t = alpha * a->get_t() + beta * b->get_t() + gamma * c->get_t(); h.setTextureCoords(t_s,t_t); assert (h.getT() >= EPSILON); return 1; } return 0; }
bool triangle_intersect(vector_t a, vector_t b, vector_t c, vector_t normal, vector_t ray_start, vector_t ray_direction, vector_t* hit, float* u, float* v, float* w) { vector_t plane_hit; if (!plane_intersect((plane_t) {a, normal}, ray_start, ray_direction, &plane_hit)) return false; float tmp_u, tmp_v, tmp_w; barycentric(a, b, c, normal, plane_hit, &tmp_u, &tmp_v, &tmp_w); if (tmp_u < 0.0 || tmp_v < 0.0 || tmp_w < 0.0) return false; *hit = plane_hit; *u = tmp_u; *v = tmp_v; *w = tmp_w; return true; }
Color lambertian(Ray normal, const Scene* s, Sphere* sphere, Plane* plane) { Color result; result.r = 0; result.g = 0; result.b = 0; bool blocked; for(int i = 0; i < s->lights.size(); i++) { blocked = false; Light current_light = s->lights.at(i); Ray lightRay; lightRay.p0 = current_light.origin; lightRay.dir = sub(normal.p0, current_light.origin); lightRay.dir = normalize(lightRay.dir); // check that point of interest is not shadowed by other objects float distFromLight = dist(normal.p0, current_light.origin); float distClosestObject = fInfinity; // distance between light and closest object along ray to normal initial point for(int k = 0; k < s->planes.size(); k++) { Plane current_plane = s->planes.at(k); if(!areEqual(¤t_plane, plane)) { distClosestObject = plane_intersect(¤t_plane, &lightRay); // check if current object would block the light if(distClosestObject < distFromLight) { blocked = true; break; } } } for(int k = 0; k < s->spheres.size(); k++) { Sphere current_sphere = s->spheres.at(k); if(!areEqual(¤t_sphere, sphere)) { distClosestObject = sphere_intersect(¤t_sphere, &lightRay); // check if current object would block the light if(distClosestObject < distFromLight) { blocked = true; break; } } } // check that the light source isn't behind the object Vec3 lv = lightRay.dir; Vec3 nv = normalize(normal.dir); if(dot(lv, nv) > 0.0) blocked = true; if(!blocked) { // add this light's contribution to the pixel color float coef = abs(dot(lv, nv)); if(sphere != NULL) { result.r += (sphere->material.color.r * current_light.color.r) * coef; result.g += (sphere->material.color.g * current_light.color.g) * coef; result.b += (sphere->material.color.b * current_light.color.b) * coef; } else if(plane != NULL) { if(plane->hastexture) { Color textureColor = getTextureColor(getTexel(normal,plane),plane); result.r += textureColor.r * current_light.color.r * coef; result.g += textureColor.g * current_light.color.g * coef; result.b += textureColor.b * current_light.color.b * coef; } else { result.r += (plane->material.color.r * current_light.color.r) * coef; result.g += (plane->material.color.g * current_light.color.g) * coef; result.b += (plane->material.color.b * current_light.color.b) * coef; } } } } return result; }
Color traceRay(Ray pixel_ray, Scene* s, Camera* c, int depth) { Color pixelColor; Ray normal[2]; pixelColor.r = 0; pixelColor.g = 0; pixelColor.b = 0; Sphere *closestSphere = NULL; Plane *closestPlane = NULL; float closestSphereDist = fInfinity; float closestPlaneDist = fInfinity; if (depth <= 0) return {0,0,0}; for (int i = 0; i < s->spheres.size(); i++) { float dist = sphere_intersect(&s->spheres[i], &pixel_ray); if (dist != fInfinity) { if(closestSphereDist == fInfinity || (closestSphereDist > dist && abs(closestSphereDist-dist) > 0.0001)) { closestSphereDist = dist; closestSphere = &s->spheres[i]; Point intersection = add(pixel_ray.p0, mul(pixel_ray.dir, dist)); Ray sphereNorm; sphereNorm.p0 = intersection; sphereNorm.dir = normalize(sub(intersection, closestSphere->center)); normal[0] = sphereNorm; } } } for (int i = 0; i < s->planes.size(); i++) { float dist = plane_intersect(&s->planes[i], &pixel_ray); if (dist != fInfinity) { if(closestPlaneDist == fInfinity || (closestPlaneDist > dist && abs(closestPlaneDist-dist) > 0.0001)) { closestPlaneDist = dist; closestPlane = &s->planes[i]; Point intersection = add(pixel_ray.p0, mul(pixel_ray.dir, dist)); Ray planeNorm; planeNorm.p0 = intersection; planeNorm.dir = normalize(closestPlane->normal); normal[1] = planeNorm; } } } if (closestPlane != NULL && closestSphere != NULL) { if (closestPlaneDist < closestSphereDist) { closestSphere = NULL; } else closestPlane = NULL; } if (closestPlane != NULL) { Color lambert = lambertian(normal[1], s, NULL, closestPlane); pixelColor.r = lambert.r; pixelColor.g = lambert.g; pixelColor.b = lambert.b; if(depth != 0) { if(closestPlane->material.transparency != 0.0) { Ray transRay; transRay.dir = pixel_ray.dir; transRay.p0 = mul(normal[1].p0, 1.01f); Color transparent = traceRay(transRay, s, c, depth-1); pixelColor.r = pixelColor.r * (1 - closestPlane->material.transparency) + transparent.r * closestPlane->material.transparency; pixelColor.g = pixelColor.g * (1 - closestPlane->material.transparency) + transparent.g * closestPlane->material.transparency; pixelColor.b = pixelColor.b * (1 - closestPlane->material.transparency) + transparent.b * closestPlane->material.transparency; } if(closestPlane->material.reflection != 0.0) { Ray reflRay = reflect(pixel_ray, normal[1]); Color reflection = traceRay( reflRay, s, c, depth-1 ); pixelColor.r = pixelColor.r * (1 - closestPlane->material.reflection) + reflection.r * closestPlane->material.reflection; pixelColor.g = pixelColor.g * (1 - closestPlane->material.reflection) + reflection.g * closestPlane->material.reflection; pixelColor.b = pixelColor.b * (1 - closestPlane->material.reflection) + reflection.b * closestPlane->material.reflection; } } } else if (closestSphere != NULL) { Color lambert = lambertian(normal[0], s, closestSphere, NULL); pixelColor.r += lambert.r; pixelColor.g += lambert.g; pixelColor.b += lambert.b; if(depth != 0) { if(closestSphere->material.transparency != 0.0) { Ray transRay; transRay.dir = pixel_ray.dir; transRay.p0 = normal[0].p0; Color transparent = traceRay(transRay, s, c, depth-1); pixelColor.r = pixelColor.r * (1 - closestSphere->material.transparency) + transparent.r * closestSphere->material.transparency; pixelColor.g = pixelColor.g * (1 - closestSphere->material.transparency) + transparent.g * closestSphere->material.transparency; pixelColor.b = pixelColor.b * (1 - closestSphere->material.transparency) + transparent.b * closestSphere->material.transparency; } if(closestSphere->material.reflection != 0.0) { Ray reflRay; reflRay = reflect(pixel_ray, normal[0]); Color reflection = traceRay(reflRay, s, c, depth-1); pixelColor.r = pixelColor.r * (1 - closestSphere->material.reflection) + reflection.r * closestSphere->material.reflection; pixelColor.g = pixelColor.g * (1 - closestSphere->material.reflection) + reflection.g * closestSphere->material.reflection; pixelColor.b = pixelColor.b * (1 - closestSphere->material.reflection) + reflection.b * closestSphere->material.reflection; } } } if(pixelColor.r > 1) { //printf("cut off red\n"); pixelColor.r = 1.0; } if(pixelColor.g > 1) { //printf("cut off green\n"); pixelColor.g = 1.0; } if(pixelColor.b > 1) { //printf("cut off blue\n"); pixelColor.b = 1.0; } return pixelColor; }
// return 1 if this patch needs to be subdivided // ( triangles intersect the normal to the opposite direction) // return 0 if ok int EncQuadBezier::make_lam() { VEC nor, bend, hv0, hv1; // bend = bdir double lam, h; int i,j, m, sm,sp,s2, idx[4][2], sd, ii,jj, nsgn, nnsgn, cr,ncr; // booleans VEC env[2][4]; // env[1]=(upper)=outer int need_subdiv = 0; // return value for (i=0; i<d1; i++) for (j=0; j<d1; j++) lambda[i][j][0]= lambda[i][j][1]= 0; for (i=0; i<segu; i++) { for (j=0; j<segv; j++) { // normal at center determines which bilinear // to choose, eg +++ in all components means // ubd ubd ubd = outer // lbd lbd lbd = inner // determine diagonal: // curvature - + // + - VEC mid[2][2]; for(m=0;m<DIM;m++) { mid[0][0][m] =(get_enc(1,i,j)[m] + get_enc(0,i,j)[m])/2; mid[0][1][m] =(get_enc(1,i,j+1)[m] + get_enc(0,i,j+1)[m])/2; mid[1][0][m] =(get_enc(1,i+1,j)[m] + get_enc(0,i+1,j)[m])/2; mid[1][1][m] =(get_enc(1,i+1,j+1)[m] + get_enc(0,i+1,j+1)[m])/2; } for (m=0; m<DIM; m++) bend[m] = mid[0][0][m]+mid[1][1][m]-mid[0][1][m]-mid[1][0][m]; VVminus(mid[1][1],mid[0][0],hv0); VVminus(mid[0][1],mid[1][0],hv1); VVcross(hv0,hv1, nor); // if (crease >= 0) // triangles |/| or flat h = VVmult(sup_nor[i][j],nor); if (h < 0) printf("h %lf\n",h); h = VVmult(bend,nor); cr = (h >= 0); // convex up in normal direction == cr=1 cralong[i*(segv)+j] = cr; // record crease of bilinear // translation table // 3 2 // 0 1 idx[0][0] = i; idx[0][1] = j; idx[1][0] = i+1; idx[1][1] = j; idx[2][0] = i+1; idx[2][1] = j+1; idx[3][0] = i; idx[3][1] = j+1; // quadrant of the normal decides on choice of bilinear // depends on whether the normal is "outward" pointing // bd[1]...[x]: x component larger for (m=0; m<DIM; m++) { nsgn = (nor[m] >= 0); // if 1 then want bd[1] -- except when // normal is inward pointing (cube) nnsgn = (nsgn+1)%2; for (sd=0; sd<4; sd++) { // (nsgn=1) want upper bd in normal dir (env[1]..) ii = idx[sd][0]; jj = idx[sd][1]; env[1][sd][m] = get_enc(nsgn,ii,jj)[m]; env[0][sd][m] = get_enc(nnsgn,ii,jj)[m]; } } if(0) // draw the nor (put it in the center of the quad) { VEC center, sum; for(m=0;m<DIM;m++) { // center of all four up-enclosure corners center[m] = (env[1][0][m] + env[1][1][m] + env[1][2][m] + env[1][3][m])/4; } Normalize(nor); VVadd(1.0, center, 20, nor, sum); glDisable(GL_LIGHTING); glColor3f(0.3,0.0, 1.0); glBegin(GL_LINES); glVertex4dv(center); glVertex4dv(sum); glEnd(); glEnable(GL_LIGHTING); } // compute lambdas based on crease orientation // cr==1 for ridge 02 in normal direction // isect with 2 env[1] and 1 env[0] for (sd=0; sd<4; sd++) { // intersect with 3 total! ii = idx[sd][0]; jj = idx[sd][1]; sp = (sd+1)%4; s2 = (sd+2)%4; sm = (sd+3)%4; ncr = (cr+1)%2; // sm---s2 // | | // sd---sp lam = plane_intersect(sup_pt[ii][jj], sup_nor[ii][jj], env[cr][sd], env[cr][sp], env[cr][s2]); // Why (cr) selection? if cr then q=nor same dir as bend, as // supnor -- so compare with the two planes of the // triangles (cr) and then with the other (ncr) // if (cr) { if (lam > lambda[ii][jj][1]) lambda[ii][jj][1] = lam; } else { if (lam < lambda[ii][jj][0]) { lambda[ii][jj][0] = lam; } } if ((cr && (lam < -tol) ) || (ncr && (lam > tol))) { printf("not ok 1 cr %d lam %lf iijj %d %d \n",cr,lam,ii,jj); need_subdiv = 1; // need to be subdivied } if(debugchoice & EXTTRI) { set_color(ncr); if(!ncr) // only outter enclosure DrawTri(env[cr][sd], env[cr][sp], env[cr][s2]); } //else printf(" ok 1 \n"); lam = plane_intersect(sup_pt[ii][jj], sup_nor[ii][jj], env[cr][sd], env[cr][s2], env[cr][sm]); if (cr) { if (lam > lambda[ii][jj][1]) lambda[ii][jj][1] = lam; } else { if (lam < lambda[ii][jj][0]){ lambda[ii][jj][0] = lam; } } if ((cr && (lam < -tol) ) || (ncr && (lam > tol))) { printf("not ok 2 cr %d lam %lf iijj %d %d \n",cr,lam,ii,jj); need_subdiv = 1; // need to be subdivied } if(debugchoice & EXTTRI) { set_color(ncr); if(!ncr) // only outter enclosure DrawTri(env[cr][sd], env[cr][s2], env[cr][sm]); } //else printf(" ok 2 \n"); lam = plane_intersect(sup_pt[ii][jj], sup_nor[ii][jj], env[ncr][sd], env[ncr][sp], env[ncr][sm]); if (ncr) { if (lam > lambda[ii][jj][1]) lambda[ii][jj][1] = lam; } else { if (lam < lambda[ii][jj][0]) { lambda[ii][jj][0] = lam; } } if ((cr && (lam > tol) ) || (ncr && (lam < -tol))) { printf("not ok 3 cr %d lam %lf iijj %d %d \n",cr,lam,ii,jj); need_subdiv = 1; // need to be subdivied } if(debugchoice & EXTTRI) { set_color(cr); if(!cr) // only outter enclosure DrawTri(env[ncr][sd], env[ncr][sp], env[ncr][sm]); } //else printf(" ok 3 \n"); cr = ncr; // crease opposite at next point } // w...[1] has pos (in normal dir) values } } // subdivide the patch if needed return need_subdiv; }