Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Trucos (https://www.clubdelphi.com/foros/forumdisplay.php?f=52)
-   -   Inportador de modelos OBJ de Blender multi-texturas (https://www.clubdelphi.com/foros/showthread.php?t=96932)

navbuoy 24-10-2024 05:09:31

Inportador de modelos OBJ de Blender multi-texturas
 
El otro dia me puse durante la noche, que es cuando mejor programo, por aquello de que no hay muchos ruidos de la calle, coches etc
y hice este codigo en C++ Builder para importar modelos OBJ exportados desde Blender y otros programas el cual carga el modelo OBJ
y tambien la informacion referente a las texturas del archivo MTL asociado, funciona muy bien ya lo veréis si lo probais

de momento dejo en vuestras manos el tema de los includes necesarios (yo los tengo en la carpeta include de Rad Studio en Archivos de Programa (x86)

y recordad que tambien necesita el glew.c agregado al proyecto y los lib de glew32 etc
no esta del todo "saneado" el codigo ya que hay cosas ahi y funciones que estan pero no utilizo, espero que podais analizarlo bien pero asi como esta funciona
por ejemplo la funcion LoadBMPTexture ya no la utiliza sino que usa la de LoadPNGTexture y la de DrawModelWithTexture tampoco la uso sino que uso la de DrawModelWithMultipleTextures

Unit11.h
Código:

//---------------------------------------------------------------------------

#ifndef Unit11H
#define Unit11H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include "acPNG.hpp"
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm11 : public TForm
{
__published:        // IDE-managed Components
        TImage *Image1;
        TPanel *Panel1;
        void __fastcall FormDestroy(TObject *Sender);
private:        // User declarations
public:                // User declarations
        __fastcall TForm11(TComponent* Owner);
void __fastcall Timer1Timer(TObject *Sender);
void __fastcall InitScene();
void __fastcall DrawScene();
void __fastcall DrawScene_New();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm11 *Form11;
//---------------------------------------------------------------------------
#endif

Código:

//---------------------------------------------------------------------------

#include <vcl.h>
#include <Vcl.Imaging.pngimage.hpp>

#include <GL/glew.h>

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>


// Incluir GLFW
#include <GL/glfw3.h>

// Incluir GLM
#include <glm/glm.hpp>

using namespace glm;

#include <GL/glut.h>
#include <GL/gl.h>    // OpenGL
#include <GL/glu.h>  // Utilidades de OpenGL

#include <tiny_obj_loader.h>
#include <FreeImage.h> // Para cargar imágenes BMP o JPG

//Estos include puede que no sean del todo necesarios ya que los planeo usar para cuando texturice
#include <iostream>
#include <fstream> // Necesario para std::ifstream
#include <sstream>
#include <vector>  // Necesario para std::vector
#include <algorithm> // Necesario para std::swap
#include <string>

#pragma hdrstop

#include "Unit11.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "acPNG"
#pragma resource "*.dfm"
TForm11 *Form11;

void InitializeOpenGL(TPanel* Panel);
bool LoadOBJModel(const std::string& filename, const std::string& texturePath);
GLuint LoadBMPTexture(const char* filename);
GLuint LoadTexture(const char* filename);
void CloseOpenGL(void);

void LoadMTL(const std::string& path);
void DrawModelWithMaterials();
void DrawModelWithMultipleTextures();
void InitTextures();
GLuint LoadPNGTexture(const char* filename);

// Variables globales para el manejo del contexto de OpenGL
HDC hdc;
HGLRC hrc;
GLuint textureID, textureID1, textureID2, defaultTextureID;  //esto ya no es necesario, ahora maneja las texturas con InitTextures()
float rotationAngle = 0.0f;
bool inicio = true;
std::vector<GLuint> textureIDs;  // Vector para almacenar las IDs de las texturas

// Crear un objeto TPngImage para cargar la imagen PNG
        TPngImage *pngImage = new TPngImage();


// Variables globales para almacenar el modelo
        tinyobj::attrib_t attrib;
        std::vector<tinyobj::shape_t> shapes;
        std::vector<tinyobj::material_t> materials;
        std::string warn, err;

// Estructura para almacenar el modelo cargado
struct ModelData {
        std::vector<float> vertices;
        std::vector<float> normals;
        std::vector<float> texcoords;
        std::vector<unsigned int> indices;
};

ModelData model;

 // Estructura para almacenar vértices y coordenadas de textura
struct Vertex {
        float x, y, z;
};
struct TexCoord {
        float u, v;
};
std::vector<Vertex> vertices;
std::vector<TexCoord> texCoords;



//---------------------------------------------------------------------------
__fastcall TForm11::TForm11(TComponent* Owner)
        : TForm(Owner)
{
  InitializeOpenGL(Panel1);
  InitScene();

        TTimer *Timer1 = new TTimer(this);
        Timer1->Interval = 16;  // Aproximadamente 60 fps
        Timer1->OnTimer = Timer1Timer;
}
//---------------------------------------------------------------------------

void LoadOBJModel2(const std::string& path, const std::string& path_mtl) {
        bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, path.c_str(), path_mtl.c_str());
        if (!ret) {
                ShowMessage("Error al cargar modelo OBJ");
                return;
        }

                if (!warn.empty()) {
                ShowMessage("Error al cargar modelo OBJ:" + AnsiString(warn.c_str()));
                return;
        }

                if (!err.empty()) {
                ShowMessage("Error al cargar modelo OBJ" + AnsiString(err.c_str()));
                return;
        }
        // Procesar vértices y coordenadas de textura
        for (const auto& shape : shapes) {
                for (const auto& index : shape.mesh.indices) {
                        Vertex v = { attrib.vertices[3 * index.vertex_index + 0],
                                                attrib.vertices[3 * index.vertex_index + 1],
                                                attrib.vertices[3 * index.vertex_index + 2] };
                        vertices.push_back(v);
                        if (!attrib.texcoords.empty()) {
                                TexCoord tc = { attrib.texcoords[2 * index.texcoord_index + 0],
                                                                attrib.texcoords[2 * index.texcoord_index + 1] };
                                texCoords.push_back(tc);
                        }
                }
        }
}




void InitTextures() {
        // Reserva espacio para las texturas (tantas como materiales tenga el modelo)
    textureIDs.resize(materials.size());
    for (size_t i = 0; i < materials.size(); i++) {
        if (!materials[i].diffuse_texname.empty()) {
            // Cargar la textura BMP usando  función LoadPNGTexture
                        textureIDs[i] = LoadPNGTexture(materials[i].diffuse_texname.c_str());
                        //ShowMessage(materials[i].diffuse_texname.c_str());
            if (textureIDs[i] == 0) {
                                ShowMessage("Error loading texture: " + AnsiString(materials[i].diffuse_texname.c_str()));
                        }
                }
        }
}


GLuint LoadPNGTexture(const char* filename)
{
  GLuint texID = 0;

  // cargar la imagen PNG
  pngImage->LoadFromFile(filename);

  // Crear un array para los datos de la textura
                unsigned char* data = new unsigned char[pngImage->Width * pngImage->Height * 4]; // RGBA
        // Copiar los datos de la imagen a la textura
                for (int y = 0; y < pngImage->Height; y++) {
                        for (int x = 0; x < pngImage->Width; x++) {
                                // Asumimos que la imagen está en formato RGBA
              TColor color = pngImage->Pixels[x][pngImage->Height - 1 - y]; // Ajustar el orden de y para la coordenada Y
                                data[(y * pngImage->Width + x) * 4 + 0] = GetRValue(color);; // R
                                data[(y * pngImage->Width + x) * 4 + 1] = GetGValue(color);; // G
                                data[(y * pngImage->Width + x) * 4 + 2] = GetBValue(color);;  // B
                                data[(y * pngImage->Width + x) * 4 + 3] = (color >> 24) & 0xFF;  // A
            }
                }

// Generar y enlazar la textura
        glGenTextures(1, &texID);
        glBindTexture(GL_TEXTURE_2D, texID);
        // Establecer los parámetros de la textura
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // Cargar la textura en OpenGL
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pngImage->Width, pngImage->Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);

    delete[] data;
        return(texID);
}

GLuint LoadBMPTexture(const char* filename) {
        GLuint texID = 0;
        FILE* file = fopen(filename, "rb");
        if (!file) {
                ShowMessage("Error al abrir archivo de textura BMP");
                return(0);
        }
        unsigned char header[54];
        fread(header, sizeof(unsigned char), 54, file);
        int width = *(int*)&header[18];
        int height = *(int*)&header[22];
        int imageSize = *(int*)&header[34];
        unsigned char* data = new unsigned char[imageSize];
        fread(data, sizeof(unsigned char), imageSize, file);
        fclose(file);
// Generar y enlazar la textura
        glGenTextures(1, &texID);
        glBindTexture(GL_TEXTURE_2D, texID);
        // Establecer los parámetros de la textura
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        // Cargar la textura en OpenGL
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
        delete[] data;
        return(texID);
}

 void SetupMaterial() {
    // Configura el color ambiental del material
    GLfloat mat_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f }; // Color ambiental del material
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    // Configura el color difuso del material
    GLfloat mat_diffuse[] = { 0.8f, 0.2f, 0.2f, 1.0f }; // Color difuso del material (rojo)
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    // Configura el color especular del material
        GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Color especular del material
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    // Define el brillo del material
    GLfloat mat_shininess[] = { 50.0f }; // Aumentar el brillo del material
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
}

void SetupLighting() {
    glEnable(GL_LIGHTING); // Activa el sistema de iluminación
    glEnable(GL_LIGHT0);  // Activa la luz 0
    // Define la posición de la luz
    GLfloat light_position[] = { 0.0f, 10.0f, 5.0f, 1.0f }; // Posición de la luz en coordenadas homogéneas
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    // Define el color de la luz ambiental
    GLfloat ambient_light[] = { 0.2f, 0.2f, 0.2f, 1.0f }; // Color suave para la luz ambiental
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_light);
    // Define el color de la luz difusa
    GLfloat diffuse_light[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Luz blanca difusa
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse_light);
    // Define el color de la luz especular
    GLfloat specular_light[] = { 1.0f, 1.0f, 1.0f, 1.0f }; // Luz blanca especular
    glLightfv(GL_LIGHT0, GL_SPECULAR, specular_light);
}



