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 17 - Carga de Modelos 3DS (Malla) 
DirectX/Opengl

Después de tanto tiempo, veamos un ejemplo en el que visualizaremos algo más que cubos esferas o cilindros. En este caso se trata de carga de modelos en formato 3DS.



Podéis encontrar por Internet una descripción amplia del formato 3DS, pero básicamente es un fichero compuesto por bloques con un identificador y unos datos. A esta combinación se le denomina "Chunck". Por tanto el formato del fichero pasa a ser una serie de "Chunck''s" que a su vez, pueden contener otra serie de "Chunck''s" en cada bloque de datos.

Así que definiremos la geometría básica 3D en el fichero 3d_structures.h como sigue a continuación:


    ///////////////////////////////////////////////////////////////////////////////
    /// struct   Mesh: Almacena información sobre una geometría.
    ///
    /// rief   
    /// author  Antonio Lucas Moreno version 1.0 date 07/09/2007 12:33:11
    ///////////////////////////////////////////////////////////////////////////////
    struct Mesh
    {
        Vertex       *  pVertex;        ///< Lista de vértices.
        unsigned int    numVertex;      ///< Nº de vértices.
        unsigned int *  pIndexes;       ///< Lista de índices, en qué orden se renderizan los vértices.
        unsigned int    numIndexes;     ///< Nº de índices.
    };

Definiremos la clase C3DSLoader que será la encargada de leer el fichero 3DS y almacenar la información de la geometría (Mesh) definida anteriormente como una lista de Mesh''s. Vemos también la definición del CHUNK como una estructura formada por su identificador y el tamaño de los datos a leer. Según el identificador leído, el bloque de datos se leerá de una forma u otra.


        ///////////////////////////////////////////////////////////////////////////////
        /// struct  Chunck: Almacena información sobre un bloque de datos del fichero.
        ///
        /// rief   
        /// author  Antonio Lucas Moreno version 1.0 date 14/09/2007 10:21:18
        ///////////////////////////////////////////////////////////////////////////////
        struct Chunck
        {
            unsigned short  id;             ///< Identificador del bloque.
            unsigned int    lenght;         ///< Tamaño en bytes del bloque.
        }
        m_Chunck;

Según el identificador leído, el bloque de datos se leerá de una forma u otra.


    #define MAIN3DS                     0X4D4D
    #define EDIT3DS                     0X3D3D

    #define EDIT_MATERIAL               0xAFFF
        #define MAT_NAME                0xA000
        #define MAT_AMBIENT             0xA010
        #define MAT_DIFFUSE             0xA020
        #define MAT_SPECULAR            0xA030
        #define MAT_TEXMAP              0xA200
        #define MAT_MAPNAME             0xA300

    #define EDIT_OBJECT                 0x4000
        #define OBJ_TRIMESH             0x4100
            #define TRI_VERTEXL         0x4110
            #define TRI_FACEL1          0x4120
            #define TRI_MATERIAL        0x4130
            #define TRI_MAPPINGCOORS    0x4140
            #define TRI_LOCAL           0x4160
        #define OBJ_LIGHT               0x4600
        #define OBJ_CAMERA              0x4700

    #define KEYF3DS                     0xB000
        #define KEYFRAME_HEADER             0xB00A
        #define KEYFRAME_START_AND_END      0xB008
        #define KEYFRAME_MESH_INFO          0xB002
            #define KEYFRAME_OBJECT_NAME        0xB010 
            #define KEYFRAME_INSTANCE_NAME      0xB011
            #define PIVOT                       0xB013 
            #define POSITION_TRACK_TAG          0xB020 
            #define ROTATION_TRACK_TAG          0xB021 
            #define SCALE_TRACK_TAG             0xB022
            #define KEYFRAME_NODEID             0xB030


    // color chuncks
    #define COL_RGB                     0x0010
    #define COL_TRU                     0x0011
    #define COL_UNK                     0x0013

