Aprende a desarrollar aplicaciones gráficas 2D y 3D paso a paso.
Programacion Grafica: Desarrollo 2D/3D con C++ y DirectX/OpenGL/GLUT/SDL - Windows/Linux


  Crear una cuenta
 • Portada • Descargas • Tu Cuenta • 
Menú
 Portada
 Noticias
 Archivo de Noticias
 Temas
 Descargas
 Inicio
 Ver Nuevas
 Más Popular
 Más Votadas
 Contenido
 Contenido
 Secciones
 Enciclopedia
 Revisiones
 FAQ
 Tus Opciones
 Tu Cuenta
 Mensajes Privados
 Recomiéndenos
 Buscar
 Diarios
 Contacto
 Enlaces Web
 Inicio
 Enviar Enlace
 Ver Nuevos
 Más Popular
 Más Valorados
 Estadísticas
 Inicio
 Detalladas
 Top 10
 
Estadísticas
 
Tutorial 19 - Carga de Modelos 3DS (Textura) 
DirectX/Opengl

Tercera y última entrega sobre la carga de Modelos 3DS. En este caso añadiremos la carga de texturas.



Tenemos que añadir algunas modificaciones a la definición del vértice y el material para añadir la información para trabajar con texturas.


    ///////////////////////////////////////////////////////////////////////////////
    /// struct  Vertex: Estructura del vértice.
    ///
    /// rief   
    /// author  Antonio Lucas Moreno version 1.02 date 30/08/2005 9:24:19
    ///////////////////////////////////////////////////////////////////////////////
    struct Vertex
    {
        float           x, y, z;            ///< Coordenadas del vértice.
        float           nx, ny, nz;         ///< Normal del vértice.
    // ********************************* NEW **************************************
        float           su, tv;             ///< Coordenadas de textura.
    // ****************************************************************************
    };

/////////////////////////////////////////////////////////////////////////////// /// struct MATERIAL Estructura que define las propiedades del material. /// /// rief /// author Antonio Lucas Moreno version 1.0 date 28/09/2005 9:26:27 /////////////////////////////////////////////////////////////////////////////// struct Material { char name[256]; ///< Nombre del material. fColorRGBA ambient; ///< Color ambiente(RGBA). fColorRGBA diffuse; ///< Color difuso(RGBAA). fColorRGBA specular; ///< Color especular(RGBA). fColorRGBA emissive; ///< Color emisivo(RGBA). // ********************************* NEW ************************************** Texture texture; ///< Textura asociada al material. // **************************************************************************** };

En la clase C3DSLoader añadimos la ruta donde se almacena el modelo para poder cargar las texturas posteriormente.


    // ********************************* NEW **************************************
        char            m_PathName[256];            ///< Directorio donde se almacena el modelo.
    // ****************************************************************************

Ahora tenemos que leer más información sobre la geometría, en el método ReadMesh(). En este caso, las coordenadas de textura.


        // Coordenadas de textura
        case TRI_MAPPINGCOORS:

            fread (&numberElements, sizeof (unsigned short), 1, m_pFile);
            for (i=0; i// Las coordenadas de textura están almacenadas como en OpenGL:
                //
                //      t
                //      ^
                //      |
                //      +--> s
                fread (&pMesh->pVertex[i].su, sizeof (float), 1, m_pFile);
                fread (&pMesh->pVertex[i].tv, sizeof (float), 1, m_pFile);
            }
            break;

Cuando leamos el material, en le método ReadMaterial(), hay que crear la textura así como asignar el material (con su textura) a cada cara.


        // Nombre del fichero de textura.
        case MAT_MAPNAME:

            if ( ReadString(textureName,sizeof(textureName)) > 0 )
            {
                // Cargamos la textura
                sprintf( textureFileName,"%s/%s", m_PathName, textureName );
                ulColorRGBA colorKey;
                colorKey.rgba=0xffffffff;
                IVideoDriver::GetVideoDriver()->LoadTexture( textureFileName, pMaterial->texture, colorKey );
            }
            break;

