Introduction-to-Qt3D: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
[toc align_right=&quot;yes&amp;quot; depth=&quot;3&amp;quot;]<br />[[Category:Developing_with_Qt::Qt3D]]
[toc align_right="yes" depth="3"]
[[Category:Developing_with_Qt::Qt3D]]


= Introduction to Qt 3D =
= Introduction to Qt 3D =
Line 17: Line 18:
A simple '''OpenGL''' program with just a ''3D cube and some lighting'' could be as long as '''140 lines''' of code when developed with '''GLUT'''.
A simple '''OpenGL''' program with just a ''3D cube and some lighting'' could be as long as '''140 lines''' of code when developed with '''GLUT'''.


[[Image:https://gitorious.org/wiki-sources/wiki-sources/blobs/raw/284e0d0b70f0d4d786b16156f0ae0dba1d926e3e/images/3d-cube-screenshot.png|3D Hello World Cube]]<br />''3D cube drawn using OpenGL.''
[[Image:https://gitorious.org/wiki-sources/wiki-sources/blobs/raw/284e0d0b70f0d4d786b16156f0ae0dba1d926e3e/images/3d-cube-screenshot.png|3D Hello World Cube]]
''3D cube drawn using OpenGL.''


<code>…
<code>…


void initialize()<br />{<br /> float ambientLight[] = { 0.2, 0.2, 0.2, 1.0 };<br /> float specularLight[] = { 1.0, 1.0, 1.0, 1.0 };<br /> float specularity[] = { 1.0, 1.0, 1.0, 1.0 };<br /> float shininess[] = { 60.0 };<br /> float lightPosition[] = { 0.0, 50.0, 50.0, 1.0 };
void initialize()
{
float ambientLight[] = { 0.2, 0.2, 0.2, 1.0 };
float specularLight[] = { 1.0, 1.0, 1.0, 1.0 };
float specularity[] = { 1.0, 1.0, 1.0, 1.0 };
float shininess[] = { 60.0 };
float lightPosition[] = { 0.0, 50.0, 50.0, 1.0 };




// Enable lighting with one light source<br /> glEnable(GL_LIGHTING);<br /> glEnable(GL_LIGHT0);
// Enable lighting with one light source
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);




// Properties of the objects' materials<br /> glMaterialfv(GL_FRONT, GL_SPECULAR, specularity); // Reflectance<br /> glMaterialfv(GL_FRONT, GL_SHININESS, shininess); // Shininess
// Properties of the objects' materials
glMaterialfv(GL_FRONT, GL_SPECULAR, specularity); // Reflectance
glMaterialfv(GL_FRONT, GL_SHININESS, shininess); // Shininess


// Enable ambient light usage<br /> glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
// Enable ambient light usage
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);


glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);<br /> glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);


// Position of the light source<br /> glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);<br />}
// Position of the light source
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
}




void resize(int width, int height)<br />{<br />
void resize(int width, int height)
{


// Set the viewport to be the entire window<br /> glViewport(0, 0, width, height);
// Set the viewport to be the entire window
glViewport(0, 0, width, height);




// Defines the perspective projection<br /> glLoadIdentity();<br /> gluPerspective(45, aspectRatio, 1, 500);
// Defines the perspective projection
glLoadIdentity();
gluPerspective(45, aspectRatio, 1, 500);




// Defines the position of the camera and the target<br /> glLoadIdentity();<br /> gluLookAt(0, 80, 200, 0, 0, 0, 0, 1, 0);<br />}
// Defines the position of the camera and the target
glLoadIdentity();
gluLookAt(0, 80, 200, 0, 0, 0, 0, 1, 0);
}


void paint()<br />{<br /> glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
void paint()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


// Vertices<br /> static const float vertices[6][4][3] = {<br /> { { 1.0, –1.0, 1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, 1.0, –1.0 }, { 1.0, 1.0, 1.0 } },<br /> { { –1.0, –1.0, –1.0 }, { –1.0, –1.0, 1.0 }, { –1.0, 1.0, 1.0 }, { –1.0, 1.0, –1.0 } },<br /> { { 1.0, –1.0, –1.0 }, { –1.0, –1.0, –1.0 }, { –1.0, 1.0, –1.0 }, { 1.0, 1.0, –1.0 } },<br /> { { –1.0, –1.0, 1.0 }, { 1.0, –1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { –1.0, 1.0, 1.0 } },<br /> { { –1.0, –1.0, –1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, –1.0, 1.0 }, { –1.0, –1.0, 1.0 } },<br /> { { –1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, –1.0 }, { –1.0, 1.0, –1.0 } }<br /> };
// Vertices
static const float vertices[6][4][3] = {
{ { 1.0, –1.0, 1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, 1.0, –1.0 }, { 1.0, 1.0, 1.0 } },
{ { –1.0, –1.0, –1.0 }, { –1.0, –1.0, 1.0 }, { –1.0, 1.0, 1.0 }, { –1.0, 1.0, –1.0 } },
{ { 1.0, –1.0, –1.0 }, { –1.0, –1.0, –1.0 }, { –1.0, 1.0, –1.0 }, { 1.0, 1.0, –1.0 } },
{ { –1.0, –1.0, 1.0 }, { 1.0, –1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { –1.0, 1.0, 1.0 } },
{ { –1.0, –1.0, –1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, –1.0, 1.0 }, { –1.0, –1.0, 1.0 } },
{ { –1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, –1.0 }, { –1.0, 1.0, –1.0 } }
};




for (int i = 0; i &lt; 6; +''i) {<br /> glBegin(GL_QUADS);<br /> glNormal3fv(normals[i]);<br /> for (int j = 0; j &lt; 4;''+j)<br /> glVertex3fv(vertices[i][j]);<br /> glEnd();<br /> }
for (int i = 0; i < 6; +''i) {
glBegin(GL_QUADS);
glNormal3fv(normals[i]);
for (int j = 0; j < 4;''+j)
glVertex3fv(vertices[i][j]);
glEnd();
}


glutSwapBuffers();<br />}
glutSwapBuffers();
}


int main(int argc, char **argv)<br />{<br />
int main(int argc, char **argv)
{


initialize();
initialize();


// Register the drawing function &quot;paint()&quot;<br /> glutDisplayFunc(paint);
// Register the drawing function "paint()"
glutDisplayFunc(paint);


// Register the resizing function &quot;resize()&quot;<br /> glutReshapeFunc(resize);
// Register the resizing function "resize()"
glutReshapeFunc(resize);


<br />}</code> ''Drawing a 3D cube with GLUT.'' &quot;source code&amp;quot;:https://gitorious.org/wiki-sources/wiki-sources/trees/master/opengl
}</code> ''Drawing a 3D cube with GLUT.'' "source code":https://gitorious.org/wiki-sources/wiki-sources/trees/master/opengl


The code above follows a very basic '''OpenGL''' program structure. It has a '''''initialize''''' function (for doing some initial setup), a '''''resize''''' function (to handle window resizes) and a '''''paint''''' function (to draw the actual 3D objects).
The code above follows a very basic '''OpenGL''' program structure. It has a '''''initialize''''' function (for doing some initial setup), a '''''resize''''' function (to handle window resizes) and a '''''paint''''' function (to draw the actual 3D objects).
Line 75: Line 121:
== '''Qt OpenGL''' ==
== '''Qt OpenGL''' ==


'''Qt OpenGL''' is a port of the '''OpenGL''' API to the '''Qt''' toolkit. It does a fairly good job at translating all of '''OpenGL''' basic functions<br />to a '''Qt''' widget. Now, instead of several functions being registered for callbacks, it is possible to take advantage of the SIGNAL/SLOT system of '''Qt'''.
'''Qt OpenGL''' is a port of the '''OpenGL''' API to the '''Qt''' toolkit. It does a fairly good job at translating all of '''OpenGL''' basic functions
to a '''Qt''' widget. Now, instead of several functions being registered for callbacks, it is possible to take advantage of the SIGNAL/SLOT system of '''Qt'''.


One of the most commonly used approches for '''Qt OpenGL''' to write a 3D program is to subclass '''QGLWidget'''. '''QGLWidget''' provides three convenience methods that you can reimplement to perform the typical OpenGL tasks: '''paintGL''', '''resizeGL''' and '''initializeGL''' (similar to the '''GLUT''' version of the program).
One of the most commonly used approches for '''Qt OpenGL''' to write a 3D program is to subclass '''QGLWidget'''. '''QGLWidget''' provides three convenience methods that you can reimplement to perform the typical OpenGL tasks: '''paintGL''', '''resizeGL''' and '''initializeGL''' (similar to the '''GLUT''' version of the program).
Line 83: Line 130:
<code>…
<code>…


class GLWidget : public QGLWidget<br />{<br /> Q_OBJECT
class GLWidget : public QGLWidget
{
Q_OBJECT


public:<br /> GLWidget(QWidget *parent = 0);
public:
GLWidget(QWidget *parent = 0);


protected:<br /> void initializeGL();<br /> void resizeGL(int width, int height);<br /> void paintGL();<br />};
protected:
void initializeGL();
void resizeGL(int width, int height);
void paintGL();
};


GLWidget::GLWidget(QWidget *parent)<br /> : QGLWidget(parent)<br />{<br /> setFormat(QGLFormat(QGL::Rgba | QGL::DoubleBuffer | QGL::DepthBuffer));<br />}
GLWidget::GLWidget(QWidget *parent)
: QGLWidget(parent)
{
setFormat(QGLFormat(QGL::Rgba | QGL::DoubleBuffer | QGL::DepthBuffer));
}


void GLWidget::initializeGL()<br />{<br /> float ambientLight[] = { 0.2, 0.2, 0.2, 1.0 };<br /> float specularLight[] = { 1.0, 1.0, 1.0, 1.0 };<br /> float specularity[] = { 1.0, 1.0, 1.0, 1.0 };<br /> float shininess[] = { 60.0 };<br /> float lightPosition[] = { 0.0, 50.0, 50.0, 1.0 };
void GLWidget::initializeGL()
{
float ambientLight[] = { 0.2, 0.2, 0.2, 1.0 };
float specularLight[] = { 1.0, 1.0, 1.0, 1.0 };
float specularity[] = { 1.0, 1.0, 1.0, 1.0 };
float shininess[] = { 60.0 };
float lightPosition[] = { 0.0, 50.0, 50.0, 1.0 };




// Enable lighting with one light source<br /> glEnable(GL_LIGHTING);<br /> glEnable(GL_LIGHT0);
// Enable lighting with one light source
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);




// Properties of the objects' materials<br /> glMaterialfv(GL_FRONT, GL_SPECULAR, specularity); // Reflectance<br /> glMaterialfv(GL_FRONT, GL_SHININESS, shininess); // Shininess
// Properties of the objects' materials
glMaterialfv(GL_FRONT, GL_SPECULAR, specularity); // Reflectance
glMaterialfv(GL_FRONT, GL_SHININESS, shininess); // Shininess


// Enable ambient light usage<br /> glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
// Enable ambient light usage
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);


glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);<br /> glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);