Cuando llegamos a leer el identificador OBJ_TRIMESH leemos la información sobre una geometría, puede haber muchas en el fichero, leyendo primero el número de vértices (cuando encontramos el identificador TRI_VERTEXL) y posteriormente (cuando encontramos el identificador TRI_FACEL1) leemos el orden en que se recorren los vértices.


    ///////////////////////////////////////////////////////////////////////////////
    ///     ReadMesh: Lee una geometría 3DS de un bloque de datos.
    ///
    ///     @param  unsigned int lenChunck: Tamaño en bytes del bloque de datos.
    ///     @param  Mesh *pMesh: Geometría creada.
    ///
    ///     @return  int: Tamaño del bytes del bloque.
    ///////////////////////////////////////////////////////////////////////////////
    int C3DSLoader::ReadMesh(unsigned int lenChunck, Mesh *pMesh)
    {
        int i,f;
        unsigned int bytesRead= 0;
        unsigned short numberElements;
        unsigned short faceFlags;
        unsigned short iVertex, numFaces;
        long beginChunckPos;

        beginChunckPos= ftell(m_pFile);

        do
        {
            ReadChunck();

            switch (m_Chunck.id)
            {
                case TRI_VERTEXL:

                    fread (&numberElements, sizeof (unsigned short), 1, m_pFile);

                    pMesh->numVertex= (unsigned int)numberElements;
                    pMesh->pVertex= new Vertex[pMesh->numVertex];

                    memset(pMesh->pVertex,0,pMesh->numVertex*sizeof(Vertex));

                    for (i=0; inumVertex; i++)
                    {
                        fread (&pMesh->pVertex[i].x, sizeof(float), 1, m_pFile);
                        fread (&pMesh->pVertex[i].z, sizeof(float), 1, m_pFile);
                        fread (&pMesh->pVertex[i].y, sizeof(float), 1, m_pFile);
                        pMesh->pVertex[i].z= -pMesh->pVertex[i].z;
                    }
                    break;

                case TRI_FACEL1:

                    fread (&numFaces, sizeof (unsigned short), 1, m_pFile);

                    pMesh->numIndexes= 3*numFaces;
                    pMesh->pIndexes= new unsigned int[pMesh->numIndexes];

                    memset(pMesh->pIndexes,0,pMesh->numIndexes*sizeof(unsigned int));

                    i= 0;

                    for (f=0; fsizeof (unsigned short), 1, m_pFile);
                        pMesh->pIndexes[i++]= iVertex;

                        fread (&iVertex, sizeof (unsigned short), 1, m_pFile);
                        pMesh->pIndexes[i++]= iVertex;

                        fread (&iVertex, sizeof (unsigned short), 1, m_pFile);
                        pMesh->pIndexes[i++]= iVertex;

                        fread (&faceFlags, sizeof (unsigned short), 1, m_pFile);
                    }
                    break;

                default:
                    SkipChunck();
                    break;
            }
        }
        while ((ftell(m_pFile) - beginChunckPos) < (lenChunck-SIZE_OF_CHUCK-1));

        return lenChunck;
    }

Para renderizar una geometría sólo hay que recorrer los vértices en el orden indicado por los índices.


    ///////////////////////////////////////////////////////////////////////////////
    ///     Render: Dibuja el modelo 3DS.
    ///
    ///     @param   nada
    ///
    ///     @return  nada
    ///////////////////////////////////////////////////////////////////////////////
    void C3DSLoader::Render()
    {
        MeshList::iterator itMesh;
        Mesh * pMesh= NULL;

        for (itMesh= m_MeshList.begin(); itMesh!=m_MeshList.end(); itMesh++)
        {
            pMesh= itMesh->second;
            if (pMesh)
            {
                IVideoDriver::GetVideoDriver()->RenderIndexedVertex( eTriangleList,
                                                                    (BYTE*)pMesh->pVertex, pMesh->numVertex,
                                                                    sizeof(Vertex), pMesh->pIndexes,
                                                                    0, pMesh->numIndexes,
                                                                    eFVF_XYZ|eFVF_NORMAL );
            }
        }
    }