El método para renderizar una geometría añade información para renderizar con texturas.


    ///////////////////////////////////////////////////////////////////////////////
    ///     Render: Dibuja el modelo 3DS.
    ///
    ///     @param   nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void C3DSLoader::Render()
    {
        MeshList::iterator itMesh;
        Mesh * pMesh= NULL;
        unsigned int i, f, startIndex, endIndex;
        Material * pLastMaterial= NULL;

        IVideoDriver *pVideoDriver= IVideoDriver::GetVideoDriver();
        if (!pVideoDriver)
            return;

        for (itMesh= m_MeshList.begin(); itMesh!=m_MeshList.end(); itMesh++)
        {
            pMesh= itMesh->second;
            if (pMesh)
            {
                // Renderizamos sus caras
                i            = 0;
                startIndex   = 0;
                endIndex     = 0;
                pLastMaterial= pMesh->pFaces[0].pMaterial;

                for ( f=0; fnumFaces; f++ )
                {
                    // Si cambia el material, renderizamos...
                    if ( pMesh->pFaces[f].pMaterial != pLastMaterial && endIndex > startIndex )
                    {
                        // Fijamos el material
                        pVideoDriver->SetMaterial( *pLastMaterial );

    // ********************************* NEW **************************************
                        pVideoDriver->SetTextureRenderStatus( eMinfilter, eLinearFilter );
                        pVideoDriver->SetTextureRenderStatus( eMagfilter, eLinearFilter );
                        pVideoDriver->SetTexture( pLastMaterial->texture );
    // ****************************************************************************

                        pVideoDriver->RenderIndexedVertex( eTriangleList,
                                                        (BYTE*)pMesh->pVertex, pMesh->numVertex,
                                                        sizeof(Vertex), pMesh->pIndexes,
                                                        startIndex, endIndex-startIndex,
                                                        eFVF_XYZ|eFVF_NORMAL|eFVF_TEX1/*NEW*/ );

                        startIndex   = endIndex;
                        pLastMaterial= pMesh->pFaces[f].pMaterial;
                    }

                    endIndex += 3;

                } // end for

                // Falta renderizar el último material
                if ( endIndex > startIndex )
                {
                    pVideoDriver->SetMaterial( *pLastMaterial );

    // ********************************* NEW **************************************
                    pVideoDriver->SetTextureRenderStatus( eMinfilter, eLinearFilter );
                    pVideoDriver->SetTextureRenderStatus( eMagfilter, eLinearFilter );
                    pVideoDriver->SetTexture( pLastMaterial->texture );
    // ****************************************************************************

                    pVideoDriver->RenderIndexedVertex( eTriangleList,
                                                    (BYTE*)pMesh->pVertex, pMesh->numVertex,
                                                    sizeof(Vertex), pMesh->pIndexes,
                                                    startIndex, endIndex-startIndex,
                                                    eFVF_XYZ|eFVF_NORMAL|eFVF_TEX1/*NEW*/ );
                }
            }
        }
    }

Se ha hecho un cambio importante en la clase GLApplication. La función de carga de texturas se ha definido en una nueva clase Tools como un método estático de forma que pueda ser llamada desde cualquier lugar del código sin necesidad de crear ningún objeto de la clase.

Definimos variables miembro para cada geometría que vamos a cargar.


    // ********************************* NEW **************************************
        C3DSLoader      m_3DSMeshFalcon;    ///< Geometría del modelo 3DS
        C3DSLoader      m_3DSMeshTie;       ///< Geometría del modelo 3DS
        C3DSLoader      m_3DSMeshDestructor;///< Geometría del modelo 3DS
    // ****************************************************************************

Estas geometrías, serán cargadas en el método CreateSceneObjects() y asociadas a cada objeto 3D creado. Es importante ver como se carga una sóla geometría de un caza Tie, pero se crean tantos cazas como queramos, pero la geometría es la misma.


    ///////////////////////////////////////////////////////////////////////////////
    ///     CreateSceneObjects: Crea los objetos que componen la escena 3D.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::CreateSceneObjects()
    {
        C3DSModel *pModel= NULL;
        char pathFile[256], fileName[256];

        // ---------------- *** Cargamos el Halcón Milenario *** ------------------
    #ifdef _MSC_VER
        sprintf( pathFile, "../../models/%s", "falcon" );
    #else
        sprintf( pathFile, "../../../models/%s", "falcon" );
    #endif
        sprintf( fileName, "%s.3ds", "falcon" );

        if ( m_3DSMeshFalcon.Load( pathFile, fileName ) == -1 )
            System::ShowMessage("Error al cargar el fichero: ",fileName,true);
        // ------------------------------------------------------------------------

        pModel= new C3DSModel( "FALCON" );
        if ( pModel )
        {
            pModel->SetMesh( &m_3DSMeshFalcon );

            // Los modelos de este tutorial están orientados hacia el eje Y positivo.
            // Lo orientamos hacia la Z positiva.
            pModel->Roll( 90.0f );  // Giro en Z
            pModel->Yaw ( 90.0f );  // Giro en Y
            pModel->SetPosition( Vector3(0,0,0) );

            // **************************************************************************************************************************
            // 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)
            // **************************************************************************************************************************
            m_ObjectList[ std::string( pModel->GetName() ) ]= static_cast( pModel );
        }

        // -------------------- *** Cargamos un caza Tie *** ----------------------
    #ifdef _MSC_VER
        sprintf( pathFile, "../../models/%s", "tie-fighter" );
    #else
        sprintf( pathFile, "../../../models/%s", "tie-fighter" );
    #endif
        sprintf( fileName, "%s.3ds", "tie-fighter" );

        if ( m_3DSMeshTie.Load( pathFile, fileName ) == -1 )
            System::ShowMessage("Error al cargar el fichero: ",fileName,true);
        // ------------------------------------------------------------------------

        pModel= new C3DSModel( "TIE-01" );
        if ( pModel )
        {
            pModel->SetMesh( &m_3DSMeshTie );

            // Los modelos de este tutorial están orientados hacia el eje Y positivo.
            // Lo orientamos hacia la Z positiva.
            pModel->Roll( 90.0f );  // Giro en Z
            pModel->Yaw ( 90.0f );  // Giro en Y
            pModel->SetPosition( Vector3(-20,0,-5) );

            m_ObjectList[ std::string( pModel->GetName() ) ]= static_cast( pModel );
        }

        // Fijémonos como creamos un nuevo objeto 3D que referencia a la misma geometría que el anterior.
        // La geometría sólo se carga y genera una vez.
        pModel= new C3DSModel( "TIE-02" );
        if ( pModel )
        {
            pModel->SetMesh( &m_3DSMeshTie );

            // Los modelos de este tutorial están orientados hacia el eje Y positivo.
            // Lo orientamos hacia la Z positiva.
            pModel->Roll( 90.0f );  // Giro en Z
            pModel->Yaw ( 90.0f );  // Giro en Y
            pModel->SetPosition( Vector3(20,0,-5) );

            m_ObjectList[ std::string( pModel->GetName() ) ]= static_cast( pModel );
        }

        // -------------- *** Cargamos el Destructor Imperial *** ----------------
    #ifdef _MSC_VER
        sprintf( pathFile, "../../models/%s", "destroyer" );
    #else
        sprintf( pathFile, "../../../models/%s", "destroyer" );
    #endif
        sprintf( fileName, "%s.3ds", "destroyer" );

        if ( m_3DSMeshDestructor.Load( pathFile, fileName ) == -1 )
            System::ShowMessage("Error al cargar el fichero: ",fileName,true);
        // ------------------------------------------------------------------------

        pModel= new C3DSModel( "DESTROYER" );
        if ( pModel )
        {
            pModel->SetMesh( &m_3DSMeshDestructor );

            // Los modelos de este tutorial están orientados hacia el eje Y positivo.
            // Lo orientamos hacia la Z positiva.
            pModel->Roll( 90.0f );  // Giro en Z
            pModel->Yaw ( 90.0f );  // Giro en Y
            pModel->SetPosition( Vector3(0,-100,-100) );

            m_ObjectList[ std::string( pModel->GetName() ) ]= static_cast( pModel );
        }

    }

