Tutorial 12 - Objetos-3D
Fecha Miércoles, 05 septiembre a las 22:25:51
Tema DirectX/Opengl


Vamos a empezar gestionando los objetos de la escena 3D. En un principio (ya que hay pocos) lo vamos a hacer almacenando los objetos en una lista, aprovechando la librería estandar de C++: STL.



STL (Standard Template Library) es una librería de plantillas que contiene estructuras de datos de uso común en programación, como son listas, pilas, colas, etc. Para ello incluiremos el fichero stl.h que contiene inclusiones de diferentes plantillas así como unos "pragmas" para eliminar los "millones" de "warnings" que aparecen en Visual cuando se usan las STL.

Definimos OBJECT_MAP en el fichero glapplication.h como una tabla hash donde cada elemento se referencia por una cadena de texto. STL tiene la clase string para el uso de cadenas de caracteres. NUNCA defináis un map con "char *" como clave hacedlo con la clase string, ya que de la otra forma, la clave sería el valor del puntero a char y no os funcionaría.


    typedef std::map< std::string, Object * >       OBJECT_MAP;

En nuestro ejemplo hemos creado la clase Object de la cual derivan las clases Cube, Cylinder y Sphere. La lista de objetos, almacena punteros a la clase Object, pero se almacenan punteros a las clases derivadas. Esto es lo que se denomina en C++ polimorfismo dinámico.

Al crear el objeto dinámicamente, se crea de la clase de objeto que corresponda, y realiza un casting a (Object*) para almacenarlo en el map. Podríamos usar castings de C, pero vamos a usar los de C++ para ver cómo funcionan.

En este caso, vamos a realizar un casting de una clase derivada a una clase padre. Como podemos ver en el comentario del código, este casting se resuelve en tiempo de compilación, con lo que se utiliza: > static_cast < T > (ptr).


    ///////////////////////////////////////////////////////////////////////////////
    ///     CreateSceneObjects: Crea los objetos que componen la escena 3D.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::CreateSceneObjects()
    {
        Vector3 points[2] =
        {
            Vector3( -1,-1,-1 ),
            Vector3(  1, 1, 1 )
        };

        Object *pObject= NULL;

        // **************************************************************************************************************************
        // NOTA:
        // La conversión una clase derivada a una clase-base (upcast) se resuelve en tiempo de compilación -> static_cast < T > (ptr)
        // Si fuese una conversión de una clase-base a una derivada (downcast) se resuelve en tiempo de ejecución -> dynamic_cast< T > (ptr)
        // **************************************************************************************************************************

        // *** Creamos un cubo ***
        Cube *pCube= new Cube("CUBO");

        if ( pCube )
        {
            pCube->Calculate( points, 2 );

            // Lo posicionamos
            Vector3 vPosition(0,2,0);
            pCube->SetPosition( vPosition );

            // Añadimos el objeto a la lista.
            m_ObjectList[ std::string(pCube->GetName()) ]= static_cast( pCube );
        }

        // *** Creamos una esfera ***
        Sphere *pSphere= new Sphere("ESFERA");

        if ( pSphere )
        {
            pSphere->Calculate( points, 2 );

            // Lo posicionamos
            Vector3 vPosition(4,1.5f,0);
            pSphere->SetPosition( vPosition );

            // Añadimos el objeto a la lista.
            m_ObjectList[ std::string(pSphere->GetName()) ]=  static_cast( pSphere );
        }

        // *** Creamos un cilindro ***
        Cylinder *pCylinder= new Cylinder("CILINDRO");

        if ( pCylinder )
        {
            pCylinder->Calculate( points, 2 );

            // Lo posicionamos
            Vector3 vPosition(-5,2,0);
            pCylinder->SetPosition( vPosition );

            // Añadimos el objeto a la lista.
            m_ObjectList[ std::string(pCylinder->GetName()) ]=  static_cast( pCylinder );
        }
    }

