OpenGL in Qt. Realization 3d or 2d model class. Help.
-
Hi everyone! Recently i've started work with Qt OpenGL.
After i've created my first triangle, rectangle, cube e.t.c.,
i decided to create separate class, which will be contain instances QGLBuffer: VBO, IBO, etc. Also this class should contain array vertex and index.
But i stumbled on the problem. My class does not work.My Class:
@
class Obj2d
{
public:
Obj2d(float x, float y,float vrt, unsigned int svrt, unsigned int ind, unsigned int sind);
private:
QGLBuffer vertexBuffer;
QGLBuffer indexBuffer;
bool prepareBufferObject(QGLBuffer buffer,
QGLBuffer::UsagePattern usagePattern,
const void data,
int dataSize);
unsigned int *indeces;
unsigned int svrt; //Size vertices
unsigned int sind;//indeces
float *verteces;
void bufferinit();
}Obj2d::bufferinit()
{
if(prepareBufferObject(&vertexBuffer, QGLBuffer::StaticDraw, verteces, svrt))
return;
if(prepareBufferObject(&indexBuffer, QGLBuffer::StaticDraw, indeces, sind))
return;
vertexBuffer.bind();
indexBuffer.bind();
}bool Obj2d::prepareBufferObject( QGLBuffer* buffer,
QGLBuffer::UsagePattern usagePattern,
const void* data,
int dataSize )
{
buffer->create();
buffer->setUsagePattern( usagePattern );
if ( !buffer->bind() )
{
qDebug() << "Could not bind buffer object to the context";
return false;
}
buffer->allocate( data, dataSize );
return true;
}@@
//In InitializeGL()
float points[] = {-300.5f, -300.5f, 0.0f, 1.0f,
-300.5f, 300.5f, 0.0f, 1.0f,
300.5f, 300.5f, 0.0f, 1.0f,
300.5f, -300.5f, 0.0f, 1.0f,1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f}; unsigned int indeces[] = {0 , 1, 2, 2, 3 ,0}; quad = new HObj2d(0.0f,0.0f, points, 8*4*sizeof(float), indeces, 3*2*sizeof(unsigned int)); quad->bufferinit();
@
@
//and PaintGL()
glDrawRangeElements(GL_TRIANGLES, 0,4,6, GL_UNSIGNED_INT, 0);//Program crashed
@Does anybody know, where is mistake in code?
How can i bind QGLBuffer in Obj2d with current QGLContext using Obj2d method?
I'll appreciate if you demostrate me your 3d or 2d model class realization. -
[quote author="ZapB" date="1349546958"]In your constructor make sure that you pass in QGLBuffer::IndexBuffer in the initializer list for the index buffer.[/quote]
Yes i did this in the initializer list.
@HObj2d::HObj2d(float x, float y, float *vrt, unsigned int svrt,unsigned int *ind, unsigned int sind):
vertexBuffer(QGLBuffer::VertexBuffer),
indexBuffer(QGLBuffer::IndexBuffer)@
Same result. -
OK. The other thing that typically causes crashes in glDraw* functions is reading beyond the end of the index or vertex buffers. I can't tell from your code snippet but make sure that you really have the vertex and index buffers bound that you think you have.
-
[quote author="ZapB" date="1349594930"]OK. The other thing that typically causes crashes in glDraw* functions is reading beyond the end of the index or vertex buffers. I can't tell from your code snippet but make sure that you really have the vertex and index buffers bound that you think you have.[/quote]
Thanks for reply.
Ok. Could you give example of code which demonstrate realization separate class for 3d or 2d model, please?
Also, i noticed that if I call the methods directly:
@
//InitializeGL
quad->prepareBufferObject(&(quad->vertexBuffer),QGLBuffer::StaticDraw,points, 48sizeof(float));
quad->prepareBufferObject(&(quad->indexBuffer),QGLBuffer::StaticDraw,indeces, 32sizeof(float));quad->vertexBuffer.bind();
quad->indexBuffer.bind();
@
Program works fine. -
Something like this works for me. This will not work out of the box though as it uses a couple of classes not in Qt (yet): Material and QOpenGLVertexArrayObject. You should be able to see the idea though :)
plane.h
@
#ifndef PLANE_H
#define PLANE_H#include <QObject>
#include "material.h"
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>class Plane : public QObject
{
Q_OBJECT
Q_PROPERTY( float width READ width WRITE setWidth )
Q_PROPERTY( float height READ height WRITE setHeight )
Q_PROPERTY( int xDivisions READ xDivisions WRITE setXDivisions )
Q_PROPERTY( int yDivisions READ yDivisions WRITE setYDivisions )public:
explicit Plane( QObject* parent = 0 );
Plane( float width, float height, int xDivisions, int yDivisions, QObject* parent = 0 );void setMaterial( const MaterialPtr& material ); MaterialPtr material() const; float width() const { return m_width; } float height() const { return m_height; } int xDivisions() const { return m_xDivisions; } int yDivisions() const { return m_yDivisions; } int indexCount() const { return 6 * m_xDivisions * m_yDivisions; }
public slots:
void setWidth(float width)
{
m_width = width;
}void setHeight(float height) { m_height = height; } void setXDivisions(int xDivisions) { m_xDivisions = xDivisions; } void setYDivisions(int yDivisions) { m_yDivisions = yDivisions; } void create(); void render();
private:
void generateVertexData( QVector<float>& vertices, QVector<float>& normals,
QVector<float>& texCoords, QVector<unsigned int>& indices );
void updateVertexArrayObject();float m_width; float m_height; int m_xDivisions; int m_yDivisions; MaterialPtr m_material; // QVertexBuffers to hold the data QOpenGLBuffer m_positionBuffer; QOpenGLBuffer m_normalBuffer; QOpenGLBuffer m_textureCoordBuffer; QOpenGLBuffer m_indexBuffer; QOpenGLVertexArrayObject m_vao;
};
#endif // PLANE_H
@ -
I had to split the post. Here's the implementation:
plane.cpp
@
#include "plane.h"#include <QVector>
Plane::Plane( QObject* parent )
: QObject( parent ),
m_width( 1.0f ),
m_height( 1.0f ),
m_xDivisions( 1 ),
m_yDivisions( 1 ),
m_positionBuffer( QOpenGLBuffer::VertexBuffer ),
m_normalBuffer( QOpenGLBuffer::VertexBuffer ),
m_textureCoordBuffer( QOpenGLBuffer::VertexBuffer ),
m_indexBuffer( QOpenGLBuffer::IndexBuffer ),
m_vao()
{
}Plane::Plane( float width, float height, int xDivisions, int yDivisions, QObject* parent )
: QObject( parent ),
m_width( width ),
m_height( height ),
m_xDivisions( xDivisions ),
m_yDivisions( yDivisions ),
m_positionBuffer( QOpenGLBuffer::VertexBuffer ),
m_normalBuffer( QOpenGLBuffer::VertexBuffer ),
m_textureCoordBuffer( QOpenGLBuffer::VertexBuffer ),
m_indexBuffer( QOpenGLBuffer::IndexBuffer ),
m_vao()
{
}void Plane::setMaterial( const MaterialPtr& material )
{
if ( material == m_material )
return;
m_material = material;
updateVertexArrayObject();
}MaterialPtr Plane::material() const
{
return m_material;
}void Plane::create()
{
// Allocate some storage to hold per-vertex data
QVector<float> v; // Vertices
QVector<float> n; // Normals
QVector<float> tex; // Tex coords
QVector<unsigned int> el; // Element indices// Generate the vertex data generateVertexData( v, n, tex, el ); // Create and populate the buffer objects m_positionBuffer.create(); m_positionBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); m_positionBuffer.bind(); m_positionBuffer.allocate( v.constData(), v.size() * sizeof( float ) ); m_normalBuffer.create(); m_normalBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); m_normalBuffer.bind(); m_normalBuffer.allocate( n.constData(), n.size() * sizeof( float ) ); m_textureCoordBuffer.create(); m_textureCoordBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); m_textureCoordBuffer.bind(); m_textureCoordBuffer.allocate( tex.constData(), tex.size() * sizeof( float ) ); m_indexBuffer.create(); m_indexBuffer.setUsagePattern( QOpenGLBuffer::StaticDraw ); m_indexBuffer.bind(); m_indexBuffer.allocate( el.constData(), el.size() * sizeof( unsigned int ) ); updateVertexArrayObject();
}
void Plane::generateVertexData( QVector<float>& vertices, QVector<float>& normals,
QVector<float>& texCoords, QVector<unsigned int>& indices )
{
vertices.resize( 3 * ( m_xDivisions + 1 ) * ( m_yDivisions + 1 ) );
normals.resize( 3 * ( m_xDivisions + 1 ) * ( m_yDivisions + 1 ) );
texCoords.resize( 2 * ( m_xDivisions + 1 ) * ( m_yDivisions + 1 ) );
indices.resize( 6 * m_xDivisions * m_yDivisions );float x2 = m_width / 2.0f; float y2 = m_height / 2.0f; float iFactor = static_cast<float>( m_height ) / static_cast<float>( m_yDivisions ); float jFactor = static_cast<float>( m_width ) / static_cast<float>( m_xDivisions ); float texi = 1.0f / m_yDivisions; float texj = 1.0f / m_xDivisions; int vertexIndex = 0; int textureCoordIndex = 0; for ( int i = 0; i <= m_yDivisions; ++i ) { float y = iFactor * i - y2; for ( int j = 0; j <= m_xDivisions; ++j ) { float x = jFactor * j - x2; vertices[vertexIndex] = x; vertices[vertexIndex+1] = 0.0f; vertices[vertexIndex+2] = y; normals[vertexIndex] = 0.0f; normals[vertexIndex+1] = 1.0f; normals[vertexIndex+2] = 0.0f; vertexIndex += 3; texCoords[textureCoordIndex] = j * texi; texCoords[textureCoordIndex+1] = i * texj; textureCoordIndex += 2; } } int index = 0; for ( int i = 0; i < m_yDivisions; ++i ) { unsigned int rowStart = i * ( m_xDivisions + 1 ); unsigned int nextRowStart = ( i + 1 ) * ( m_xDivisions + 1 ); for ( int j = 0; j < m_xDivisions; ++j ) { indices[index] = rowStart + j; indices[index+1] = nextRowStart + j; indices[index+2] = nextRowStart + j + 1; indices[index+3] = rowStart + j; indices[index+4] = nextRowStart + j + 1; indices[index+5] = rowStart + j + 1; index += 6; } }
}
void Plane::updateVertexArrayObject()
{
// Ensure that we have a valid material and geometry
if ( !m_material || !m_positionBuffer.isCreated() )
return;// Create a vertex array object if ( !m_vao.isCreated() ) m_vao.create(); m_vao.bind(); QOpenGLShaderProgramPtr shader = m_material->shader(); shader->bind(); m_positionBuffer.bind(); shader->enableAttributeArray( "vertexPosition" ); shader->setAttributeBuffer( "vertexPosition", GL_FLOAT, 0, 3 ); m_normalBuffer.bind(); shader->enableAttributeArray( "vertexNormal" ); shader->setAttributeBuffer( "vertexNormal", GL_FLOAT, 0, 3 ); m_textureCoordBuffer.bind(); shader->enableAttributeArray( "vertexTexCoord" ); shader->setAttributeBuffer( "vertexTexCoord", GL_FLOAT, 0, 2 ); m_indexBuffer.bind(); // End VAO setup m_vao.release();
}
void Plane::render()
{
// Bind the vertex array object to set up our vertex buffers and index buffer
m_vao.bind();// Draw it! glDrawElements( GL_TRIANGLES, indexCount(), GL_UNSIGNED_INT, 0 );
}
@