El método en el que se renderizan los objetos, RenderSceneObjects(), cambia de forma que aplica las transformaciones realizadas sobre las naves, ya sea posición u orientación, simplemente transforma del espacio local al global


    ///////////////////////////////////////////////////////////////////////////////
    ///     RenderSceneObjects: Renderiza los objetos que componen la escena 3D.
    ///
    ///     @param  nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void GraphicApplication::RenderSceneObjects()
    {
        C3DSModel *pModel;
        C3DSLoader *pMesh;
        ObjectList::iterator itObj;
    // ********************************* NEW **************************************
        Matrix  transform;
        Matrix  worldTransform;
    // ****************************************************************************

        for ( itObj=m_ObjectList.begin(); itObj!=m_ObjectList.end(); ++itObj )
        {
            if ( itObj->second )
            {
                // *****************************************************************************************************************
                // 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)".
                // *****************************************************************************************************************
                pModel= dynamic_cast( itObj->second );

    // ********************************* NEW **************************************
                // Transformamos del espacio local al espacio global.
                transform.Translate( pModel->GetPosition() );
                worldTransform= pModel->GetLocalMatrix() * transform;
                m_pVideoDriver->SetTransform( worldTransform );
    // ****************************************************************************

                pMesh= pModel->GetMesh();
                if ( pMesh )
                    pMesh->Render();
            }
        } // end for
    }

Si en DirectX os aparecen unas líneas extrañas que van al infitino, comentad el defin __CONSOLE__ en el fichero win-main.cpp. Por alguna razón que desconozco hace eso si la aplicación está en modo consola.

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



Nota: Los modelos los obtuve algún día de la red. No os puedo decir dónde pues no me acuerdo.

Compartir en Facebook
Enviado el Miércoles, 07 noviembre a las 11:01:07 por administrador
 
Enlaces Relacionados
· Más Acerca de DirectX/Opengl
· Noticias de administrador


Noticia más leída sobre DirectX/Opengl:
Tutorial 16 - Movimiento-3D - (Tercera Persona)

 
Votos del Artículo
Puntuación Promedio: 5
votos: 1


Por favor tómate un segundo y vota por este artículo:
Excelente
Muy Bueno
Bueno
Regular
Malo

 
Opciones

 Versión Imprimible  Versión Imprimible

 
"Tutorial 19 - Carga de Modelos 3DS (Textura)" | Entrar / Crear Cuenta | 0 Comentarios
Los comentarios son propiedad de quien los envió. No somos responsables por su contenido.

No se permiten comentarios Anónimos, Regístrese por favor

Sitio potenciado por NukeProjects.Net        NukeStilo 1.0 se basa en PHP-Nuke        Theme Diseñado por NukeMods

© Antonio Lucas Moreno