//------------------------------------------------------------------------------ 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; }
// 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::Intersects(const Ray& r,float& result) const { float VD=Vector3::Dot(normal,r.Dir()); if(VD==0) return false; float V0=-(Vector3::Dot(normal,r.Origin())+distance); result=V0/VD; if(result<EPSILON) //role of EPSILON is explained in "common.h" return false; return true; }
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; }
//------------------------------------------------------------------------------ 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; }
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; }
bool AABB::Intersect(const Ray& ray, Intersection& intersection, void* additional_data) const { ++Profiler::numRayVolumeTestsPerFrame; Vector3 origin = ray.Origin(); Vector3 inversed_dir = ray.InvDirection(); Range<float> t, t_y, t_z; if (inversed_dir.X() >= 0) { t.Max = (m_MaxExtent.X() - origin.X()) * inversed_dir.X(); t.Min = (m_MinExtent.X() - origin.X()) * inversed_dir.X(); } else { t.Min = (m_MaxExtent.X() - origin.X()) * inversed_dir.X(); t.Max = (m_MinExtent.X() - origin.X()) * inversed_dir.X(); } if (inversed_dir.Y() >= 0) { t_y.Max = (m_MaxExtent.Y() - origin.Y()) * inversed_dir.Y(); t_y.Min = (m_MinExtent.Y() - origin.Y()) * inversed_dir.Y(); } else { t_y.Min = (m_MaxExtent.Y() - origin.Y()) * inversed_dir.Y(); t_y.Max = (m_MinExtent.Y() - origin.Y()) * inversed_dir.Y(); } if (t.Min > t_y.Max || t_y.Min > t.Max) return false; if (t.Min < t_y.Min) t.Min = t_y.Min; if (t.Max > t_y.Max) t.Max = t_y.Max; if (inversed_dir.Z() >= 0) { t_z.Max = (m_MaxExtent.Z() - origin.Z()) * inversed_dir.Z(); t_z.Min = (m_MinExtent.Z() - origin.Z()) * inversed_dir.Z(); } else { t_z.Min = (m_MaxExtent.Z() - origin.Z()) * inversed_dir.Z(); t_z.Max = (m_MinExtent.Z() - origin.Z()) * inversed_dir.Z(); } if (t.Min > t_z.Max || t_z.Min > t.Max) return false; if (t.Min < t_z.Min) t.Min = t_z.Min; if (t.Max > t_z.Max) t.Max = t_z.Max; Range<float> range = ray.EffectRange(); if (Math::Contain(t.Min, range)) intersection.SetDistance(t.Min); else if (Math::Contain(t.Max, range)) intersection.SetDistance(0.f); else if (range.Min > t.Min && range.Max < t.Max) intersection.SetDistance(0.f); else return false; intersection.SetIntersectObject((IIntersectTarget*)this); intersection.SetTestObject(&ray); return true; }
//------------------------------------------------------------------------ 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; }