PDA

Просмотр полной версии : QT+LIB3DS [QGLViewer]


lovepsone
08.05.2013, 17:16
Здравствуйте уважаемые пользователи!
Юзаю библиотеку QGLViewer для загрузки 3ds модели! Модель сама загружается, а текстура нет!
Вот мой код:

#ifndef _3DSVIEWER_H
#define _3DSVIEWER_H

#include <QtGui>
#include "lib3ds\file.h"
#include "lib3ds\node.h"
#include "QGLViewer\QGLViewer.h"

#define CountTexture 1

class Viewer : public QGLViewer
{
Q_OBJECT

public:
Viewer();

protected :
virtual void draw();
virtual void animate();
virtual void init();
virtual void keyPressEvent(QKeyEvent *e);
virtual QString helpString() const;

void renderNode(Lib3dsNode *node);
void initScene();
void loadFile();
QImage loadBMP(QString NameBMP);
void setTexture();

private :
Lib3dsFile *file;
float current_frame;
char* camera_name;
GLuint Texture;//[CountTexture];
// Texture parameters
float ratio, u_max, v_max;
float scale_x, scale_y; // scale the texcoords, as OpenGL thinks in TEX_XSIZE and TEX_YSIZE

};

#endif // _3DSVIEWER_H



#include "3dsViewer.h"

#include "lib3ds\camera.h"
#include "lib3ds\mesh.h"
#include "lib3ds\material.h"
#include "lib3ds\matrix.h"
#include "lib3ds\vector.h"
#include "lib3ds\light.h"
#include <string.h>
#include <math.h>
#include <qfiledialog.h>

using namespace std;
using namespace qglviewer;

#define TEX_XSIZE 1024
#define TEX_YSIZE 1024

Viewer::Viewer() : file(NULL), current_frame(0.0), camera_name(NULL)
{
}

void Viewer::keyPressEvent(QKeyEvent *e)
{
switch (e->key())
{
case Qt::Key_L : loadFile(); break;
default: QGLViewer::keyPressEvent(e);
}
}

QString Viewer::helpString() const
{
QString text("<h2>3 d s V i e w e r</h2>");
text += "This example uses the lib3ds library to load a 3ds object file.<br><br>";
text += "Press <b>L</b>(oad) to open a 3ds file.<br><br>";
text += "Note that certain 3ds files contain animated sequences that can ";
text += "be played using the <b>Return</b> (animate) key.";
return text;
}

void Viewer::loadFile()
{
/*#if QT_VERSION < 0x040000
QString name = QFileDialog::getOpenFileName(".", "3DS files (*.3ds *.3DS);;All files (*)", this, "Choose", "Select a 3ds model");
#else
QString name = QFileDialog::getOpenFileName(this, "Select a 3ds model", ".", "3DS files (*.3ds *.3DS);;All files (*)");
#endif*/

QString name("blyak.3DS");
// In case of Cancel
if (name.isEmpty())
return;

#if QT_VERSION < 0x040000
file = lib3ds_file_load(name.latin1());
#else
file = lib3ds_file_load(name.toLatin1().constData());
#endif
if (!file)
{
qWarning("Error : Unable to open file ");
exit(1);
}

if (file->cameras)
camera_name = file->cameras->name;
else
camera_name = NULL;

lib3ds_file_eval(file,0);

initScene();

float min[3], max[3];
lib3ds_file_bounding_box(file, min, max);
setSceneBoundingBox(Vec(min), Vec(max));

if (!file->cameras)
camera()->showEntireScene();
else
updateGL();
stopAnimation();
}

QImage Viewer::loadBMP(QString NameBMP)
{
QImage img(NameBMP);

if (img.isNull())
{
qWarning("Unable to load file[bmp]");
return img;
}

QMatrix matr;
matr = matr.rotate(90);
QTransform trans(matr);
img.transformed(trans);
//img.
// 1E-3 needed. Just try with width=128 and see !
/*int newWidth = 1<<(int)(1+log(img.width() -1+1E-3) / log(2.0));
int newHeight = 1<<(int)(1+log(img.height()-1+1E-3) / log(2.0));

u_max = img.width() / (float)newWidth;
v_max = img.height() / (float)newHeight;

if ((img.width()!=newWidth) || (img.height()!=newHeight))
{
qWarning("Image size set to %dx%d pixels", newWidth, newHeight);
img = img.copy(0, 0, newWidth, newHeight);
}

ratio = newWidth / float(newHeight);*/

return QGLWidget::convertToGLFormat(img); // flipped 32bit RGBA
}

void Viewer::setTexture()
{
QImage glImg = loadBMP("blyak.bmp");

if(glImg.isNull())
return;

Texture = bindTexture(glImg, GL_TEXTURE_2D);
//glBindTexture(GL_TEXTURE_2D, Texture);
glTexImage2D(GL_TEXTURE_2D, 0, 4, glImg.width(), glImg.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, glImg.bits());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTE R,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTE R,GL_LINEAR);
scale_x = (float)glImg.width()/(float)TEX_XSIZE;
scale_y = (float)glImg.height()/(float)TEX_YSIZE;
}