// Position of the light source<br /> glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);<br />}
// Position of the light source
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
}


void GLWidget::resizeGL(int width, int height)<br />{<br />
void GLWidget::resizeGL(int width, int height)
{


// Set the viewport to be the entire window<br /> glViewport(0, 0, width, height);
// Set the viewport to be the entire window
glViewport(0, 0, width, height);




// Defines the perspective projection<br /> glLoadIdentity();<br /> gluPerspective(45, aspectRatio, 1, 500);
// Defines the perspective projection
glLoadIdentity();
gluPerspective(45, aspectRatio, 1, 500);




// Defines the position of the camera and the target<br /> glLoadIdentity();<br /> gluLookAt(0, 80, 200, 0, 0, 0, 0, 1, 0);<br />}
// Defines the position of the camera and the target
glLoadIdentity();
gluLookAt(0, 80, 200, 0, 0, 0, 0, 1, 0);
}
 
void GLWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
// Vertices
static const float vertices[6][4][3] = {
{ { 1.0, –1.0, 1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, 1.0, –1.0 }, { 1.0, 1.0, 1.0 } },
{ { –1.0, –1.0, –1.0 }, { –1.0, –1.0, 1.0 }, { –1.0, 1.0, 1.0 }, { –1.0, 1.0, –1.0 } },
{ { 1.0, –1.0, –1.0 }, { –1.0, –1.0, –1.0 }, { –1.0, 1.0, –1.0 }, { 1.0, 1.0, –1.0 } },
{ { –1.0, –1.0, 1.0 }, { 1.0, –1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { –1.0, 1.0, 1.0 } },
{ { –1.0, –1.0, –1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, –1.0, 1.0 }, { –1.0, –1.0, 1.0 } },
{ { –1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, –1.0 }, { –1.0, 1.0, -1.0 } }
};
 
 
for (int i = 0; i < 6; +''i) {
glBegin(GL_QUADS);
glNormal3fv(normals[i]);
for (int j = 0; j < 4;''+j)
glVertex3fv(vertices[i][j]);
glEnd();
}
}</code> ''GLWidget class for drawing the 3D cube.'' "source code":https://gitorious.org/wiki-sources/wiki-sources/trees/master/QtOpenGL/glwidget
 
This version is still about '''140 lines''' of code. Except that now we have the convenience of using it within a '''Qt''' class. That means, the drawing of the 3D objects can still be done with '''OpenGL''' standard functions, while leaving the window management and input handling part to the '''Qt''' API.
 
h2. Using '''Qt 3D'''
 
'''Qt 3D''' was created to simplify the usage of the '''OpenGL''' standard API within a '''Qt''' application. It abstracts most of the setup previously required. Camera position, viewing volume, vertices definition and other initial settings become '''much simpler'''. Therefore, reduces the overall code needed for creating a basic 3D program.
 
Similar to '''QGLWidget''', in '''Qt 3D''' there's a class named '''QGLView''' which does most of the work regarding this initial settings. All we need to do is subclass it.
 
<code>/* Qt 3D headers */
 
class GLView : public QGLView
{
Q_OBJECT
 
public:
GLView(QWidget *parent = 0);
~GLView();
 
protected:
void initializeGL(QGLPainter *painter);
void paintGL(QGLPainter *painter);
 
private:
QGLSceneNode *m_rootNode;
};


void GLWidget::paintGL()<br />{<br /> glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


// Vertices<br /> static const float vertices[6][4][3] = {<br /> { { 1.0, –1.0, 1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, 1.0, –1.0 }, { 1.0, 1.0, 1.0 } },<br /> { { –1.0, –1.0, –1.0 }, { –1.0, –1.0, 1.0 }, { –1.0, 1.0, 1.0 }, { –1.0, 1.0, –1.0 } },<br /> { { 1.0, –1.0, –1.0 }, { –1.0, –1.0, –1.0 }, { –1.0, 1.0, –1.0 }, { 1.0, 1.0, –1.0 } },<br /> { { –1.0, –1.0, 1.0 }, { 1.0, –1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { –1.0, 1.0, 1.0 } },<br /> { { –1.0, –1.0, –1.0 }, { 1.0, –1.0, –1.0 }, { 1.0, –1.0, 1.0 }, { –1.0, –1.0, 1.0 } },<br /> { { –1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, –1.0 }, { –1.0, 1.0, <s>1.0 } }<br /> };
GLView::GLView(QWidget *parent)
<br /> …
: QGLView(parent)
<br /> for (int i = 0; i &lt; 6; +''i) {<br /> glBegin(GL_QUADS);<br /> glNormal3fv(normals[i]);<br /> for (int j = 0; j &lt; 4;''+j)<br /> glVertex3fv(vertices[i][j]);<br /> glEnd();<br /> }<br />}</code> ''GLWidget class for drawing the 3D cube.'' &quot;source code&amp;quot;:https://gitorious.org/wiki-sources/wiki-sources/trees/master/QtOpenGL/glwidget
, m_rootNode(0)
<br />This version is still about '''140 lines''' of code. Except that now we have the convenience of using it within a '''Qt''' class. That means, the drawing of the 3D objects can still be done with '''OpenGL''' standard functions, while leaving the window management and input handling part to the '''Qt''' API.
{
<br />h2. Using '''Qt 3D'''
// Create the cube
<br />'''Qt 3D''' was created to simplify the usage of the '''OpenGL''' standard API within a '''Qt''' application. It abstracts most of the setup previously required. Camera position, viewing volume, vertices definition and other initial settings become '''much simpler'''. Therefore, reduces the overall code needed for creating a basic 3D program.
QGLBuilder builder;
<br />Similar to '''QGLWidget''', in '''Qt 3D''' there's a class named '''QGLView''' which does most of the work regarding this initial settings. All we need to do is subclass it.
builder << QGL::Faceted << QGLCube(2);
<br /><code>/* Qt 3D headers */
m_rootNode = builder.finalizedSceneNode();
<br />class GLView : public QGLView<br />{<br /> Q_OBJECT
<br />public:<br /> GLView(QWidget *parent = 0);<br /> ~GLView();
<br />protected:<br /> void initializeGL(QGLPainter *painter);<br /> void paintGL(QGLPainter *painter);
<br />private:<br /> QGLSceneNode *m_rootNode;<br />};


<br />GLView::GLView(QWidget *parent)<br /> : QGLView(parent)<br /> , m_rootNode(0)<br />{<br /> // Create the cube<br /> QGLBuilder builder;<br /> builder &lt;&lt; QGL::Faceted &lt;&lt; QGLCube(2);<br /> m_rootNode = builder.finalizedSceneNode();
// Setup the camera
<br /> // Setup the camera<br /> camera()</s>&gt;setFieldOfView(45);<br /> camera()<s>&gt;setNearPlane(1);<br /> camera()</s>&gt;setFarPlane(500);<br />}
camera()->setFieldOfView(45);
camera()->setNearPlane(1);
camera()->setFarPlane(500);
}


GLView::~GLView()<br />{<br /> delete m_rootNode;<br />}
GLView::~GLView()
{
delete m_rootNode;
}


void GLView::initializeGL(QGLPainter *painter)<br />{<br /> QGLLightParameters *lightParameters = new QGLLightParameters(this);<br /> QGLMaterial *material = new QGLMaterial(this);<br /> QColor color;
void GLView::initializeGL(QGLPainter *painter)
{
QGLLightParameters *lightParameters = new QGLLightParameters(this);
QGLMaterial *material = new QGLMaterial(this);
QColor color;


// Setup the lighting for the scene<br /> painter-&gt;setStandardEffect(QGL::LitMaterial);<br /> color.setRgbF(0.2, 0.2, 0.2, 1.0);<br /> lightParameters-&gt;setAmbientColor(color);<br /> color.setRgbF(1.0, 1.0, 1.0, 1.0);<br /> lightParameters-&gt;setSpecularColor(color);<br /> lightParameters-&gt;setDirection(QVector3D(0.0, 50.0, 50.0));<br /> painter-&gt;setMainLight(lightParameters);
// Setup the lighting for the scene
painter->setStandardEffect(QGL::LitMaterial);
color.setRgbF(0.2, 0.2, 0.2, 1.0);
lightParameters->setAmbientColor(color);
color.setRgbF(1.0, 1.0, 1.0, 1.0);
lightParameters->setSpecularColor(color);
lightParameters->setDirection(QVector3D(0.0, 50.0, 50.0));
painter->setMainLight(lightParameters);


// Apply a material<br /> color.setRgbF(1.0, 1.0, 1.0, 1.0);<br /> material-&gt;setSpecularColor(color);<br /> material-&gt;setShininess(60);<br /> color.setRgbF(0.0, 0.0, 1.0, 1.0);<br /> material-&gt;setAmbientColor(color);<br /> material-&gt;setDiffuseColor(color);<br /> painter-&gt;setFaceMaterial(QGL::AllFaces, material);<br />}
// Apply a material
color.setRgbF(1.0, 1.0, 1.0, 1.0);
material->setSpecularColor(color);
material->setShininess(60);
color.setRgbF(0.0, 0.0, 1.0, 1.0);
material->setAmbientColor(color);
material->setDiffuseColor(color);
painter->setFaceMaterial(QGL::AllFaces, material);
}


void GLView::paintGL(QGLPainter *painter)<br />{<br /> // Perform some transformations<br /> painter-&gt;modelViewMatrix().translate(0.0, 0.0, 5.0);<br /> painter-&gt;modelViewMatrix().rotate(15.0, 1.0, 0.0, 0.0);<br /> painter-&gt;modelViewMatrix().rotate(30.0, 0.0, 1.0, 0.0);<br /> painter-&gt;modelViewMatrix().rotate(15.0, 0.0, 0.0, 1.0);
void GLView::paintGL(QGLPainter *painter)
{
// Perform some transformations
painter->modelViewMatrix().translate(0.0, 0.0, 5.0);
painter->modelViewMatrix().rotate(15.0, 1.0, 0.0, 0.0);
painter->modelViewMatrix().rotate(30.0, 0.0, 1.0, 0.0);
painter->modelViewMatrix().rotate(15.0, 0.0, 0.0, 1.0);


// Draw the cube<br /> m_rootNode-&gt;draw(painter);<br />}</code> ''GLView class for drawing the 3D cube.'' &quot;source code&amp;quot;:https://gitorious.org/wiki-sources/wiki-sources/trees/master/Qt3D/glview
// Draw the cube
m_rootNode->draw(painter);
}</code> ''GLView class for drawing the 3D cube.'' "source code":https://gitorious.org/wiki-sources/wiki-sources/trees/master/Qt3D/glview


The code now looks easier to understand than its previous versions. There was no need for setting the cube's vertices, no aspect ratio calculation, no lighting normals set. The real work is done by the '''QGLBuilder''' class and '''QGLPainter''' class. The first one ('''QGLBuilder''') creates the geometry of the cube and adds it to the scene, while the second ('''QGLPainter''') does the actual drawing of the cube.
The code now looks easier to understand than its previous versions. There was no need for setting the cube's vertices, no aspect ratio calculation, no lighting normals set. The real work is done by the '''QGLBuilder''' class and '''QGLPainter''' class. The first one ('''QGLBuilder''') creates the geometry of the cube and adds it to the scene, while the second ('''QGLPainter''') does the actual drawing of the cube.
Line 155: Line 314:
== References ==
== References ==


The source code used in this article was based on examples from the following references:<br />&quot;OpenGL Programming Guide&amp;quot;:http://www.glprogramming.com/red/<br />&quot;GLUT&amp;quot;:http://www.opengl.org/resources/libraries/glut/<br />&quot;Qt OpenGL&amp;quot;:http://doc.qt.io/qt-5/qtopengl-index.html<br />&quot;Qt 3D&amp;quot;:http://doc.qt.nokia.com/qt-quick3d-snapshot/
The source code used in this article was based on examples from the following references:
"OpenGL Programming Guide":http://www.glprogramming.com/red/
"GLUT":http://www.opengl.org/resources/libraries/glut/
"Qt OpenGL":http://doc.qt.io/qt-5/qtopengl-index.html
"Qt 3D":http://doc.qt.nokia.com/qt-quick3d-snapshot/


'''Qt 3D''' latest snapshot can be obtained here: &quot;Qt Quick 3D&amp;quot;:http://doc.qt.nokia.com/qt-quick3d-snapshot/
'''Qt 3D''' latest snapshot can be obtained here: "Qt Quick 3D":http://doc.qt.nokia.com/qt-quick3d-snapshot/

Revision as of 08:53, 25 February 2015

[toc align_right="yes" depth="3"]

Introduction to Qt 3D

NOTE: Qt 3D (along with Qt Quick 3D project) is undergoing heavy development. They are not yet part of Qt 5, and the API shown in this article may be subject to changes.

WARNING: The contents of this article were last updated in 2012. This article is heavily outdated.

Qt 3D is a set of C++ APIs for 3D programming built on top of Qt OpenGL. The newest project is called Qt Quick 3D which creates QML bindings to Qt 3D.

First, we'll make a comparison of the previous OpenGL APIs: GLUT and Qt OpenGL.

GLUT (OpenGL Utility Toolkit)

GLUT was one the first (if not the first) toolkit to provide a portable API to handle window management for OpenGL programs. It uses callbacks to register drawing functions and more. There were also routines provided for drawing geometric primitives (both in solid and wireframe state) such as cubes and spheres.

A simple OpenGL program with just a 3D cube and some lighting could be as long as 140 lines of code when developed with GLUT.

3D Hello World Cube 3D cube drawn using OpenGL.



void initialize()
{
 float ambientLight[] = { 0.2, 0.2, 0.2, 1.0 };
 float specularLight[] = { 1.0, 1.0, 1.0, 1.0 };
 float specularity[] = { 1.0, 1.0, 1.0, 1.0 };
 float shininess[] = { 60.0 };
 float lightPosition[] = { 0.0, 50.0, 50.0, 1.0 };



// Enable lighting with one light source
 glEnable(GL_LIGHTING);
 glEnable(GL_LIGHT0);



// Properties of the objects' materials
 glMaterialfv(GL_FRONT, GL_SPECULAR, specularity); // Reflectance
 glMaterialfv(GL_FRONT, GL_SHININESS, shininess); // Shininess

// Enable ambient light usage
 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);

glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
 glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);

// Position of the light source
 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
}



void resize(int width, int height)
{
 

// Set the viewport to be the entire window
 glViewport(0, 0, width, height);



// Defines the perspective projection
 glLoadIdentity();
 gluPerspective(45, aspectRatio, 1, 500);



// Defines the position of the camera and the target
 glLoadIdentity();
 gluLookAt(0, 80, 200, 0, 0, 0, 0, 1, 0);
}

void paint()
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Vertices
 static const float vertices[6][4][3] = {
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } }
 };



for (int i = 0; i < 6; +''i) {
 glBegin(GL_QUADS);
 glNormal3fv(normals[i]);
 for (int j = 0; j < 4;''+j)
 glVertex3fv(vertices[i][j]);
 glEnd();
 }

glutSwapBuffers();
}

int main(int argc, char **argv)
{
 

initialize();

// Register the drawing function "paint()"
 glutDisplayFunc(paint);

// Register the resizing function "resize()"
 glutReshapeFunc(resize);


}

Drawing a 3D cube with GLUT. "source code":https://gitorious.org/wiki-sources/wiki-sources/trees/master/opengl

The code above follows a very basic OpenGL program structure. It has a initialize function (for doing some initial setup), a resize function (to handle window resizes) and a paint function (to draw the actual 3D objects).

Qt OpenGL

Qt OpenGL is a port of the OpenGL API to the Qt toolkit. It does a fairly good job at translating all of OpenGL basic functions to a Qt widget. Now, instead of several functions being registered for callbacks, it is possible to take advantage of the SIGNAL/SLOT system of Qt.

One of the most commonly used approches for Qt OpenGL to write a 3D program is to subclass QGLWidget. QGLWidget provides three convenience methods that you can reimplement to perform the typical OpenGL tasks: paintGL, resizeGL and initializeGL (similar to the GLUT version of the program).

The program below follows the same basic structure of its GLUT previous version.



class GLWidget : public QGLWidget
{
 Q_OBJECT

public:
 GLWidget(QWidget *parent = 0);

protected:
 void initializeGL();
 void resizeGL(int width, int height);
 void paintGL();
};

GLWidget::GLWidget(QWidget *parent)
 : QGLWidget(parent)
{
 setFormat(QGLFormat(QGL::Rgba | QGL::DoubleBuffer | QGL::DepthBuffer));
}

void GLWidget::initializeGL()
{
 float ambientLight[] = { 0.2, 0.2, 0.2, 1.0 };
 float specularLight[] = { 1.0, 1.0, 1.0, 1.0 };
 float specularity[] = { 1.0, 1.0, 1.0, 1.0 };
 float shininess[] = { 60.0 };
 float lightPosition[] = { 0.0, 50.0, 50.0, 1.0 };



// Enable lighting with one light source
 glEnable(GL_LIGHTING);
 glEnable(GL_LIGHT0);



// Properties of the objects' materials
 glMaterialfv(GL_FRONT, GL_SPECULAR, specularity); // Reflectance
 glMaterialfv(GL_FRONT, GL_SHININESS, shininess); // Shininess

// Enable ambient light usage
 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);

glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
 glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight);

// Position of the light source
 glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
}

void GLWidget::resizeGL(int width, int height)
{
 

// Set the viewport to be the entire window
 glViewport(0, 0, width, height);



// Defines the perspective projection
 glLoadIdentity();
 gluPerspective(45, aspectRatio, 1, 500);



// Defines the position of the camera and the target
 glLoadIdentity();
 gluLookAt(0, 80, 200, 0, 0, 0, 0, 1, 0);
}

void GLWidget::paintGL()
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Vertices
 static const float vertices[6][4][3] = {
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 } },
 { { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, 1.0 }, { 1.0, 1.0, -1.0 } }
 };

 

 for (int i = 0; i < 6; +''i) {
 glBegin(GL_QUADS);
 glNormal3fv(normals[i]);
 for (int j = 0; j < 4;''+j)
 glVertex3fv(vertices[i][j]);
 glEnd();
 }
}

GLWidget class for drawing the 3D cube. "source code":https://gitorious.org/wiki-sources/wiki-sources/trees/master/QtOpenGL/glwidget

This version is still about 140 lines of code. Except that now we have the convenience of using it within a Qt class. That means, the drawing of the 3D objects can still be done with OpenGL standard functions, while leaving the window management and input handling part to the Qt API.

h2. Using Qt 3D

Qt 3D was created to simplify the usage of the OpenGL standard API within a Qt application. It abstracts most of the setup previously required. Camera position, viewing volume, vertices definition and other initial settings become much simpler. Therefore, reduces the overall code needed for creating a basic 3D program.

Similar to QGLWidget, in Qt 3D there's a class named QGLView which does most of the work regarding this initial settings. All we need to do is subclass it.

/* Qt 3D headers */

class GLView : public QGLView
{
 Q_OBJECT

public:
 GLView(QWidget *parent = 0);
 ~GLView();

protected:
 void initializeGL(QGLPainter *painter);
 void paintGL(QGLPainter *painter);

private:
 QGLSceneNode *m_rootNode;
};


GLView::GLView(QWidget *parent)
 : QGLView(parent)
 , m_rootNode(0)
{
 // Create the cube
 QGLBuilder builder;
 builder << QGL::Faceted << QGLCube(2);
 m_rootNode = builder.finalizedSceneNode();

 // Setup the camera
 camera()->setFieldOfView(45);
 camera()->setNearPlane(1);
 camera()->setFarPlane(500);
}

GLView::~GLView()
{
 delete m_rootNode;
}

void GLView::initializeGL(QGLPainter *painter)
{
 QGLLightParameters *lightParameters = new QGLLightParameters(this);
 QGLMaterial *material = new QGLMaterial(this);
 QColor color;

// Setup the lighting for the scene
 painter->setStandardEffect(QGL::LitMaterial);
 color.setRgbF(0.2, 0.2, 0.2, 1.0);
 lightParameters->setAmbientColor(color);
 color.setRgbF(1.0, 1.0, 1.0, 1.0);
 lightParameters->setSpecularColor(color);
 lightParameters->setDirection(QVector3D(0.0, 50.0, 50.0));
 painter->setMainLight(lightParameters);

// Apply a material
 color.setRgbF(1.0, 1.0, 1.0, 1.0);
 material->setSpecularColor(color);
 material->setShininess(60);
 color.setRgbF(0.0, 0.0, 1.0, 1.0);
 material->setAmbientColor(color);
 material->setDiffuseColor(color);
 painter->setFaceMaterial(QGL::AllFaces, material);
}

void GLView::paintGL(QGLPainter *painter)
{
 // Perform some transformations
 painter->modelViewMatrix().translate(0.0, 0.0, 5.0);
 painter->modelViewMatrix().rotate(15.0, 1.0, 0.0, 0.0);
 painter->modelViewMatrix().rotate(30.0, 0.0, 1.0, 0.0);
 painter->modelViewMatrix().rotate(15.0, 0.0, 0.0, 1.0);

// Draw the cube
 m_rootNode->draw(painter);
}

GLView class for drawing the 3D cube. "source code":https://gitorious.org/wiki-sources/wiki-sources/trees/master/Qt3D/glview

The code now looks easier to understand than its previous versions. There was no need for setting the cube's vertices, no aspect ratio calculation, no lighting normals set. The real work is done by the QGLBuilder class and QGLPainter class. The first one (QGLBuilder) creates the geometry of the cube and adds it to the scene, while the second (QGLPainter) does the actual drawing of the cube.

The basic structure of the program is still there with the paintGL and initializeGL methods. There are also three more classes that handle typical OpenGL tasks: QGLCamera, QGLLightParameters and QGLMaterial.

References

The source code used in this article was based on examples from the following references: "OpenGL Programming Guide":http://www.glprogramming.com/red/ "GLUT":http://www.opengl.org/resources/libraries/glut/ "Qt OpenGL":http://doc.qt.io/qt-5/qtopengl-index.html "Qt 3D":http://doc.qt.nokia.com/qt-quick3d-snapshot/

Qt 3D latest snapshot can be obtained here: "Qt Quick 3D":http://doc.qt.nokia.com/qt-quick3d-snapshot/