void DrawModelWithMultipleTextures() {

glColor3f(1.0f, 1.0f, 1.0f);  // Establece el color a blanco (RGB)

        glEnable(GL_TEXTURE_2D);
        // Recorre todas las formas (shapes) del modelo
for (size_t s = 0; s < shapes.size(); s++) {
    // Obtén el ID del material para esta forma
    int material_id = shapes[s].mesh.material_ids[0];
    // Si el material tiene una textura, usa esa textura
    if (material_id >= 0 && material_id < materials.size()) {
        if (!materials[material_id].diffuse_texname.empty()) {
            glBindTexture(GL_TEXTURE_2D, textureIDs[material_id]);
        } else {
            // Si no hay textura, usa un color base o alguna otra textura por defecto
            glBindTexture(GL_TEXTURE_2D, defaultTextureID);
        }
    }
    // Dibuja los triángulos de esta forma
    glBegin(GL_TRIANGLES);
    for (size_t i = 0; i < shapes[s].mesh.indices.size(); i++) {
        tinyobj::index_t idx = shapes[s].mesh.indices[i];
        // Coordenadas de textura
        if (idx.texcoord_index >= 0) {
            glTexCoord2f(attrib.texcoords[2 * idx.texcoord_index], attrib.texcoords[2 * idx.texcoord_index + 1]);
        }
        // Vértices
        glVertex3f(attrib.vertices[3 * idx.vertex_index + 0],
                  attrib.vertices[3 * idx.vertex_index + 1],
                  attrib.vertices[3 * idx.vertex_index + 2]);
    }
    glEnd();
  }
}


