bool Plane::intersect(const Ray& ray, IntersectionData& intersectionData) { if ((ray.Start().Y() > this->Y() && ray.Direction().Y() > VerySmall) || (ray.Start().Y() < this->Y() && ray.Direction().Y() < VerySmall)) { return false; } double yRayDirection = ray.Direction().Y(); double yDifference = ray.Start().Y() - this->Y(); double multiplier = yDifference / -yRayDirection; if (multiplier > intersectionData.getDistance()) { return false; } Vector intersectionPoint = ray.Start() + ray.Direction() * multiplier; if (fabs(intersectionPoint.X()) > this->Limit() || fabs(intersectionPoint.Z()) > this->Limit()) { return false; } intersectionData.setIntersectionPoint(intersectionPoint); intersectionData.setDistance(multiplier); intersectionData.setNormal(Vector(0.0, 1.0, 0.0)); intersectionData.setTextureU(intersectionData.IntersectionPoint().X()); intersectionData.setTextureV(intersectionData.IntersectionPoint().Z()); return true; }
//------------------------------------------------------------------------------ bool Plane::Intersect( const Ray& _ray, Intersection& o_intersection) const { float rayParameter = ( m_distance - m_normal.Dot( _ray.Origin() ) ) / m_normal.Dot( _ray.Direction() ); if (rayParameter < 0.0f) return false; Vector position = _ray.Origin() + _ray.Direction() * rayParameter; o_intersection = Intersection( position, m_normal,Vector2D(0,0), rayParameter, m_pMaterial ); return true; }
bool DielectricMaterial::Scatter( const Ray& ray, const HitRecord& record, Vector3& attenuation, Ray& scattered ) const { attenuation = Vector3( 1.f, 1.f, 1.f ); const float dirDotNormal = ray.Direction().Dot( record.normal ); Vector3 outwardNormal; float niOverNt; float cosine; if ( dirDotNormal > 0.f ) { outwardNormal = -record.normal; niOverNt = refractionIndex; //cosine = refractionIndex * dirDotNormal / ray.Direction().Length(); cosine = dirDotNormal / ray.Direction().Length(); cosine = std::sqrt( 1.f - refractionIndex * refractionIndex * ( 1.f - cosine * cosine ) ); } else { outwardNormal = record.normal; niOverNt = 1.f / refractionIndex; cosine = -dirDotNormal / ray.Direction().Length(); } const Vector3 reflected = Reflect( ray.Direction(), record.normal ); float reflectProbability; Vector3 refracted; if ( Refract( ray.Direction(), outwardNormal, niOverNt, refracted ) ) { reflectProbability = Schlick( cosine, refractionIndex ); } else { reflectProbability = 1.f; } if ( Rand01() < reflectProbability ) { scattered = Ray( record.point, reflected ); } else { scattered = Ray( record.point, refracted ); } return true; }
Color RayTracer::Render(const Ray& rRay, bool vIsReflecting, const Shape* pReflectingFrom ) { mRecursions++; Shape* closest_shape; Point intersect_point; Color result; if (vIsReflecting) closest_shape = QueryScene(rRay, intersect_point, vIsReflecting, pReflectingFrom); else closest_shape = QueryScene(rRay, intersect_point); if (closest_shape == NULL && !vIsReflecting) { mRecursions = 0; return mBackgroundColor; } if (closest_shape == NULL && vIsReflecting) { mRecursions = 0; return mAmbientColor*mAmbientIntensity; } if ( mRecursions > mRecursionLimit ) { mRecursions = 0; return Color(0,0,0); // mAmbientColor*mAmbientIntensity; } result = closest_shape->ShapeColor()*Shade(closest_shape, intersect_point); Ray backwards_ray(intersect_point,rRay.Direction()*-1); if ( closest_shape->DiffuseReflectivity() > 0.0 ) result = result + (Render( closest_shape->Reflect(intersect_point,backwards_ray), true, closest_shape )*closest_shape->DiffuseReflectivity()); return (result + mSpecularColor); }
Color FresnelTexture::getTextureColor(const Ray& ray, double u, double v, Vector& normal) const { Vector faceForwardNormal = Vector::faceForward(ray.Direction(), normal); double indexOfRefraction = this->indexOfRefraction; // If the ray is entering the geometry we must use the reciprocal of the index of refraction if (Vector::dotProduct(ray.Direction(), normal) > 0.0) { indexOfRefraction = 1.0 / indexOfRefraction; } double fresnelCoefficient = this->fresnel(ray.Direction(), faceForwardNormal, indexOfRefraction); Color resultColor(fresnelCoefficient, fresnelCoefficient, fresnelCoefficient); return resultColor; }
Ray Shape::Reflect(const Point& rReflectFrom, const Ray& rIncidentRay) const { Ray result; // the reflected ray Vector result_direction; // the reflected direction vector Vector incident_unit = rIncidentRay.Direction().Normalize(); Vector normal = this->Normal(rReflectFrom, rIncidentRay.Origin() ); if ( !normal.IsSameDirection(incident_unit) ) normal.ReverseDirection(); // we want the normal in the same direction of the incident ray. result.Origin(rReflectFrom); result.Direction( normal*2.0*normal.Dot(incident_unit) - incident_unit ); /* if ( normal.Dot(rIncidentRay.Direction().Normalize()) < 0.0 ) normal.ReverseDirection(); result.Origin(rReflectFrom); result.Direction((normal*2.0) - rIncidentRay.Direction().Normalize()); */ return result; }
double RayTracer::Specular(const Shape* pShapeToShade, const Point& rPointOnShapeToShade, const Light* pLight) { Ray reflected = pShapeToShade->Reflect(rPointOnShapeToShade,Ray(rPointOnShapeToShade, pLight->LightPoint())); Vector eye_vector(rPointOnShapeToShade, mEyePoint); Vector reflected_vector = reflected.Direction().Normalize(); eye_vector.NormalizeThis(); double dot_product = eye_vector.Dot(reflected_vector); int n = pShapeToShade->SpecularSize(); double specular_intensity = dot_product/(n - n*dot_product+ dot_product); return unit_limiter(specular_intensity*pLight->Intensity()); }
//------------------------------------------------------------------------------ bool Sphere::Intersect( const Ray& _ray, Intersection& o_intersection ) const { Vector p = Position() - _ray.Origin(); float pDotRayDir = p.Dot( _ray.Direction() ); // ray pointing away from sphere if(( pDotRayDir )<0 ) return false; /* pDotRayDir distance between origin and P's projection on Ray p.Dot( p ) magnitude sqaured of p O, O, |\ |\ | \ | \ R. \ p R. \ p | \ ,-- | \ ,-- | '\ | '\ | ' \ | ' \ |'_____. |___'______ . Q ' r P Q ' r P ' figure 1 ) figure 2 ) 1 ) rSquared + RSquared = PSquared 2 ) rSquared + RSquared < PSquared */ float temp = m_radiusSquared + pDotRayDir * pDotRayDir - p.Dot( p ); // no intersection if ( temp < 0.0f ) { return false; } //rayParameter = pDotRayDir - sqrtf( temp ); float rayParameter; // if ray origin is inside sphere if ( ( pDotRayDir - sqrtf( temp ) ) < 0.0f ) { rayParameter = pDotRayDir + sqrtf( temp ); Vector intersectionPos= _ray.GetPosition( rayParameter ); Vector normal = ( intersectionPos - Position() ).Normalise(); o_intersection = Intersection( intersectionPos, normal, Vector2D(0,0), rayParameter, g_air ); //intersection inside sphere; return true; } rayParameter = pDotRayDir - sqrtf( temp ); Vector intersectionPos = _ray.GetPosition( rayParameter ); Vector normal = ( intersectionPos - Position() ).Normalise(); o_intersection = Intersection( intersectionPos, normal, Vector2D(0,0), rayParameter, m_pMaterial ); return true; }
// Light's Functions void AreaLight::AccumulateIlluminationAtSurface( const Ray &ray, const Vector<float> &surfaceNormal, const float &surfaceRoughness, const Scene &scene, Color &diffuse, Color &specular ) const { if( _positions.empty() ) return; Color areaLightDiffuse( 0 ); Color areaLightSpecular( 0 ); // Accumulate the illumination from all the positions for(VectorList::const_iterator itr = _positions.begin(); itr != _positions.end(); ++itr ) { const Vector<float> &lightPosition = (*itr); Vector<float> lightRayDirection = lightPosition - ray.Origin(); const float lightRayLength = lightRayDirection.Normalize(); // If the light is out of range of the surface if( lightRayLength > _range ) continue; // The illumination from this light const Ray lightRay( ray.Origin(), lightRayDirection, ray ); const Color illuminationFromLight = Illumination( lightRay, lightRayLength, scene ); if( illuminationFromLight.Magnitude2() < Maths::Tolerance ) continue; // Calculate the illumination at the point on the surface const Color illumination = illuminationFromLight * ( 1 - lightRayLength * _oneOverRange ); // Accumulate the diffuse areaLightDiffuse += illumination * Maths::Max<float>(0, surfaceNormal.Dot( lightRayDirection )); // Accumulate the specular areaLightSpecular += illuminationFromLight * powf( Maths::Max<float>(0, ray.Direction().Dot( lightRayDirection.Reflect( surfaceNormal ) ) ), surfaceRoughness ); } diffuse += areaLightDiffuse * (1.0f / _positions.size()); specular += areaLightSpecular * (1.0f / _positions.size()); }
bool Plane::Intersect(const Ray& ray, Intersection& intersection, void* additional_data) const { float dir_norm = ray.Direction().DotProduct(m_Orientation); if (abs(dir_norm) < std::numeric_limits<float>::epsilon()) return false; float t = (m_Center - ray.Origin()).DotProduct(m_Orientation) / dir_norm; Range<float> range = ray.EffectRange(); if (Math::Contain(t, range)) { intersection.SetDistance(t); intersection.SetIntersectObject((IIntersectTarget*)this); intersection.SetTestObject(&ray); return true; } return false; }
//------------------------------------------------------------------------ Ray operator * ( const Matrix& _transform, const Ray& _ray ) { return Ray( _transform * _ray.Origin(), _transform * _ray.Direction(), _ray.GetMaterial() ); }
bool Kdtree::intersect(Ray &r, HitInfo* pHitInfo ) { pHitInfo->bHasInfo = false; pHitInfo->hitTime = INFINITY; Point3 invDir(1.f/r.Direction().X(), 1.f/r.Direction().Y(), 1.f/r.Direction().Z()); float tmin = 0; float tmax = 0; // intersect bounding box if(!m_Bounds.Intersect(r, tmin, tmax)) { return false; } bool done = false; list<TODO> todo; BSPNode *current = &m_pTree[0]; while(!done) { if(pHitInfo->hitTime < tmin) { break; } if(!current->isLeaf()) { int axis = current->splitAxis(); float split = current->SplitPos(); split = (split > -EPSILON && split < EPSILON) ? 0 : split; float tplane = (split - r.Origin()[axis]) * invDir[axis]; BSPNode *first, *second; // decide which child to check first int below = r.Origin()[axis] <= split; if(below) { first = &m_pTree[current->leftChild]; second = &m_pTree[current->leftChild+1]; } else { second = &m_pTree[current->leftChild]; first = &m_pTree[current->leftChild+1]; } if(tplane == 0)//(tplane > -EPS && tplane < EPS) { if(invDir[axis] > 0) current = second; else current = first; } else if(tplane >= tmax || tplane < 0) current = first; else if(tplane <= tmin) current = second; else { TODO temp; temp.node = second; temp.tmax = tmax; temp.tmin = tplane; todo.push_front(temp); current = first; tmax = tplane; } } else { // check all intersect in this leaf std::list<IPrimitive*>::const_iterator it; if(current->m_pPrimList) { for(int i = 0; i < current->nTriangle(); i++) { HitInfo thisHit; current->m_pPrimList[i]->intersect( r, &thisHit); if( thisHit.hitTime < pHitInfo->hitTime ) { *pHitInfo = thisHit; } } // end checking all Primitives in this leaf } if(!todo.empty()) { TODO temp = (*todo.begin()); current = temp.node; tmin = temp.tmin; tmax = temp.tmax; todo.pop_front(); } else { done = true; } } // end check leaf } // end while loop return pHitInfo->bHasInfo; }
Vector3D RecursiveTraceStrategy::operator ()(const Ray &tracer, const int depth, const double refrIndex) const { double usableEpsilion = std::numeric_limits<float>::epsilon(); // Epsilon for a float will always produce a usable delta for doubles (this is a little bit of a bad idea) //begin traversing the world // double closestDist = std::numeric_limits<double>::infinity(); std::shared_ptr<Shape> closest; for(std::shared_ptr<Shape> s : _Shapes) { //find the distance from the origin to the point of intersection // double dist = s->Intersect(tracer); if(dist > 0) { if(dist > closestDist) continue; closestDist = dist; closest = s; } } if(closest == nullptr) return {0.0, 0.0, 0.0}; Vector3D compositeColor = {0.0, 0.0, 0.0}; //calculate the position vector of the point of intersection using the line along the current ray // Vector3D intersectPoint = tracer.Origin() + (tracer.Direction() * closestDist); //get the unit normal at the point of intersection to apply shading Vector3D unitNormal = closest->Normal(intersectPoint); // Get the material of the shape std::shared_ptr<const Material> shapeMat = closest->SurfaceMaterial(); //traverse the world again looking for lights // for(std::shared_ptr<Light> l : _Lights) { //retrieve the position vector of the light source (treated as a uniform pointline source) Vector3D lightCenter = l->Position(); //create a vector from the intersect point to the light source Vector3D toLight = (lightCenter - intersectPoint).Normalize(); //calculate occlusion (for a pointlike source this is boolean) // Note that I'm adding a small offset in the direction we want to go so that we don't // intersect with the current shape Ray occlRay(intersectPoint + (usableEpsilion * toLight), toLight); double visibility = 1.0; // occlusion = 1 - visibility for(std::shared_ptr<Shape> o : _Shapes) { double d = o->Intersect(occlRay); if(d > 0) { visibility = 0.0; break; } } if(visibility > 0) { //apply lighting function // double radianceDist = shapeMat->Brdf(tracer.Direction(), toLight, unitNormal); std::shared_ptr<const Material> lightMat = l->LightMaterial(); compositeColor += shapeMat->Color().Weight(lightMat->Color() * radianceDist * visibility); } } //apply reflections // double refl = shapeMat->Reflectance(); double refr = shapeMat->Refractance(); double rindex = shapeMat->IndexOfRefraction(); if(refl > 0.0 && depth < _MaxTraceIterations) { Vector3D reflectionDir; reflectionDir = tracer.Direction() - 2.0 * (tracer.Direction() * unitNormal) * unitNormal; Ray reflected(intersectPoint + (usableEpsilion * reflectionDir), reflectionDir); Vector3D reflCol = (*this)(reflected, depth + 1, refrIndex); compositeColor += shapeMat->Color().Weight(refl * reflCol); } //apply refractions // if(refr > 0.0 && depth < _MaxTraceIterations) { // This is basically Snell's law double relIndex = refrIndex / rindex; Vector3D refractionNormal = unitNormal; // The cosine between the incident ray's direction and the unit normal should be non-positive (e.g. angle in [PI/2, PI]), otherwise normals need to be reversed if(refractionNormal * tracer.Direction() > 0) refractionNormal *= -1; double cosI = - (refractionNormal * tracer.Direction()); double cosT2 = 1.0 - (relIndex * relIndex) * (1.0 - (cosI * cosI)); if(cosT2 > 0.0) { Vector3D refractedDir = (relIndex * tracer.Direction()) + (relIndex * cosI - sqrt(cosT2)) * refractionNormal; Ray refracted(intersectPoint + (usableEpsilion * refractedDir), refractedDir); Vector3D refrCol = (*this)(refracted, depth + 1, rindex); compositeColor += shapeMat->Color().Weight(refr * refrCol); } } return compositeColor; }
//------------------------------------------------------------------------------ //from[http://www.flipcode.com/archives/Raytracing_Topics_Techniques-Part_7_Kd-Trees_and_More_Speed.shtml] bool Triangle::Intersect( const Ray& _ray, Intersection& o_intersection ) const { /* v0 /\ b / \c v1/_____\ v2 a */ Vector b = m_vertex[1] - m_vertex[0]; Vector c = m_vertex[2] - m_vertex[0]; Vector normal = b.Cross (c); //triangle is a line if( RealCompare( normal.Dot(normal), 0.0f, 0.0000000001 ) ) return false; Normalise(normal); //ray-plane intersection float rayParameter = normal.Dot ( m_vertex[0] - _ray.Origin () ) / normal.Dot ( _ray.Direction () ); //no intersection on the plane if ( rayParameter < 0.0f ) { return false; } //if on the plane //solve the problem on 2d //get dominant axis of normal uint8_t axis = normal.DominantAxis(); // p = p1*v1 + p2*v2 + p3*v3 // p1+ p2+ p3 =1 // p2 ( v2 - v1 ) + p3 ( v3 - v1 ) = intersection - v1 Vector intersectionPos = _ray.Origin () + rayParameter * _ray.Direction (); Vector diff = intersectionPos - m_vertex[0]; float bU, bV, cU, cV, diffU, diffV; uint8_t axisU = ( axis + 1 )%3; uint8_t axisV = ( axis + 2 )%3; diffU = diff[axisU]; diffV = diff[axisV]; bU = b[axisU]; bV = b[axisV]; cU = c[axisU]; cV = c[axisV]; float tmp = bU * cV - bV * cU ; float p2 = ( cV * diffU - cU * diffV ) / tmp; if ( p2<0.0 ) { return false; } float p3 = ( bU * diffV - bV * diffU ) / tmp; if ( p3<0.0 ) { return false; } if ( p2+ p3> 1.0 ) { return false; } float p1 = 1.0 - p2 - p3; Vector averageNormal = p1 * m_normal[0] + p2 * m_normal[1] + p3 * m_normal[2]; Vector2D averageTexCoord = p1 * m_texture[0] + p2 * m_texture[1] + p3 * m_texture[2]; Normalise(averageNormal); if( averageNormal.Dot( _ray.Direction() ) > 0 ) { return false; } if( m_pMaterial->kf() > 0 && _ray.Direction().Dot( averageNormal ) > 0 ) { //when calculating refraction for the ray inside object o_intersection = Intersection ( intersectionPos, averageNormal, averageTexCoord, rayParameter, g_air ); } else if( m_pMaterial->kf()==0 && _ray.Direction().Dot(averageNormal ) > 0) { printf("back face\n"); o_intersection = Intersection ( intersectionPos, averageNormal, averageTexCoord, rayParameter, m_pMaterial ); } else o_intersection = Intersection ( intersectionPos, averageNormal, averageTexCoord, rayParameter, m_pMaterial ); return true; }