コード例 #1
0
ファイル: Scene.cpp プロジェクト: GuillaumeArruda/INF8702
///////////////////////////////////////////////////////////////////////////////
///  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;
}
コード例 #2
0
ファイル: Scene.cpp プロジェクト: Eric-Morissette/INF8702
///////////////////////////////////////////////////////////////////////////////
///  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 );

    // ...
    // ...

    return Filter;
}
コード例 #3
0
ファイル: Scene.cpp プロジェクト: Eric-Morissette/INF8702
///////////////////////////////////////////////////////////////////////////////
///  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;
}
コード例 #4
0
ファイル: Triangle.cpp プロジェクト: GuillaumeArruda/INF8702
///////////////////////////////////////////////////////////////////////////////
///  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;
}
コード例 #5
0
ファイル: Triangle.cpp プロジェクト: UlricVilleneuve/INF8702
///////////////////////////////////////////////////////////////////////////////
///  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;
}
コード例 #6
0
ファイル: Scene.cpp プロジェクト: Eric-Morissette/INF8702
///////////////////////////////////////////////////////////////////////////////
///  public  LancerRayons \n
///  Description : Lancement des rayons (raytrace) dans la scène courante
///
///  @return None
///
///  @author Olivier Dionne 
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
void CScene::LancerRayons( void )
{
	Initialiser();

	// Distance entre la camera et la scene
	const float distanceCameraScene = CVecteur3::Distance(m_Camera.PointVise, m_Camera.Position);

	// Simple trigonometrie entre la distance entre la camera et la scene et l'angle de la camera
	const float hauteur = 2 * (tan(Deg2Rad(m_Camera.Angle)) * distanceCameraScene);
	// Regle de trois pour trouver la largeur a partir de la hauteur
	const float largeur = hauteur * m_ResLargeur / (float)m_ResHauteur;

	// On ne prend pas compte d'une rotation/orientation speciale de la camera ici, elle est prise en compte plus loin
	// La position Hauteur Min de la scene est la somme des vecteurs de distance en -Z et la moitie de la hauteur en -Y
	CVecteur3 positionHauteurMin = CVecteur3(0, -hauteur / 2, -distanceCameraScene);
	// Logique semblable pour la Largeur Min
	CVecteur3 positionLargeurMin = CVecteur3(-largeur / 2, 0, -distanceCameraScene);

	for (int y = 0; y < m_ResHauteur; ++y)
	{
		//Calculer la position pixelY dans la scene
		CVecteur3 pixelY = positionHauteurMin + CVecteur3(0, (y / (float)m_ResHauteur) * hauteur, 0);

		for (int x = 0; x < m_ResLargeur; ++x)
		{
			//Calculer la position pixelX dans la scene
			CVecteur3 pixelX = positionLargeurMin + CVecteur3((x / (float)m_ResLargeur) * largeur, 0, 0);

			CRayon rayon;

			//Ajuster l'origine du rayon
			rayon.AjusterOrigine(m_Camera.Position);

			//Ajuster la direction du rayon
			CVecteur3 direction = CVecteur3::Normaliser(pixelX + pixelY);
			//Ajuster la direction selon la matrice d'orientation de la camera
			rayon.AjusterDirection(direction * m_Camera.Orientation);
			
			//Initialiser les autres caracteristiques du rayon
			rayon.AjusterEnergie(Math3D::REAL(1));
			rayon.AjusterNbRebonds(0);
			rayon.AjusterIndiceRefraction(Math3D::REAL(1));

			//Lancer le rayon et obtenir la couleur
			CCouleur couleur = CScene::ObtenirCouleur(rayon);

			//Enregistrer les couleurs
			m_InfoPixel[(x + y * m_ResLargeur) * 3]     = couleur.r;
			m_InfoPixel[(x + y * m_ResLargeur) * 3 + 1] = couleur.g;
			m_InfoPixel[(x + y * m_ResLargeur) * 3 + 2] = couleur.b;
		}
	}

    // Créer une texture openGL
    glGenTextures  ( 1, &m_TextureScene );
    glBindTexture  ( GL_TEXTURE_2D, m_TextureScene );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexImage2D   ( GL_TEXTURE_2D, 0, GL_RGBA8, m_ResLargeur, m_ResHauteur, 0, GL_RGB, GL_FLOAT, m_InfoPixel );
}
コード例 #7
0
ファイル: Scene.cpp プロジェクト: GuillaumeArruda/INF8702
///////////////////////////////////////////////////////////////////////////////
///  public  LancerRayons \n
///  Description : Lancement des rayons (raytrace) dans la scène courante
///
///  @return None
///
///  @author Olivier Dionne
///  @date   13/08/2008
///
///////////////////////////////////////////////////////////////////////////////
void CScene::LancerRayons( void )
{
    Initialiser();

    REAL HalfH        = tan( Deg2Rad<REAL>( m_Camera.Angle * RENDRE_REEL( 0.5 ) ) );
    REAL HalfW        = ( RENDRE_REEL( m_ResLargeur ) / m_ResHauteur ) * HalfH;
    REAL InvResWidth  = RENDRE_REEL( 1.0 ) / m_ResLargeur;
    REAL InvResHeight = RENDRE_REEL( 1.0 ) / m_ResHauteur;

    CRayon   Rayon;
    CCouleur PixelColor;
    int      PixelIdx = 0;

    #pragma omp parallel for private(Rayon, PixelColor, PixelIdx)
    for( int PixY = 0; PixY < m_ResHauteur; PixY++ )
    {
        for( int PixX = 0; PixX < m_ResLargeur; PixX++ )
        {

            // Prépare le rayon
            Rayon.AjusterOrigine( m_Camera.Position );

            Rayon.AjusterDirection( CVecteur3( ( 2 * PixX * InvResWidth  - 1 ) * HalfW,
                                               ( 2 * PixY * InvResHeight - 1 ) * HalfH,
                                               -1 ) );

            Rayon.AjusterDirection( CVecteur3::Normaliser( Rayon.ObtenirDirection() * m_Camera.Orientation ) );
            Rayon.AjusterEnergie( 1 );
            Rayon.AjusterNbRebonds( 0 );
            Rayon.AjusterIndiceRefraction( 1 );

            PixelColor = ObtenirCouleur( Rayon );

            PixelIdx = ( PixX + ( PixY * m_ResLargeur ) ) * 3;
            m_InfoPixel[ PixelIdx + 0 ] = PixelColor.r;
            m_InfoPixel[ PixelIdx + 1 ] = PixelColor.g;
            m_InfoPixel[ PixelIdx + 2 ] = PixelColor.b;
        }
    }

    // Créer une texture openGL
    glGenTextures  ( 1, &m_TextureScene );
    glBindTexture  ( GL_TEXTURE_2D, m_TextureScene );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexImage2D   ( GL_TEXTURE_2D, 0, GL_RGBA8, m_ResLargeur, m_ResHauteur, 0, GL_RGB, GL_FLOAT, m_InfoPixel );
}
コード例 #8
0
ファイル: Quadrique.cpp プロジェクト: GuillaumeArruda/INF8702
///////////////////////////////////////////////////////////////////////////////
///  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;
}
コード例 #9
0
ファイル: Quadrique.cpp プロジェクト: GuillaumeArruda/INF8702
///////////////////////////////////////////////////////////////////////////////
///  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;
}