void DrawModelWithTexture(GLuint textureID) {

        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, textureID);  // Usa la textura especificada
        glBegin(GL_TRIANGLES);
        for (size_t i = 0; i < vertices.size(); i++) {
                if (i < texCoords.size()) {
                        glTexCoord2f(texCoords[i].u, texCoords[i].v);
                }
                glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z);
        }
        glEnd();
        glDisable(GL_TEXTURE_2D);
}



void __fastcall TForm11::InitScene()
{
        // Cargar el modelo y la textura
        LoadOBJModel2(".\\gfx\\models\\casa.obj", ".\\gfx\\models");
       
        // Inicializar y cargar texturas
        InitTextures();

        glEnable(GL_DEPTH_TEST);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

}



void RenderScene() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
        // Configurar la cámara
        gluLookAt(0.0, 0.0, 5.0,  0.0, 0.0, 0.0,  0.0, 1.0, 0.0);
    DrawModelWithMultipleTextures();
    SwapBuffers(hdc);
}




void __fastcall TForm11::DrawScene_New()
{
// Limpiar con fondo transparente
// Establecer el color de fondo
    glClearColor(0.5f, 0.7f, 1.0f, 1.0f); // Cambia esto al color que desees
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Limpia los buffers
    glLoadIdentity();



        // Configurar la matriz de proyección
          glMatrixMode(GL_PROJECTION);
          glLoadIdentity();
          gluPerspective(45.0f, (double)Form11->Panel1->Width / (double)Form11->Panel1->Height, 0.1f, 100.0f); // Ajusta el campo de visión
          glMatrixMode(GL_MODELVIEW);



        //gluPerspective(45.0f, 800.0f / 600.0f, 1.0f, 100.0f);

        glLoadIdentity();
        gluLookAt(0.0, 0.0, 12.0,  // Cámara
                          0.0, 0.0, 0.0,    // Mirando al centro de la escena
                          0.0, 1.0, 0.0);  // Vector arriba
        // Aplicar rotación
        glRotatef(270.0f, 0.0f, 0.0f, 1.0f);
        glRotatef(30.0f, 0.0f, 1.0f, 0.0f);
                rotationAngle += 0.5f; // Incrementar ángulo para rotar continuamente
        glRotatef(rotationAngle, 1.0f, 0.0f, 0.0f);


                // Dibujar el modelo con la textura
                DrawModelWithMultipleTextures();


glDisable(GL_TEXTURE_2D); // Desactiva el texturizado

        //Form11->Label1->Caption = "Angulo de Rotacion: 270 Grados";
        //Form11->Label2->Caption = "TextureID: " + FloatToStr(textureID1);

        //ShowMessage("OK");
        //DrawModel_good(); // Llamar a la función que dibuja el modelo

        SwapBuffers(hdc); // Intercambia los buffers para mostrar la escena
        glFlush();
}



