Exemplo n.º 1
0
///////////////////////////////////////////////////////////////////////////////
///  private constant  ObtenirFiltreDeSurface \n
///  Description : Obtenir le filtre du matériau de la surface. Le coefficient de
///                réfraction nous indique du même coup s'il y a transparence de la
///                surface.
///
///  @param [in, out]  LumiereRayon CRayon &     Le rayon de lumière (ou d'ombre) à tester
///
///  @return const CCouleur Le filtre de couleur
///
///  @author Olivier Dionne
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
const CCouleur CScene::ObtenirFiltreDeSurface( CRayon& LumiereRayon ) const
{
    CCouleur Filter = CCouleur::BLANC;
    CIntersection LumiereIntersection;

    REAL Distance = CVecteur3::Norme( LumiereRayon.ObtenirDirection() );
    LumiereRayon.AjusterDirection( LumiereRayon.ObtenirDirection() / Distance );

    // TODO : À COMPLÉTER LORS DU VOLET 2...


    // Tester le rayon de lumière avec chaque surface de la scène
    // pour vérifier s'il y a intersection
    CIntersection Result;
    CIntersection Tmp;

    for (SurfaceIterator aSurface = m_Surfaces.begin(); aSurface != m_Surfaces.end(); aSurface++)
    {
        Tmp = (*aSurface)->Intersection(LumiereRayon);
        if (Tmp.ObtenirDistance() > EPSILON)
        {
            Filter *= Tmp.ObtenirSurface()->ObtenirCoeffRefraction() * Tmp.ObtenirSurface()->ObtenirCouleur();
        }
    }

    // S'il y a une intersection appliquer la translucidité de la surface
    // intersectée sur le filtre

    return Filter;
}
Exemplo n.º 2
0
///////////////////////////////////////////////////////////////////////////////
///  public virtual  Intersection \n
///  Description : Effectue l'intersection Rayon/Triangle
///
///  @param [in]       Rayon const CRayon &    Le rayon à tester
///
///  @return Scene::CIntersection Le résultat de l'ntersection
///
///  @author Olivier Dionne 
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
CIntersection CTriangle::Intersection( const CRayon& Rayon )
{
    CIntersection Result;

    // Tomas Akenine-Moller and Eric Haines "Real-Time Rendering 2nd Ed." 2002, p.581
    // http://jgt.akpeters.com/papers/MollerTrumbore97/code.html

    CVecteur3 Edge1 = m_Pts[ 1 ] - m_Pts[ 0 ];
    CVecteur3 Edge2 = m_Pts[ 2 ] - m_Pts[ 0 ];

    // Commencer par le calcul du déterminant - aussi utilisé pour calculer U
    CVecteur3 VecP = CVecteur3::ProdVect( Rayon.ObtenirDirection(), Edge2 );
    // Si le déterminant est près de 0, le rayon se trouve dans le PLAN du triangle
    REAL Det  = CVecteur3::ProdScal( Edge1, VecP );

    if( Abs<REAL>( Det ) < EPSILON )
        return Result;
    else
    {
        REAL InvDet = RENDRE_REEL( 1.0 ) / Det;
        
        // Calculer la distance entre point0 et l'origine du rayon
        CVecteur3 VecS = Rayon.ObtenirOrigine() - m_Pts[ 0 ];
        // Calculer le paramètre U pour tester les frontières
        REAL u = CVecteur3::ProdScal( VecS, VecP ) * InvDet;
        if ( u < 0 || u > 1 )
            return Result;
        else
        {
            CVecteur3 VecQ = CVecteur3::ProdVect( VecS, Edge1 );

            // Calculer le paramètre V pour tester les frontières
            REAL v = CVecteur3::ProdScal( Rayon.ObtenirDirection(), VecQ ) * InvDet;
            if( v < 0 || u + v > 1 )
                return Result;
            else
            {
                Result.AjusterSurface( this );
                Result.AjusterDistance( CVecteur3::ProdScal( Edge2, VecQ ) * InvDet );
                Result.AjusterNormale( m_Normale );
            }
        }
    }

    return Result;
}
Exemplo n.º 3
0
///////////////////////////////////////////////////////////////////////////////
///  public virtual  Intersection \n
///  Description : Effectue l'intersection Rayon/Triangle
///
///  @param [in]       Rayon const CRayon &    Le rayon à tester
///
///  @return Scene::CIntersection Le résultat de l'ntersection
///
///  @author Olivier Dionne 
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
CIntersection CTriangle::Intersection(const CRayon& Rayon)
{
	CIntersection Result;

	// À COMPLÉTER ... 

	// Voici deux références pour acomplir le développement :
	// 1) Tomas Akenine-Moller and Eric Haines "Real-Time Rendering 2nd Ed." 2002, p.581
	// 2) Son article: http://www.graphics.cornell.edu/pubs/1997/MT97.pdf

	// Notez que la normale du triangle est déjà calculée lors du prétraitement
	// il suffit que de la passer à la structure d'intersection.
	CVecteur3 edge1 = m_Pts[1] - m_Pts[0];
	CVecteur3 edge2 = m_Pts[2] - m_Pts[0];
	CVecteur3 pvec = CVecteur3::ProdVect(Rayon.ObtenirDirection(), edge2);
	REAL det = CVecteur3::ProdScal(edge1, pvec);

	if (det < EPSILON)
		return Result;

	CVecteur3 tvec = Rayon.ObtenirOrigine() - m_Pts[0];

	REAL U = CVecteur3::ProdScal(tvec, pvec);

	if ((U < EPSILON) || (U > det))
		return Result;

	CVecteur3 qvec = CVecteur3::ProdVect(tvec, edge1);

	REAL V = CVecteur3::ProdScal(Rayon.ObtenirDirection(), qvec);

	if ((V < EPSILON) || (U + V > det))
		return Result;

	REAL t = CVecteur3::ProdScal(edge2, qvec) / det;
	Result.AjusterDistance(t);
	Result.AjusterSurface(this);
	if (CVecteur3::ProdScal(m_Normale, Rayon.ObtenirDirection()) > EPSILON) {
		Result.AjusterNormale(-m_Normale);
	}
	else {
		Result.AjusterNormale(m_Normale);
	}
	return Result;
}
Exemplo n.º 4
0
///////////////////////////////////////////////////////////////////////////////
///  private constant  ObtenirCouleurSurIntersection \n
///  Description : Obtient la couleur à un point d'intersection en particulier
///                Calcule les contributions colorées de toutes les lumières, avec
///                les modèles de Phong et de Gouraud. Aussi, dépendemment des
///                propriétés de la surface en intersection, on réfléchi ou in 
///                réfracte le rayon courant.
///                current ray.
///
///  @param [in]       Rayon const CRayon &    Le rayon à tester
///  @param [in]       Intersection const Scene::CIntersection &    L'ntersection spécifiée
///
///  @return const CCouleur La couleur à l'intersection donnée
///
///  @author Olivier Dionne 
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
const CCouleur CScene::ObtenirCouleurSurIntersection( const CRayon& Rayon, const CIntersection& Intersection ) const
{
    CCouleur  Result = Intersection.ObtenirSurface()->ObtenirCouleur() * Intersection.ObtenirSurface()->ObtenirCoeffAmbiant();
    CVecteur3 IntersectionPoint = Rayon.ObtenirOrigine()+ Intersection.ObtenirDistance() * Rayon.ObtenirDirection();
    
    // Calculer les contribution colorées des toutes les lumières dans la scène
    CCouleur LumiereContributions = CCouleur::NOIR;
    CRayon   LumiereRayon;
    for( LumiereIterator uneLumiere = m_Lumieres.begin(); uneLumiere != m_Lumieres.end(); uneLumiere++ )
    {
        // Initialise le rayon de lumière (ou rayon d'ombre)
        LumiereRayon.AjusterOrigine( IntersectionPoint );
        LumiereRayon.AjusterDirection( ( *uneLumiere )->GetPosition() - IntersectionPoint );
        LumiereRayon.AjusterEnergie( 1 );
        LumiereRayon.AjusterIndiceRefraction( 1 );

        if( CVecteur3::ProdScal( LumiereRayon.ObtenirDirection(), Intersection.ObtenirNormale() ) > 0 )
        {
            // Obtenir la couleur à partir de la lumière
            CCouleur Filter         = ObtenirFiltreDeSurface( LumiereRayon );
            CCouleur LumiereCouleur = ( *uneLumiere )->ObtenirCouleur() * Filter;

            // Ajouter la contribution de Gouraud
            REAL GouraudFactor = ( *uneLumiere )->GetIntensity() * Intersection.ObtenirSurface()->ObtenirCoeffDiffus() *
                CVecteur3::ProdScal( Intersection.ObtenirNormale(), LumiereRayon.ObtenirDirection() );
            Result += Intersection.ObtenirSurface()->ObtenirCouleur() * GouraudFactor * LumiereCouleur;

            // ...
        }
    }

    return Result;
}
Exemplo n.º 5
0
///////////////////////////////////////////////////////////////////////////////
///  private constant  ObtenirCouleur \n
///  Description : Obtenir la couleur du pixel pour un rayon donné
///
///  @param [in]       Rayon const CRayon &    Le rayon à tester
///
///  @return const CCouleur La couleur du pixel
///
///  @author Olivier Dionne 
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
const CCouleur CScene::ObtenirCouleur( const CRayon& Rayon ) const
{
    CIntersection Result;
    CIntersection Tmp;
    
    for( SurfaceIterator aSurface = m_Surfaces.begin(); aSurface != m_Surfaces.end(); aSurface++ )
    {
        Tmp = ( *aSurface )->Intersection( Rayon );
        if( Tmp.ObtenirDistance() > EPSILON && ( Tmp.ObtenirDistance() < Result.ObtenirDistance() || Result.ObtenirDistance() < 0 ) )
            Result = Tmp;
    }
    
    // S'il n'y a aucune intersection, retourner la couleur de l'arrière-plan
    // Sinon, retourner la couleur à l'intersection
    return ( Result.ObtenirDistance() < 0 ) ? m_CouleurArrierePlan : ObtenirCouleurSurIntersection( Rayon, Result );
}
Exemplo n.º 6
0
bool CTriangleMesh::Hit(CRay const& ray, CIntersection & intersection) const
{
	// Вычисляем обратно преобразованный луч (вместо вполнения прямого преобразования объекта)
	CRay invRay = Transform(ray, GetInverseTransform());
	CVector3d const& invRayStart = invRay.GetStart();
	CVector3d const& invRayDirection = invRay.GetDirection();

	//////////////////////////////////////////////////////////////////////////
	// Здесь следует выполнить проверку на пересечение луча с ограничивающим
	// объемом (bounding volume) полигональной сетки.
	// При отсутствии такого пересечения луч гарантированно не будет пересекать
	// ни одну из граней сетки, что позволит избежать лишних проверок:
	// if (!ray_intesects_bounding_volume)
	//     return false;
	//////////////////////////////////////////////////////////////////////////
	
	// Получаем информацию о массиве треугольников сетки
	CTriangle const* const triangles = m_pMeshData->GetTriangles();
	const size_t numTriangles = m_pMeshData->GetTriangleCount();

	// Массив найденных пересечений луча с гранями сетки.
	std::vector<FaceHit> faceHits;

	//////////////////////////////////////////////////////////////////////////
	// Используется поиск пересечения луча со всеми гранями сетки.
	// Данный подход является очень неэффективным уже на полигональных сетках,
	// содержащих более нескольких десятков граней, а, тем более, сотни и тысячи граней.
	//
	// Для эффективного поиска столкновений следует представить полигональную сетку
	// не в виде массива граней, а в виде древовидной структуры (Oct-Tree или BSP-Tree),
	// что уменьшит вычислительную сложность поиска столкновений с O(N) до O(log N)
	//////////////////////////////////////////////////////////////////////////
	FaceHit hit;
	for (size_t i = 0; i < numTriangles; ++i)
	{
		CTriangle const& triangle = triangles[i];

		// Проверка на пересечение луча с треугольной гранью
		if (triangle.HitTest(invRayStart, invRayDirection, hit.hitTime, hit.hitPointInObjectSpace, hit.w0, hit.w1, hit.w2))
		{
			// Сохраняем индекс грани и добавляем информацию в массив найденных пересечений
			hit.faceIndex = i;

			if (faceHits.empty())
			{
				// При обнаружени первого пересечения резервируем
				// память сразу под 8 пересечений (для уменьшения количества операций выделения памяти)
				faceHits.reserve(8);
			}
			faceHits.push_back(hit);
		}
	}

	// При отсутствии пересечений выходим
	if (faceHits.empty())
	{
		return false;
	}

	//////////////////////////////////////////////////////////////////////////
	// Упорядочиваем найденные пересечения по возрастанию времени столкновения
	//////////////////////////////////////////////////////////////////////////
	size_t const numHits = faceHits.size();
	std::vector<FaceHit const *> hitPointers(numHits);
	{
		// Инициализируем массив указателей на точки пересечения
		for (size_t i = 0; i < numHits; ++i)
		{
			hitPointers[i] = &faceHits[i];
		}

		// Сортируем массив указателей по возрастанию времени столкновения
		// Сортируются указатели, а не сами объекты, чтобы сократить
		// издержки на обмен элементов массива:
		// На 32 битной платформе размер структуры FaceHit равен 64 байтам,
		// а размер указателя - всего 4 байта.
		if (numHits > 1)
		{
			std::sort(hitPointers.begin(), hitPointers.end(), HitPointerComparator());
			// Теперь указатели в массиве hitPointers отсортированы
			// в порядке возрастания времени столкновения луча с гранями
		}
	}

	//////////////////////////////////////////////////////////////////////////
	// Возвращаем информацию о найденных пересечениях
	//////////////////////////////////////////////////////////////////////////
	for (size_t i = 0; i < numHits; ++i)
	{
		// Получаем информацию о столкновении
		FaceHit const& faceHit = *hitPointers[i];

		// Сохраняем информацию только о первом пересечении
		if (i == 0)
		{
			ExtendedHitData *hd = (ExtendedHitData*)&m_lastHitData;
			hd->faceIndex = faceHit.faceIndex;
			hd->vc[0] = static_cast<float>(faceHit.w0);
			hd->vc[1] = static_cast<float>(faceHit.w1);
			hd->vc[2] = static_cast<float>(faceHit.w2);
		}

		// Точка столкновения в мировой системе координат
		CVector3d hitPoint = ray.GetPointAtTime(faceHit.hitTime);

		// Грань, с которой произошло столкновение
		CTriangle const& triangle = triangles[faceHit.faceIndex];

		// Нормаль "плоской грани" во всех точках столкновения равна нормали самой грани
		CVector3d normalInObjectSpace = triangle.GetPlaneEquation();

		if (!triangle.IsFlatShaded())
		{
			// Для неплоских граней выполняется интерполяция нормалей вершин треугольника
			// с учетом их весовых коэффициентов в точке пересечения
			Vertex const& v0 = triangle.GetVertex0();
			Vertex const& v1 = triangle.GetVertex1();
			Vertex const& v2 = triangle.GetVertex2();

			// Взвешенный вектор нормали
			normalInObjectSpace = 
				faceHit.w0 * v0.normal + 
				faceHit.w1 * v1.normal +
				faceHit.w2 * v2.normal;
		}

		// Нормаль в мировой системе координат
		CVector3d normal = GetNormalMatrix() * normalInObjectSpace;

		// Добавляем информацию о точке пересечения в объект intersection
		intersection.AddHit(
			CHitInfo(
				faceHit.hitTime, *this, 
				hitPoint,
				faceHit.hitPointInObjectSpace,
				normal, normalInObjectSpace
				)
			);
	}

	return true;
}
Exemplo n.º 7
0
///////////////////////////////////////////////////////////////////////////////
///  public virtual  Intersection \n
///  Description : Effectue l'intersection Rayon/Quadrique
///
///  @param [in]       Rayon const CRayon &    Le rayon à tester
///
///  @return Scene::CIntersection Le résultat de l'ntersection
///
///  @author Olivier Dionne 
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
CIntersection CQuadrique::Intersection( const CRayon& Rayon )
{
    CIntersection Result;

    // algorithme d'intersection tiré de ... 
    // Eric Haines, Paul Heckbert "An Introduction to Rayon Tracing",
    // Academic Press, Edited by Andrw S. Glassner, pp.68-73 & 288-293

    CVecteur3 RayonDirection = Rayon.ObtenirDirection();
    CVecteur3 RayonOrigin    = Rayon.ObtenirOrigine();

    const REAL ACoeff = RayonDirection.x * ( m_Quadratique.x * RayonDirection.x   +
                                             m_Mixte.z       * RayonDirection.y   +
                                             m_Mixte.y       * RayonDirection.z ) +
                        RayonDirection.y * ( m_Quadratique.y * RayonDirection.y   +
                                             m_Mixte.x       * RayonDirection.z ) +
                        RayonDirection.z * ( m_Quadratique.z * RayonDirection.z );

    const REAL BCoeff = RayonDirection.x * ( m_Quadratique.x * RayonOrigin.x + RENDRE_REEL( 0.5 )                     *
                                           ( m_Mixte.z * RayonOrigin.y + m_Mixte.y * RayonOrigin.z + m_Lineaire.x ) ) +
                        RayonDirection.y * ( m_Quadratique.y * RayonOrigin.y + RENDRE_REEL( 0.5 )                     * 
                                           ( m_Mixte.z * RayonOrigin.x + m_Mixte.x * RayonOrigin.z + m_Lineaire.y ) ) +
                        RayonDirection.z * ( m_Quadratique.z * RayonOrigin.z + RENDRE_REEL( 0.5 )                     * 
                                           ( m_Mixte.y * RayonOrigin.x + m_Mixte.x * RayonOrigin.y + m_Lineaire.z ) );

    const REAL CCoeff = RayonOrigin.x * ( m_Quadratique.x * RayonOrigin.x   +
                                          m_Mixte.z       * RayonOrigin.y   +
                                          m_Mixte.y       * RayonOrigin.z   +
                                          m_Lineaire.x                    ) +
                        RayonOrigin.y * ( m_Quadratique.y * RayonOrigin.y   +
                                          m_Mixte.x       * RayonOrigin.z   +
                                          m_Lineaire.y                    ) +
                        RayonOrigin.z * ( m_Quadratique.z * RayonOrigin.z   +
                                          m_Lineaire.z                    ) +
                        m_Cst;

    
    if( ACoeff != 0.0 )
    {
        REAL Ka    = -BCoeff / ACoeff;
        REAL Kb    =  CCoeff / ACoeff;
        REAL Delta = Ka * Ka - Kb;

        if( Delta > 0 )
        {
            Delta   = sqrt( Delta );
            REAL T0 = Ka - Delta;
            REAL T1 = Ka + Delta;

            REAL Distance = Min<REAL>( T0, T1 );
            if( Distance < EPSILON )
                Distance = Max<REAL>( T0, T1 );
            
            if( !( Distance < 0 ) )
            {
                Result.AjusterDistance( Distance );
                Result.AjusterSurface( this );

                // Calcule la normale de surface
                CVecteur3 HitPt = RayonOrigin + Distance * RayonDirection;
                
                CVecteur3 Normal;
                Normal.x = RENDRE_REEL( 2.0 ) * m_Quadratique.x * HitPt.x +
                           m_Mixte.y * HitPt.z                            +
                           m_Mixte.z * HitPt.y                            +
                           m_Lineaire.x;

                Normal.y = RENDRE_REEL( 2.0 ) * m_Quadratique.y * HitPt.y +
                           m_Mixte.x * HitPt.z                            +
                           m_Mixte.z * HitPt.x                            +
                           m_Lineaire.y;

                Normal.z = RENDRE_REEL( 2.0 ) * m_Quadratique.z * HitPt.z +
                           m_Mixte.x * HitPt.y                            +
                           m_Mixte.y * HitPt.x                            +
                           m_Lineaire.z;

                Result.AjusterNormale( CVecteur3::Normaliser( Normal ) );
            }
        }
    }
    else
    {
        Result.AjusterSurface ( this );
        Result.AjusterDistance( -RENDRE_REEL( 0.5 ) * ( CCoeff / BCoeff ) );
        Result.AjusterNormale ( CVecteur3::Normaliser( m_Lineaire ) );
    }

    return Result;
}
Exemplo n.º 8
0
///////////////////////////////////////////////////////////////////////////////
///  public virtual  Intersection \n
///  Description : Effectue l'intersection Rayon/Quadrique
///
///  @param [in]       Rayon const CRayon &    Le rayon à tester
///
///  @return Scene::CIntersection Le résultat de l'ntersection
///
///  @author Olivier Dionne 
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
CIntersection CQuadrique::Intersection( const CRayon& Rayon )
{
    CIntersection Result;

	float a, b, c, d, e, f, g, h, i, j;
	float A, B, C;
	float t0, t1, tf;
	const CVecteur3 rd = Rayon.ObtenirDirection();
	const CVecteur3 r0 = Rayon.ObtenirOrigine();

	/*a = m_Quadratique[0];
	e = m_Quadratique[1];
	h = m_Quadratique[2];

	b = m_Mixte[0];
	c = m_Mixte[1];
	f = m_Mixte[2];

	d = m_Lineaire[0];
	g = m_Lineaire[1];
	i = m_Lineaire[2];

	j = m_Cst;

	A = a * rd.x * rd.x + 2 * b * rd.x * rd.y + 2 * c * rd.x * rd.z +
		e * rd.y * rd.y + 2 * f * rd.y * rd.z + h * rd.z * rd.z;

	B = 2 * (a * r0.x * rd.x + b * (r0.x * rd.y + rd.x * r0.y) + c * (r0.x * rd.z + rd.x * r0.z) +
		d * rd.x + e * r0.y * rd.y + f * (r0.y * rd.z + rd.y * r0.z) + g * rd.y +
		h * r0.z * rd.z + i * rd.z);

	C = a * r0.x * r0.x + 2 * b * r0.x * r0.y + 2 * c * r0.x * r0.z + 2 * d * r0.x +
		e * r0.y * r0.y + 2 * f * r0.y * r0.z + 2 * g * r0.y +
		h * r0.z * r0.z + 2 * i * r0.z + j;*/

    a = m_Quadratique[0];
    b = m_Quadratique[1];
    c = m_Quadratique[2];

    d = m_Mixte[0];
    e = m_Mixte[1];
    f = m_Mixte[2];

    g = m_Lineaire[0];
    h = m_Lineaire[1];
    i = m_Lineaire[2];

    j = m_Cst;

    A = a * rd.x * rd.x + b * rd.y * rd.y + c * rd.z * rd.z + d * rd.x * rd.y +
        e * rd.x * rd.z + f * rd.y * rd.z;

    B = 2 * a * r0.x * rd.x + 2 * b * r0.y * rd.y + 2 * c * r0.z * rd.z + 
        d * (r0.x * rd.y + r0.y * rd.x) + e * (r0.x * rd.z) + f * (r0.y * rd.z + rd.y * r0.z) +
        g * rd.x + h * rd.y + i * rd.z;

    C = a * r0.x * r0.x + b * r0.y * r0.y + c * r0.z * r0.z + d * r0.x * r0.y +
        e * r0.x * r0.z + f * r0.y * r0.z + g * r0.x + h * r0.y + i * r0.z + j;

    if (A == 0.f)
    {
        tf = -C / B;
    }
    else
    {
        float discriminant = B * B - 4 * A * C;
        if (discriminant < 0)
        {
            return Result;
        }
        else
        {
            tf = (-B - sqrt(discriminant)) / (2 * A);
            if (tf < 0)
            {
                tf = (-B + sqrt(discriminant)) / (2 * A);
                if (tf < 0)
                    return Result;
            }

        }
    }

    CVecteur3 intersection(r0 + rd * tf);
    Result.AjusterDistance(CVecteur3::Norme(intersection - r0));

    CVecteur3 normale;
    normale.x =  (2 * a * intersection.x + d * intersection.y + e * intersection.z) + g;
    normale.y =  (d * intersection.x + 2 * b * intersection.y + f * intersection.z) + h;
    normale.z =  (e * intersection.x + f * intersection.y + 2 * c * intersection.z) + i;
    normale = CVecteur3::Normaliser(normale);

    Result.AjusterNormale(CVecteur3::ProdScal(normale, rd) > 0 ? -normale : normale);
    Result.AjusterSurface(this);

    return Result;
}