void Viewer::init()
{
// Texture parameters
u_max = 1.0;
v_max = 1.0;
ratio = 1.0;

glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDisable(GL_LIGHT1);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
//glEnable(GL_TEXTURE_2D);

// Enable GL textures
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glEnable(GL_TEXTURE_2D);

// Nice texture coordinate interpolation
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );

setKeyDescription(Qt::Key_L, "Loads a new 3ds file");

restoreStateFromFile();
//help();
setTexture();
loadFile();
}

void Viewer::initScene()
{
if (!file)
return;

// Lights
GLfloat amb[] = {0.0, 0.0, 0.0, 1.0};
GLfloat dif[] = {1.0, 1.0, 1.0, 1.0};
GLfloat spe[] = {1.0, 1.0, 1.0, 1.0};
GLfloat pos[] = {0.0, 0.0, 0.0, 1.0};
int li=GL_LIGHT0;
for (Lib3dsLight* l=file->lights; l; l=l->next)
{
glEnable(li);

glLightfv(li, GL_AMBIENT, amb);
glLightfv(li, GL_DIFFUSE, dif);
glLightfv(li, GL_SPECULAR, spe);

pos[0] = l->position[0];
pos[1] = l->position[1];
pos[2] = l->position[2];
glLightfv(li, GL_POSITION, pos);

if (!l->spot_light)
continue;

pos[0] = l->spot[0] - l->position[0];
pos[1] = l->spot[1] - l->position[1];
pos[2] = l->spot[2] - l->position[2];
glLightfv(li, GL_SPOT_DIRECTION, pos);
++li;
}

// Camera
Lib3dsNode* c = lib3ds_file_node_by_name(file, camera_name, LIB3DS_CAMERA_NODE);
Lib3dsNode* t = lib3ds_file_node_by_name(file, camera_name, LIB3DS_TARGET_NODE);
if (!c || !t)
return;

Lib3dsMatrix M;
lib3ds_matrix_camera(M, c->data.camera.pos, t->data.target.pos, c->data.camera.roll);

// cout << "Pos = " << Vec(c->data.camera.pos) << endl;
// cout << "Tar = " << Vec(t->data.target.pos) << endl;
// cout << "Rol = " << c->data.camera.roll << endl;

camera()->setPosition(Vec(c->data.camera.pos));
camera()->lookAt(Vec(t->data.target.pos));
Vec up=camera()->frame()->transformOf(Vec(0.0, 0.0, 1.0));
float angle=atan2(up.x, up.y);
Quaternion q(Vec(0.0, 0.0, 1.0), c->data.camera.roll-angle);
camera()->frame()->rotate(q);
camera()->setFieldOfView(M_PI/180.0*c->data.camera.fov);
glRotatef(-90, 1.0,0,0);
}

void Viewer::renderNode(Lib3dsNode *node)
{
for (Lib3dsNode* p=node->childs; p!=0; p=p->next)
renderNode(p);

if (node->type == LIB3DS_OBJECT_NODE)
{
if (strcmp(node->name,"$$$DUMMY")==0)
return;

if (!node->user.d)
{
Lib3dsMesh *mesh=lib3ds_file_mesh_by_name(file, node->name);
if (!mesh)
return;

node->user.d = glGenLists(1);
glNewList(node->user.d, GL_COMPILE);

Lib3dsVector *normalL = new Lib3dsVector[3*mesh->faces];

Lib3dsMatrix M;
lib3ds_matrix_copy(M, mesh->matrix);
lib3ds_matrix_inv(M);
glMultMatrixf(&M[0][0]);

lib3ds_mesh_calculate_normals(mesh, normalL);

for (unsigned int p=0; p<mesh->faces; ++p)
{
Lib3dsFace *f=&mesh->faceL[p];
Lib3dsMaterial *mat=0;
if (f->material[0])
mat=lib3ds_file_material_by_name(file, f->material);

if (mat)
{
static GLfloat a[4]={0,0,0,1};
float s;
glMaterialfv(GL_FRONT, GL_AMBIENT, a);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular);
s = pow(2, 10.0*mat->shininess);
if (s>128.0)
s=128.0;
glMaterialf(GL_FRONT, GL_SHININESS, s);
}
else
{
Lib3dsRgba a={0.2, 0.2, 0.2, 1.0};
Lib3dsRgba d={0.8, 0.8, 0.8, 1.0};
Lib3dsRgba s={0.0, 0.0, 0.0, 1.0};
glMaterialfv(GL_FRONT, GL_AMBIENT, a);
glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
glMaterialfv(GL_FRONT, GL_SPECULAR, s);
}

glBindTexture(GL_TEXTURE_2D, Texture);
glBegin(GL_TRIANGLES);
glNormal3fv(f->normal);
for (int i=0; i<3; ++i)
{
glNormal3fv(normalL[3*p+i]);

glTexCoord2f(mesh->texelL[f->points[i]][1]*scale_x, scale_y - mesh->texelL[f->points[i]][0]*scale_y);
//glTexCoord2f(mesh->texelL[f->points[i]][1], mesh->texelL[f->points[i]][0]);
glVertex3fv(mesh->pointL[f->points[i]].pos);
}
glEnd();
}

delete[] normalL;

glEndList();
}

if (node->user.d)
{
glPushMatrix();
Lib3dsObjectData* d = &node->data.object;
glMultMatrixf(&node->matrix[0][0]);
glTranslatef(-d->pivot[0], -d->pivot[1], -d->pivot[2]);
glCallList(node->user.d);
glPopMatrix();
}
}
}

