const ColorRGB Scene3D::traceRay(const Ray& ray, int depth) const { float closest_t_value = NO_INTERSECT; const SceneObject* closest_object = findClosest(ray, closest_t_value); if (closest_object == 0) return ColorRGB(0,0,0); ColorRGB retColor(0,0,0); for (int i = 0; i < lights.size(); i++) { Vector3D normL = ((*lights[i]).get_position()-ray.getPointAt(closest_t_value)).normalize(); Vector3D normN = (*closest_object).surface_normal(ray.getPointAt(closest_t_value)); retColor += (*lights[i]).get_color()*(*closest_object).get_color()*std::max((normL*normN),float(0)); if (depth < 6 && (*closest_object).get_reflectivity() > 0) { Ray reflected_ray = ray.reflect(ray.getPointAt(closest_t_value), (*closest_object).surface_normal(ray.getPointAt(closest_t_value))); ColorRGB reflection_color = traceRay(reflected_ray, depth+1); retColor+= (*closest_object).get_reflectivity()*reflection_color; } } return retColor; }
void Controller::OnMouseMove(Flags nFlags, int x, int y) { Point point(x,y); if (nFlags == LBUTTON) { Vec3 r; r.x = -(Float)(point.x - mouse.x)/3; r.y = (Float)(point.y - mouse.y)/3; r = cross(r, Vec3(0,0,1)); Matrix rot = Matrix::Rotation( r.normalized(), r.getLen()); m_Rotation = m_Rotation * rot; } if (nFlags == (LBUTTON|RBUTTON) ) { Vec3 r; r.x = -(Float)(point.x - mouse.x)/3; r.y = (Float)(point.y - mouse.y)/3; r = cross(r, Vec3(0,0,1)); Matrix rot = Matrix::Rotation( r.normalized(), r.getLen()); m_Rotation2 = m_Rotation2 * rot; } if (nFlags == RBUTTON ) { Vec3 n = transform(Vec3(0,0,-1), m_Rotation.getInverted() ); n = n.normalized(); Plane ebene = Plane(n.x, n.y, n.z, 0); Ray a = getViewport().DPtoRay(mouse.x, mouse.y); Ray b = getViewport().DPtoRay(point.x, point.y); Float ta = 0, tb = 0; ebene.getIntersectionWithLine(a.getOrigin(), a.getPointAt(1), ta); ebene.getIntersectionWithLine(b.getOrigin(), b.getPointAt(1), tb); Vec3 d = a.getPointAt(ta) - b.getPointAt(tb); m_Translation = m_Translation + transform(d, m_Rotation ); } mouse = point; }
Color PointLight::calculateColor(const Scene &scene, const Ray &ray, float distance, const Vector &normal, MaterialPointer material) const { Vector point = ray.getPointAt(distance); Color ambientComponent; Color diffuseComponent; Color specularComponent; ambientComponent = componentwiseProduct(material->ambientColor, mAmbientIntensity); Color result = ambientComponent; Vector shadowRayDirection = mPosition - point; float distanceToLight = shadowRayDirection.length(); float attenuation = 1 / (mConstantAttenutaionCoefficient + mLinearAttenutaionCoefficient * distanceToLight + mQuadraticAttenutaionCoefficient * distanceToLight * distanceToLight); result *= attenuation; shadowRayDirection.normalize(); float shadowRayDotNormal = shadowRayDirection.dotProduct(normal); // If the point is not illuminated if (shadowRayDotNormal <= 0.0) { return result; } Ray shadowRay(point + shadowRayDirection * EPS_FOR_SHADOW_RAYS, shadowRayDirection); RayIntersection shadowRayIntersection = scene.calculateNearestIntersection(shadowRay); // If object is not in shadow if (!shadowRayIntersection.rayIntersectsWithShape || shadowRayIntersection.distanceFromRayOrigin > distanceToLight) { Color diffuseColor = material->diffuseColor; diffuseComponent = componentwiseProduct(diffuseColor, mDiffuseIntensity * attenuation * shadowRayDotNormal); Vector lightReflect = shadowRayDirection - normal * 2 * shadowRayDirection.dotProduct(normal); lightReflect.normalize(); Vector cameraDirection = ray.getOriginPosition() - point; cameraDirection.normalize(); float cosLightReflect = cameraDirection.dotProduct(lightReflect); if (cosLightReflect > 0.0) { Color specularColor = material->specularColor; specularComponent = componentwiseProduct(specularColor, mSpecularIntensity * powf(cosLightReflect, material->specularPower) * attenuation); } } result += (diffuseComponent + specularComponent); return result; }
Vector Cone::getNormal(const Ray &ray, float distance) const { Vector coneAxis = (mBottomCenter - mTop); coneAxis.normalize(); Vector point = ray.getPointAt(distance); // If point is lying at bottom Vector pointPositionRelativelyToBottom = point - mBottomCenter; if (fabs(coneAxis.dotProduct(pointPositionRelativelyToBottom)) < FLOAT_ZERO && pointPositionRelativelyToBottom.dotProduct(pointPositionRelativelyToBottom) < mRadius * mRadius) { return coneAxis; } // Otherwise, if point is lying at side surface Vector approximatedNormal = point - (coneAxis * (point - mBottomCenter).dotProduct(coneAxis) + mBottomCenter); float radiansPerHeight = mRadius / (mBottomCenter - mTop).length(); Vector normal = approximatedNormal + coneAxis * (-radiansPerHeight * approximatedNormal.length()); normal.normalize(); return normal; }
bool Sphere::intersectRay(const Ray &ray, Point &intersection) const { Vector3d centerToOrigin = ray.getOrigin() - center; // a = 0, т.к. нормируем вектор направления луча. double b = (Vector3d::dotProduct(ray.getDirection().normalize(), centerToOrigin)); double c = centerToOrigin.lengthSquared() - radiusSquared; double d = b * b - c; if (d >= 0) { double sqrtOfD = sqrt(d); double t1 = -b + sqrtOfD; double t2 = -b - sqrtOfD; double t_min = std::min(t1, t2); double t_max = std::max(t1, t2); double t_closest = (t_min >= 0) ? t_min : t_max; if (t_closest > 0) { intersection = ray.getPointAt(t_closest); return true; } else { return false; } } return false; }
Vector Sphere::getNormal(const Ray &ray, float distance) const { Vector normal = (ray.getPointAt(distance) - mCenter) / mRadius; normal.normalize(); return normal; }
RayIntersection Cone::intersectWithRay(const Ray &ray) const { Vector coneAxis = (mBottomCenter - mTop); coneAxis.normalize(); Vector rayOriginPosition = ray.getOriginPosition(); Vector rayDirection = ray.getDirection(); Vector bottomCenterToRayOrigin = rayOriginPosition - mTop; float rayDirectionDotAxis = rayDirection.dotProduct(coneAxis); float bottomCenterToRayOriginDotAxis = bottomCenterToRayOrigin.dotProduct(coneAxis); float radiansPerHeight = mRadius / (mBottomCenter - mTop).length(); Vector u = rayDirection + coneAxis * (-rayDirectionDotAxis); Vector v = bottomCenterToRayOrigin + coneAxis * (-bottomCenterToRayOriginDotAxis); float w = bottomCenterToRayOriginDotAxis * radiansPerHeight; float radiansPerDirection = rayDirectionDotAxis * radiansPerHeight; // Solve square equation a * x^2 + b * x + c = 0 float a = u.dotProduct(u) - radiansPerDirection * radiansPerDirection; float closestRoot = -1.f; float rayExit = -1.f; float root = 0.f; std::vector<float> intersectionDistances; if (fabs(a) > FLOAT_ZERO) { float b = 2 * (u.dotProduct(v) - w * radiansPerDirection); float c = v.dotProduct(v) - w * w; float discriminant = b * b - 4 * a * c; if (discriminant < 0.0) { return RayIntersection(); } discriminant = sqrtf(discriminant); float denominator = 1.0 / (2.0 * a); root = (-b - discriminant) * denominator; if (root > 0.0) { Vector point = ray.getPointAt(root); Vector bottomCenterToPoint = point - mTop; Vector topToPoint = point - mBottomCenter; if (coneAxis.dotProduct(bottomCenterToPoint) > 0.0 && (-coneAxis).dotProduct(topToPoint) > 0.0) { intersectionDistances.push_back(root); closestRoot = root; } } root = (-b + discriminant) * denominator; if (root > 0.0) { Vector point = ray.getPointAt(root); Vector bottomCenterToPoint = point - mTop; Vector topToPoint = point - mBottomCenter; if (coneAxis.dotProduct(bottomCenterToPoint) > 0.0 && (-coneAxis).dotProduct(topToPoint) > 0.0) { intersectionDistances.push_back(root); if (closestRoot < 0.0) { closestRoot = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } } } // Intersection with bottom if (fabs(rayDirectionDotAxis) < FLOAT_ZERO) { if (closestRoot > 0.0) { if (rayExit < 0.f) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } ConePointer pointer = ConePointer(new Cone(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); } // Intersection with top and bottom points root = (-coneAxis).dotProduct(rayOriginPosition - mBottomCenter) / rayDirectionDotAxis; if (root > 0.0) { Vector topToPoint = ray.getPointAt(root) - mBottomCenter; if (topToPoint.dotProduct(topToPoint) < mRadius * mRadius) { intersectionDistances.push_back(root); if (closestRoot < 0.0) { closestRoot = root; rayExit = root; } else if (root < closestRoot) { rayExit = closestRoot; closestRoot = root; } else { rayExit = root; } } } if (closestRoot > 0.0) { if (rayExit < 0.0) { intersectionDistances.insert(intersectionDistances.begin(), 0.f); } ConePointer pointer = ConePointer(new Cone(*this)); return RayIntersection(true, pointer, closestRoot, getNormal(ray, closestRoot), intersectionDistances); } return RayIntersection(); }
RGB SubsurfacePathtracer::trace(Ray p_ray, Vector3d cameraPos, int p_depth) { RGB radiance(0,0,0); RGB localRadiance(0,0,0); RayIntersection nearestRayInt; p_depth++; bool intersected = false; if(scene->kdTree == NULL) { intersected = p_ray.nearestIntersection(scene->getObjects(), scene->getObjectCount(), &nearestRayInt); } else { intersected = scene->kdTree->nearestIntersection(&p_ray, &nearestRayInt); } if(intersected) { if(!(nearestRayInt.object->getShader()->isLight() && p_ray.getDiffuse())) { //local ilumination: Vector3d viewVec = cameraPos - nearestRayInt.point; viewVec.normalize(); localRadiance = nearestRayInt.object->getShader()->getDiffuseRadiance(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, scene); radiance = localRadiance; if(nearestRayInt.object->getShader()->hasSubsurface()) { radiance = radiance + subsurface(&nearestRayInt, &p_ray); //return subsurface(&nearestRayInt, &p_ray); } int outVecsCount = 0; RGB indirectRadiance; if(p_depth == 1) { for(int i = 0; i < 5; i++) { if(p_depth < maxDepth) { Ray outRays[10]; RGB values[10]; outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values); for(int s = 0; s < outVecsCount; s++) { Ray ray = outRays[s]; indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ; } } indirectRadiance; } indirectRadiance = indirectRadiance / 5; } else { if(p_depth < maxDepth) { Ray outRays[10]; RGB values[10]; outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values); for(int s = 0; s < outVecsCount; s++) { Ray ray = outRays[s]; indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ; } } } if(outVecsCount > 0) { radiance = radiance + indirectRadiance; } } } else if(scene->getBackground() != NULL) { radiance = scene->getBackground()->getRadianceAt(p_ray.getPoint(), p_ray.getPointAt(FAR_AWAY)); } return radiance; }
Color RayTracer::traceRay(const Ray &ray, int currentRecursionDepth, bool isRayReflected, float environmentDensity, float reflectionIntensity, RayIntersection &intersection) { if (currentRecursionDepth > MAX_TRACER_RECURSION_DEPTH) { return Color(); } intersection = mScene->calculateNearestIntersection(ray); if (!intersection.rayIntersectsWithShape) { if (isRayReflected) { return Color(); } return mScene->getBackgroundMaterial()->ambientColor; } Vector intersectionPoint = ray.getPointAt(intersection.distanceFromRayOrigin); ShapePointer shape = intersection.shape; MaterialPointer shapeMaterial = shape->getMaterial(); Vector normal = intersection.normalAtInresectionPoint; Color pixelColor = mScene->calculateIlluminationColor(ray, intersection.distanceFromRayOrigin, normal, shapeMaterial); /* Process reflection and refraction */ Vector rayDirection = ray.getDirection(); float viewProjection = rayDirection.dotProduct(normal); // Turn normal to the front side Vector outNormal = normal; if (viewProjection > 0.0) { outNormal = -normal; } // Calculate fresnel factor bool isTotalInternalReflection = false; float fresnel = calculateFrenselCoefficient(rayDirection, environmentDensity, shapeMaterial->densityFactor, outNormal, isTotalInternalReflection); // Calculate reflection if (shapeMaterial->reflectionFactor > 0.0 && reflectionIntensity > EPS_FOR_REFLECTION_RAYS) { // Reflect ray Vector reflectedRayDirection = rayDirection - outNormal * 2.0 * rayDirection.dotProduct(outNormal); RayIntersection reflectedRayIntersection; Color reflectedColor = traceRay(Ray(intersectionPoint + reflectedRayDirection * EPS_FOR_REFLECTION_RAYS, reflectedRayDirection), currentRecursionDepth + 1, true, shapeMaterial->densityFactor, reflectionIntensity * shapeMaterial->reflectionFactor, reflectedRayIntersection); reflectedColor *= reflectionIntensity * shapeMaterial->reflectionFactor * fresnel; pixelColor += componentwiseProduct(reflectedColor, shapeMaterial->diffuseColor); } // Calculate refraction if (shapeMaterial->refractionFactor > 0.0) { float shapeDensity = shapeMaterial->densityFactor; Vector reflectedRayDirection = claculateRefractedRayDirection(rayDirection, outNormal, environmentDensity, shapeDensity, isTotalInternalReflection); if (!isTotalInternalReflection) { RayIntersection refractedRayIntersection; Color refracted = traceRay(Ray(intersectionPoint + reflectedRayDirection * EPS_FOR_REFLECTION_RAYS, reflectedRayDirection), currentRecursionDepth + 1, true, shapeDensity, reflectionIntensity, refractedRayIntersection); // Use Burger-Lambert-Beer law if (refractedRayIntersection.rayIntersectsWithShape) { Color absorbance = (shapeMaterial->diffuseColor) * 0.15f * (-refractedRayIntersection.distanceFromRayOrigin); Color transparency = Color(expf(absorbance.r), expf(absorbance.g), expf(absorbance.b)); pixelColor += componentwiseProduct(refracted, transparency) * (1.0 - fresnel); } } } return pixelColor; }