Definimos también la clase C3DSModel como un objeto 3D representado por una geometría 3DS. Hacemos esto, como norma general de diseño, en la que separamos el objeto 3D de su representación. Esto es así, porque pueden existir diferentes objetos 3D con la misma representación.

La aplicación principal, finalmente crea un objeto de la clase C3DSLoader, carga el modelo y se lo asigna al objeto de la clase C3DSModel.


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

    #ifdef _MSC_VER
        sprintf( pathFile, "../../models/%s", MODEL_NAME );
    #else
        sprintf( pathFile, "../../../models/%s", MODEL_NAME );
    #endif
        sprintf( fileName, "%s.3ds", MODEL_NAME );

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

        ObjectList::iterator itObject= m_ObjectList.find( std::string(fileName) );

        // Si no se encuentra el modelo     
        if ( itObject == m_ObjectList.end() )
        {
            pModel= new C3DSModel( fileName );
            if ( pModel )
            {
                pModel->SetMesh( &m_3DSMesh );

                // **************************************************************************************************************************
                // 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(fileName) ]= static_cast( pModel );
            }
        }
    // ****************************************************************************
    }

Para renderiza el objeto, sólo hay que llamar al método Render() de la geometría del objeto que es la que sabe cómo debe renderizarse.


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

        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 );

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

    // ****************************************************************************
    }

Para más información sobre el formato: The Unofficial 3DStudio 3DS File Format V1.0 By Jeff Lewis

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



Nota: El modelo 747.3ds no lo he diseñado yo, no sirvo para diseñador 3D, lo que no recuerdo es la página donde lo descargué.

Compartir en Facebook
Enviado el Lunes, 05 noviembre a las 14:59:46 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: 4.33
votos: 3


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 17 - Carga de Modelos 3DS (Malla)" | Entrar / Crear Cuenta | 3 Comentarios | Buscar Discusión
Los comentarios son propiedad de quien los envió. No somos responsables por su contenido.

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

Re: Tutorial 17 - Carga de Modelos 3DS (Malla) (Puntuación 1)
por Ligator el Martes, 12 agosto a las 02:25:55
(Información del Usuario | Enviar un Mensaje)
Hola,

Me agrada lo que muestras en la página, pero desafortunadamente tengo problemas para descargar los zip de los ejemplos.



Ojalá pudieras hacer algo al respecto. De antemanomuchas gracias.



Re: Tutorial 17 - Carga de Modelos 3DS (Malla) (Puntuación 1)
por daalruag el Domingo, 15 noviembre a las 13:14:41
(Información del Usuario | Enviar un Mensaje)
hola espero qu porfavor me ayuden estoy mi rando el ejemplo y me salen dos problemas de que no encuentra dos archivos dos .h unos es el d3dx9.h y el otro es que noencuentra el directorio de directxvideodriver.sbr

porfa ayudenme que estoy re entusiasmado con el tema uy no me sale este pedazo graciasXD



Re: Tutorial 17 - Carga de Modelos 3DS (Malla) (Puntuación 1)
por administrador el Martes, 28 septiembre a las 06:44:07
(Información del Usuario | Enviar un Mensaje) http://www.programaciongrafica.com/
Hola, parece ser que Microsoft ha cambiado los ficheros en las últimas ediciones del SDK de DirectX 9.



Descargaros el tutorial último, el 23, que tiene actualizada la clase directxvideodriver.cpp.



Sustituid la línea del comienzo:



#include dxerr9.h



por



#if defined (_MSC_VER) && (_MSC_VER >= 1310)

#define DX_ERRORS

#include dxerr.h

#endif



cambiad las llamadas a DXGetErrorDescription9() por DXGetErrorDescription()



y en las opciones del Visual hay que enlazar con la librería dxerr.lib en lugar de dxerr9.lib.



A ver si tengo tiempo y actualizo hacia atrás TODOS los tutoriales con este cambio, pero de momento descargaros el tutorial 23 para que os sirva de ejemplo de cómo eliminar este error.



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

© Antonio Lucas Moreno