//---------------------------------------------------------------------------
void __fastcall TForm11::Timer1Timer(TObject *Sender)
{

        DrawScene_New();  // Dibuja el cubo cada vez que el temporizador se activa
}
//---------------------------------------------------------------------------
 void InitializeOpenGL(TPanel* Panel) {
        hdc = GetDC(Panel->Handle);
  // Crear un contexto de OpenGL temporal

        PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1 };
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 32;
        pfd.cDepthBits = 24;
        pfd.iLayerType = PFD_MAIN_PLANE;
        int pixelFormat = ChoosePixelFormat(hdc, &pfd);
        SetPixelFormat(hdc, pixelFormat, &pfd);
        HGLRC tempContext = wglCreateContext(hdc);
        wglMakeCurrent(hdc, tempContext);
        // Inicializar GLEW
        GLenum err = glewInit();
        if (err != GLEW_OK) {
                ShowMessage("Error al inicializar GLEW");
                return;
        }

        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(tempContext);
        HGLRC mainContext = wglCreateContext(hdc);
        wglMakeCurrent(hdc, mainContext);

    // Habilitar mezcla
          //glEnable(GL_BLEND);
        //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // En tu función de inicialización
//glEnable(GL_LIGHTING);  // Habilitar iluminación
//glEnable(GL_LIGHT0);    // Habilitar la luz 0

//SetupLighting();
//SetupMaterial();
}


void CloseOpenGL(void) {
        wglMakeCurrent(NULL, NULL);
        wglDeleteContext(hrc);
        ReleaseDC(NULL, hdc);
}

//---------------------------------------------------------------------------

void __fastcall TForm11::FormDestroy(TObject *Sender)
{
  CloseOpenGL();
}
//---------------------------------------------------------------------------


Neftali [Germán.Estévez] 24-10-2024 13:53:19

Gracias por el código.
^\||/^\||/^\||/


La franja horaria es GMT +2. Ahora son las 13:09:23.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi