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();
}
//---------------------------------------------------------------------------
Última edición por navbuoy fecha: 24-10-2024 a las 05:29:33.
|