Cuando vamos a renderizar, vamos a acceder a los elementos almacenados en el map, que son punteros a Object, pero realmente contiene referencias a los diferentes tipos de geometrías. Debemos realizar un casting a la inversa ya que las distintas geometrías tienen métodos particulares que no se encuentran presentes en la clase Object.

Para realizar un casting de la clase padre a la clase derivada (ver comentario del código fuente) hay que usar > dynamic_cast< T > (ptr).


    ///////////////////////////////////////////////////////////////////////////////
    ///     RenderSceneObjects: Renderiza los objetos que componen la escena 3D.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::RenderSceneObjects()
    {
        Object *pObject;
        OBJECT_MAP::iterator itObj;

        fColorRGBA greenColor   = { 0.0f, 1.0f, 0.0f, 0.0f };   // Verde
        fColorRGBA yellowColor  = { 1.0f, 1.0f, 0.0f, 0.0f };   // Amarillo
        fColorRGBA redColor     = { 1.0f, 0.0f, 0.0f, 0.0f };   // Rojo

        Material greenMaterial, yellowMaterial, redMaterial;

        memset( &greenMaterial, 0, sizeof(Material) );
        greenMaterial.ambient   = greenColor;
        greenMaterial.diffuse   = greenColor;
        greenMaterial.specular  = greenColor;

        memset( &yellowMaterial, 0, sizeof(Material) );
        yellowMaterial.ambient  = yellowColor;
        yellowMaterial.diffuse  = yellowColor;
        yellowMaterial.specular = yellowColor;

        memset( &redMaterial, 0, sizeof(Material) );
        redMaterial.ambient     = redColor;
        redMaterial.diffuse     = redColor;
        redMaterial.specular    = redColor;

        for ( itObj=m_ObjectList.begin(); itObj!=m_ObjectList.end(); ++itObj )
        {
            pObject= itObj->second;

            if ( pObject )
            {
                // *****************************************************************************************************************
                // NOTA:
                // La conversión es de una clase-base a una derivada y se resuelve en tiempo de ejecución -> dynamic_cast< T > (ptr)
                // Para poder usar dynamic_cast en Visual C, hay que activar la opción RTTI.
                // Menú: Project -> Settings... -> Pestaña C/C++ -> Category: C++ Language, marcar "Enable Run-Time Type Information (RTTI)".
                // *****************************************************************************************************************

                if ( !strcmp(pObject->GetName(),"CUBO") )
                {
                    Cube *pCube= dynamic_cast(pObject);
                    m_pVideoDriver->SetMaterial  ( greenMaterial );
                    m_pVideoDriver->SetTransform ( pCube->GetWorldMatrix() );
                    pCube->Render();
                }

                else if ( !strcmp(pObject->GetName(),"ESFERA") )
                {
                    Sphere *pSphere= dynamic_cast(pObject);
                    m_pVideoDriver->SetMaterial  ( yellowMaterial );
                    m_pVideoDriver->SetTransform ( pSphere->GetWorldMatrix() );
                    pSphere->Render( 24, 12 );
                }
                else if ( !strcmp(pObject->GetName(),"CILINDRO") )
                {
                    Cylinder *pCylinder= dynamic_cast(pObject);

                    m_pVideoDriver->SetMaterial  ( redMaterial );
                    m_pVideoDriver->SetTransform ( pCylinder->GetWorldMatrix() );
                    pCylinder->Render( 12, 6 );
                }
            }
        } // end for
    }

Podéis descargaros el ejemplo: tutorial-12.zip



Compartir en Facebook



Este artículo proviene de Programacion Grafica: Desarrollo 2D/3D con C++ y DirectX/OpenGL/GLUT/SDL - Windows/Linux
http://www.programaciongrafica.com

La dirección de esta noticia es:
http://www.programaciongrafica.com/modules.php?name=News&file=article&sid=13