void Viewer::draw()
{
if (!file)
return;

glBindTexture(GL_TEXTURE_2D, Texture);
/*glNormal3f(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 1.0-v_max);
//glVertex2f(-u_max*ratio,-v_max);
glTexCoord2f(0.0, 1.0);
//glVertex2f(-u_max*ratio, v_max);
glTexCoord2f(u_max, 1.0);
//glVertex2f( u_max*ratio, v_max);
glTexCoord2f(u_max, 1.0-v_max);
//glVertex2f( u_max*ratio,-v_max);
glEnd();*/

for (Lib3dsNode* p=file->nodes; p!=0; p=p->next)
renderNode(p);
}


void Viewer::animate()
{
current_frame++;
if (current_frame > file->frames)
current_frame=0;
lib3ds_file_eval(file, current_frame);
initScene();
}


Opengl пока разбираю и опыта нет. Мб кто поможет?

Sid
09.05.2013, 14:32
Чувак, я твой фанат теперь :D Я давно эту идею вынашиваю, написать собственый модельвивер на qt :)

lovepsone
09.05.2013, 18:03
Чувак, я твой фанат теперь :D Я давно эту идею вынашиваю, написать собственый модельвивер на qt :)

Да вот пока с Opengl изучаю + в Qt интегрирую! Вот тока пока проблем выше крыши!

Evgeniy
10.05.2013, 10:21
glBindTexture после glGenLists...не?
Даже не после а внутри блока....и тестурку выбрать клетчатую салатовую, что бы наверняка знать грузится-нет.

lovepsone
11.05.2013, 17:40
Обновил первый пост!Вроде теперь текстура загружается, но моделька отображается черным цветом!
Смотрите скрин ниже в первом посте!

Я даже нарисовал куб и попытался наложить текстуру, но нечего не вышло! Значит я чего-то не знаю... Буду думать.

Sid
11.05.2013, 20:00
Альфа канал указал верно? Я помню когда делал для m2 то текстура blp в RGBA не отображалась, потом выставил альфа на максимум и все появилось :) Долго ломал тогда голову )

lovepsone
15.05.2013, 21:59
Текстуру удалось наложить, но есть некоторые проблемы!
Я поворачиваю камеру на 90 градусов( Что бы модель стояла правильно по координатам х,у.z, т.е стояла ровно)! При таком раскладе я налаживаю текстуру и... Текстура ложится прямо а не по вершинам указанных в 3ds файле! Далее пришлось посчитать вершины текстуры, в итоге по коду вышло так:

glBindTexture(GL_TEXTURE_2D, Texture);
glBegin(GL_TRIANGLES);
glNormal3fv(f->normal);
for (int i=0; i<3; ++i)
{
glNormal3fv(normalL[3*p+i]);

glTexCoord2f(mesh->texelL[f->points[i]][1]*scale_x, scale_y - mesh->texelL[f->points[i]][0]*scale_y);
glVertex3fv(mesh->pointL[f->points[i]].pos);
}
glEnd();

И что вы думаете? Не получилось... Далее я полез в фотошоп и повернул текстуру на 90 градусов по часовой... Все ок! Текстура легла как надо!!!
Меня это не устроило и попробовал поворачивать текстуру перед наложением на модель(в самом коде). Сделал так:

QImage Viewer::loadBMP(QString NameBMP)
{
QImage img(NameBMP);

if (img.isNull())
{
qWarning("Unable to load file[bmp]");
return img;
}

QMatrix matr;
matr = matr.rotate(90);
QTransform trans(matr);
img.transformed(trans); // переменная img типа QImage, в которой помещена текстура формата .bmp

return QGLWidget::convertToGLFormat(img); // flipped 32bit RGBA

}


Но текстура так и не повернулась... Код в первом посте обновлен!

Evgeniy
15.05.2013, 22:55
glPushMatrix();
glTranslatef
glRotatef
Draw()
glPopMatrix();
Всегда вращай и двигай объект, а не камеру ...тогда не надо пересчитывать все координаты (всмысле тектурные, нормали и т.п.)...

lovepsone
16.05.2013, 13:21
Завтра буду дома, постараюсь доделать! Код вполне рабочий, но нужно оптимизировать... Всем спасибо!