Я использую Assimp для загрузки файла .3ds и производный класс QGLWidget, чтобы нарисовать его с помощью PaintGL (). Он работает с небольшими файлами .3ds (несколько килобайт), но если я пытаюсь отобразить большие файлы (например, 1 МБ), приложение вылетает. Мой путь слишком плох и изогнут? Я делаю что-то неправильно?
С qDebug я понимаю, что paintGL () работает правильно. Проблема в методе ourRender, потому что, если я затемню
for (int t = 0; t < p->getFaces().count(); ++t)
и подробно
glVertex3f(f.getVerticesArray()[s].getX(),f.getVerticesArray();
цикл это все работает быстро (но, очевидно, ничего не нарисовано), кроме сетки и оси. С ним, и при загрузке некоторых сложных 3ds, он падает
мое оборудование
Phenom II X3 2.10ghz,4GB and 6650M (last drivers)
На Celeron 2.1 Ghz это вылетает
НО на i7 программа запускается но рендерит @ 2FPS (если я не использую метод «ourRender», он рендерится на 120fps на моем компьютере)
void GLWidget::paintGL()
{
qDebug << "Start PaintGL() #" << times;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(objCamera->mPos.x, objCamera->mPos.y, objCamera->mPos.z,
0, objCamera->mView.y, 0,
objCamera->mUp.x, objCamera->mUp.y, objCamera->mUp.z);
if (drawLines) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
else glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
draw_grid();
drawAxis();
ourRender(this->scenaa);
qDebug << "Close PaintGL() #" << times;
}
И это метод ourRender:
void GLWidget::ourRender(const Scene* sc){
QHash<QString, SceneObject*>& hash=sc->getObj();
double molt =1/20;
int counter =0;
for (QHash<QString,SceneObject*>::ConstIterator i = hash.begin();i!=hash.end();++i) {
aiMatrix4x4 minchia(1,0,0,molt*20,0,1,0,molt*20,0,0,1,molt*20,0,0,0,1);
aiTransposeMatrix4(&minchia);
glPushMatrix();
const Mesh* p = dynamic_cast<Mesh*>(i.value());
glMultMatrixf((float*) &minchia);
if(p){
for (int t = 0; t < p->getFaces().count(); ++t) {
Face f = p->getFaces()[t];
GLenum face_mode;
switch(f.getVerticesArray().count()) {
case 1: face_mode = GL_POINTS; break;
case 2: face_mode = GL_LINES; break;
case 3: face_mode = GL_TRIANGLES; break;
default: face_mode = GL_POLYGON; break;
}
glBegin(face_mode);
QList<Vector3D> lista = f.getVerticesArray();
for(int s = 0; s < lista.count(); s++) {
if (p->getNormals().count()>0)
--------->glVertex3f(f.getVerticesArray()[s].getX(),f.getVerticesArray()[s].getY(),f.getVerticesArray()[s].getZ());
}
glEnd();
}
}
glPopMatrix();
molt+=13;
counter++;
}
glPopMatrix();
}
…в производном конструкторе класса QGLWidget …
SceneImporter* aa = new AssimpAdapter();
Scene * nuovo=aa->importFile("C:/Users/nicola/Desktop/Source/aces.3ds");
scenaa=nuovo;
Мы решили проблему с изменением метода «ourender» (используя ссылки вместо копий)
void GLWidget::ourRender(Scene *&sc){
QHash<QString, SceneObject*>& hash=sc->getObj();
int counter =0;
for (QHash<QString,SceneObject*>::ConstIterator i = hash.begin();i!=hash.end();++i) {
aiMatrix4x4 m;
aiTransposeMatrix4(&m);
glPushMatrix();
const Mesh* p = dynamic_cast<Mesh*>(i.value());
glMultMatrixf((float*) &m);
if(p){
//apply_material(aaFuori.GetScene()->mMaterials[counter]);
QList<Face>& faccie=p->getFaces();
for (int t = 0; t < faccie.count(); ++t) {
Face f = faccie[t];
GLenum face_mode;
switch(f.getVerticesArray().count()) {
case 1: face_mode = GL_POINTS; break;
case 2: face_mode = GL_LINES; break;
case 3: face_mode = GL_TRIANGLES; break;
default: face_mode = GL_POLYGON; break;
}
glBegin(face_mode);
QList<Vector3D>& lista = f.getVerticesArray();
int conta=lista.count();
glVertex3f(lista[0].x,lista[0].y,lista[0].z);
glVertex3f(lista[1].x,lista[1].y,lista[1].z);
glVertex3f(lista[2].x,lista[2].y,lista[2].z);
glEnd();
}
}
glPopMatrix();
counter++;
}
Теперь мы можем отображать 8MBytes .3Ds @ 4fps во время поворота камеры (вместо сбоя приложения). Кто-нибудь из вас может дать нам мнение об этом результате — хорошо это или плохо?
Optimizazion. Дело в том, что для каждой вершины мы обращались к QList 3 раза. Теперь мы изменили его, и вместо Qlist мы используем массив Vector3D *, который сохраняет положение вершин и поэтому мы можем использовать метод GL glVertex3fv ((GLfloat *) массив [numface] .posvertex); Таким образом, учитывая указатель на лицо, это намного быстрее, чем раньше (от 4 до 10 кадров в секунду на той же сцене).
void GLWidget::ourRender(Scene *sc){
QHash<QString, SceneObject*>& hash=sc->getObj();
aiMatrix4x4 m;
for (QHash<QString,SceneObject*>::ConstIterator i = hash.begin();i!=hash.end();++i) {
aiTransposeMatrix4(&m);
glPushMatrix();
Mesh* p = dynamic_cast<Mesh*>(i.value());
glMultMatrixf((float*) &m);
if(p){
QList<Face>& faccie=p->getFaces();
int numerofacce=faccie.count();
for (int t = 0; t < numerofacce; ++t) {
Face& f = faccie[t];
GLenum face_mode;
Vector3D* lista=f.arrayVertici;
switch(f.getVerticesArray().count()) {
case 1:
face_mode = GL_POINTS;
glBegin(face_mode);
glVertex3fv((GLfloat*)lista[0].pos);
break;
case 2:
face_mode = GL_LINES;
glBegin(face_mode);
glVertex3fv((GLfloat*)lista[0].pos);
glVertex3fv((GLfloat*)lista[1].pos);
break;
case 3:
face_mode = GL_TRIANGLES;
glBegin(face_mode);
glVertex3fv(&lista[0].pos[0]);
glVertex3fv(&lista[1].pos[0]);
glVertex3fv(&lista[2].pos[0]);
break;
default: face_mode = GL_POLYGON; break;
}
glEnd();
}
}
glPopMatrix();
counter++;
}
glPopMatrix();
}
Где Vector3D инициализируется так:
Vector3D::Vector3D(double x, double y, double z) {
setX(x);
setY(y);
setZ(z);
pos[0]=x; //vertex1
pos[1]=y; //vertex2
pos[2]=z; //vertex3
}
PS: Grimmy предлагает мне использовать DisplayLists (обнаружен прямо сейчас). Завтра я попробую их.