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; }
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; }
void b3GpuRaycast::castRaysHost(const b3AlignedObjectArray<b3RayInfo>& rays, b3AlignedObjectArray<b3RayHit>& hitResults, int numBodies,const struct b3RigidBodyCL* bodies, int numCollidables,const struct b3Collidable* collidables, const struct b3GpuNarrowPhaseInternalData* narrowphaseData) { // return castRays(rays,hitResults,numBodies,bodies,numCollidables,collidables); B3_PROFILE("castRaysHost"); for (int r=0;r<rays.size();r++) { b3Vector3 rayFrom = rays[r].m_from; b3Vector3 rayTo = rays[r].m_to; float hitFraction = hitResults[r].m_hitFraction; int hitBodyIndex= -1; b3Vector3 hitNormal; for (int b=0;b<numBodies;b++) { const b3Vector3& pos = bodies[b].m_pos; const b3Quaternion& orn = bodies[b].m_quat; switch (collidables[bodies[b].m_collidableIdx].m_shapeType) { case SHAPE_SPHERE: { b3Scalar radius = collidables[bodies[b].m_collidableIdx].m_radius; if (sphere_intersect(pos, radius, rayFrom, rayTo,hitFraction)) { hitBodyIndex = b; b3Vector3 hitPoint; hitPoint.setInterpolate3(rays[r].m_from, rays[r].m_to,hitFraction); hitNormal = (hitPoint-bodies[b].m_pos).normalize(); } } case SHAPE_CONVEX_HULL: { b3Transform convexWorldTransform; convexWorldTransform.setIdentity(); convexWorldTransform.setOrigin(bodies[b].m_pos); convexWorldTransform.setRotation(bodies[b].m_quat); b3Transform convexWorld2Local = convexWorldTransform.inverse(); b3Vector3 rayFromLocal = convexWorld2Local(rayFrom); b3Vector3 rayToLocal = convexWorld2Local(rayTo); int shapeIndex = collidables[bodies[b].m_collidableIdx].m_shapeIndex; const b3ConvexPolyhedronCL& poly = narrowphaseData->m_convexPolyhedra[shapeIndex]; if (rayConvex(rayFromLocal, rayToLocal,poly,narrowphaseData->m_convexFaces, hitFraction, hitNormal)) { hitBodyIndex = b; } break; } default: { static bool once=true; if (once) { once=false; b3Warning("Raytest: unsupported shape type\n"); } } } } if (hitBodyIndex>=0) { hitResults[r].m_hitFraction = hitFraction; hitResults[r].m_hitPoint.setInterpolate3(rays[r].m_from, rays[r].m_to,hitFraction); hitResults[r].m_hitNormal = hitNormal; hitResults[r].m_hitBody = hitBodyIndex; } } }