QT-OpenGl Vertex not redrawing - qt

I have a simple openGl program that should redrawn when i change a spinner.
When the paintGL method is invoked the color of my vertex triangles change but the number of them (that is based on the spinner ) don't.
My code is the following:
void GLWidget::paintGL()
{
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR) ;
glClearColor(0.0, 0.0, 0.0, 0.0);
for(int i=0;i<numVertex;i++){
glBegin(GL_TRIANGLE_FAN);
drawTriangle(i);
glEnd();
}
qDebug("numVetex %d",numVertex);
};
void GLWidget::drawTriangle(int iteraction){
float theta=thetaIncrement*iteraction;
float x= radius*qCos(theta);
float y=radius*qSin(theta);
double r=((double) rand() / (RAND_MAX));
double g=((double) rand() / (RAND_MAX));
double b=((double) rand() / (RAND_MAX));
glColor3f(r,g,b);
glVertex3f( 0.0f, 0.0f, 0.0f);
glVertex3f(x,y,0.0f);
theta=thetaIncrement*(iteraction+1);
x= radius*qCos(theta);
y=radius*qSin(theta);
glVertex3f( x,y, 0.0f);
}
Even if i don't draw anything for example, on even number of vertex i just put a return on paintGl , the already drawn vertex still are showed on the screen.
Any recommendation?

your glClear call doesn't have a valid argument remove the GL_COLOR part:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;

Related

Use glBlendFunc in QOpenGLWidget

I'm trying to use glBlendFunc in QOpenGLWidget (in paintGL), but objects do not mix (alpha is works).
My code:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(blenFunc, GL_ONE);
m_world.setToIdentity();
m_world.rotate((m_xRot / 16.0f), 1, 0, 0);
m_world.rotate(m_yRot / 16.0f, 0, 1, 0);
m_world.rotate(m_zRot / 16.0f, 0, 0, 1);
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
m_program->bind();
m_tex->bind();
fillYoffsetLightning();
const GLfloat scaleFactor = 0.05f;
m_world.scale(scaleFactor, scaleFactor, 0.0f);
m_world.translate(0.f, 0.0f, 0.0f);
const GLfloat fact = 1 / scaleFactor;
const uint8_t X = 0, Y = 1;
for(int i = 0; i < maxElem; ++i) {
const GLfloat offX = m_ELECT[i][X] * fact;
const GLfloat offY = m_ELECT[i][Y] * fact;
m_world.translate(offX, offY);
m_program->setUniformValue(m_projMatrixLoc, m_proj);
m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world);
QMatrix3x3 normalMatrix = m_world.normalMatrix();
m_program->setUniformValue(m_normalMatrixLoc, normalMatrix);
glDrawArrays(GL_TRIANGLE_FAN, 0, m_logo.vertexCount());
update();
m_world.translate(-offX, -offY);
}
m_program->release();
shaders are simple:
// vertex
"attribute highp vec4 color;\n"
"varying highp vec4 colorVertex;\n"
//......... main:
"colorVertex = color;\n"
// fragment
"varying highp vec4 colorVertex;\n"
//......... main:
"gl_FragColor = colorVertex;\n"
Color is:
a pentagon with a gradient from white from center to blue to the edges is drawn (center color is 1,1,1, edges is 0,0,0.5)
screenshoot
Why is this happening?
If you want to achieve a blending effect, the you have to disable the depth test:
glDisable(GL_DEPTH_TEST);
Note, the default depth test function is GL_LESS. If a fragment is draw on a place of a previous fragment, then it is discarded by the depth test, because this condition is not full filled.
If the depth test is disabled, then the fragments are "blended" by the blending function (glBlendFunc) and equation (glBlendEquation).
I recommend to use the following blending function:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
In my case (Qt 5.15.2) I found that using a color call with no alpha component (eg. glColor3f(1,0,0) ) causes the blending to be disabled for any subsequent rendering. To my surprise I could not even recover it by re-issuing these commands:
glEnable(GL_BLEND); // wtf has no effect
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Blending simply remained disabled until the next paint begins. This did not happen with the original QGLWidget class. It only happens with QOpenGLWidget and only on Windows (Mac + Linux are fine).
The good-enough solution for me was to replace any non-alpha color calls with alpha equivalents, at least for cases where you need to use blending later in the render. Eg.
glColor3f(1,0,0); // before
glColor4f(1,0,0,1); // after
Another issue that might come up is if you use QPainter along with direct rendering, because the QPainter will trash your OpenGL state. See the mention of 'beginNativePainting' in the docs:
https://doc.qt.io/qt-5/qopenglwidget.html#painting-techniques
EDIT: I'll add this here because my comment on Rabbid's answer was deleted for some reason - the depth test does NOT need to be disabled to use blending. Rabbid might be thinking of disabling depth buffer writes which is sometimes done to allow drawing all translucent objects without having to sort them in order of furthest to nearest:
Why we disable Z-write in blending

Draw in QGLFrameBufferObject

With Qt and opengl, I would like draw in a QGlFrameBufferObject ?
I try this :
QGLFrameBufferObject * fbo = new QGLFramebufferObject(200, 200, QGLFramebufferObject::NoAttachment, GL_TEXTURE_2D, GL_RGBA32F);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0f, fbo->size().width(), fbo->size().height(), 0.0f, 0.0f, 1.0f);
fbo->bind();
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
fbo->release();
fbo->toImage().save("test.jpg"));
But I don't get a red image.
OTHER QUESTION
And if I want draw with :
glBegin(GL_QUAD);
glColor3d(0.2, 0.5, 1.0);
glVertex2i( 10, 20);
glColor3d(0.7, 0.5, 1.0);
glVertex2i( 15, 20);
glColor3d(0.8, 0.4, 1.0);
glVertex2i( 15, 25);
glColor3d(0.1, 0.9, 1.0);
glVertex2i( 10, 25);
glEnd();
Do I need also glClear() ?
You never actually clear the framebuffer. glClearColor() only sets the color used for clearing, but does not clear anything. You will need to add the second line here:
glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
The glClear() call will clear the color buffer with the clear color you specified in the first call. The framebuffer content is initially undefined, so you should always clear the framebuffer with a glClear() call before you start drawing. The only exception is if you're certain that the primitives you render will cover every pixel of the drawing surface. Even then, on some architectures it can actually be better for performance to still call glClear() first.
It shouldn't matter yet as long as you only clear the buffer. But once you want to start drawing, you will also need to set the viewport:
glViewport(0, 0, 200, 200);

QGL, opengl - all values of zaxis outside of 1;-1 get clipped

All figures outside of z-axis: (1;-1) range get clipped. Here is some code:
void MainWindow::initializeGL()
{
glDepthRange(-2,2);
glEnable(GL_TEXTURE_2D);
glDisable(GL_COLOR_MATERIAL);
glEnable(GL_BLEND);
glEnable(GL_POLYGON_SMOOTH);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(1, 1, 0, 0);
glDisable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LESS); // The Type Of Depth Test To Do
glShadeModel(GL_SMOOTH); // Enables Smooth Color Shading
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
void MainWindow::paintGL(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// glEnable(GL_TEXTURE_2D);
// glBindTexture(GL_TEXTURE_2D,texture);
// glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0 , image.width(), image.height(), 0, 0, image.bits() );
//glMatrixMode(GL_MODELVIEW);
//glEnable(GL_DEPTH_TEST);
glTranslated(0.0, 0.0, 1.9);
qglColor(Qt::black);
glBegin(GL_TRIANGLES);
glVertex3d(-0.1,0.1,1);
glVertex3d(-0.1,-0.1,-1);
glVertex3d(0.1,-0.1,0);
glEnd();
}
Any idea why does it happen?
This is actually completely normal behavior.
When you use identity modelview and projection matrices, your coordinates are in clip-space. The default W value for a 3D vertex in OpenGL is 1.0 (vertices are always 4D), and clip-space -> NDC works by dividing each component of a vertex by its W component and then clipping anything with a coordinate outside the range [-1,1].
I think what is confusing you is the glDepthRange (...) call. That does not affect clipping. Depth range is part of the viewport transformation, which happens after clipping.

Communicating large/changing/complex sets of vertices in OpenGL?

I've got a very basic scene rendering with a vertex and color array (some code below). I see how to bind the vertexes and colors to the vertex shaders attributes. Currently this vertex and color information is in a local array variable in my render function as you can see below and then glDrawArrays(GL_TRIANGLES, 0, n) is called to draw them for each frame.
I'm trying to picture the architecture of a larger moving scene where there are lots of models with lots of verticies that need to be loaded and unloaded.
The naïve way I imagine to extend this would be to place all the vertex/color data in one big array in main memory and then call glDrawArrays once for each frame. This seems to be inefficient to me. On every frame the vertex and color information changes only in parts, so arranging and reloading an entire monolithic vertex array for every frame seems wrong.
What do 3D games and so forth do about this? Are they for each frame placing all the vertexes in one big array in main memory, and then calling glDrawArrays once? If not, what architecture and OpenGL calls do they generally use to communicate all the vertexes of the scene to the GPU? Is it possible to load vertexes into GPU memory and then reuse them for several frames? Is it possible to draw multiple vertex arrays from multiple places in main memory?
static const char *vertexShaderSource =
R"(
attribute highp vec4 posAttr;
attribute lowp vec4 colAttr;
varying lowp vec4 col;
uniform highp mat4 matrix;
void main()
{
col = colAttr;
gl_Position = matrix * posAttr;
}
)";
static const char *fragmentShaderSource =
R"(
varying lowp vec4 col;
void main()
{
gl_FragColor = col;
}
)";
void Window::render()
{
glViewport(0, 0, width(), height());
glClear(GL_COLOR_BUFFER_BIT);
m_program->bind();
constexpr float delta = 0.001;
if (forward)
eyepos += QVector3D{0,0,+delta};
if (backward)
eyepos += QVector3D{0,0,-delta};
if (left)
eyepos += QVector3D{-delta,0,0};
if (right)
eyepos += QVector3D{delta,0,0};
QMatrix4x4 matrix;
matrix.perspective(60, 4.0/3.0, 0.1, 10000.0);
matrix.lookAt(eyepos, eyepos+direction, {0, 1, 0});
matrix.rotate(timer.elapsed() / 100.0f, 0, 1, 0);
m_program->setUniformValue("matrix", matrix);
QVector3D vertices[] =
{
{0.0f, 0.0f, 0.0f},
{1.0f, 0.0f, 0.0f},
{1.0f, 1.0f, 0.0f},
};
QVector3D colors[] =
{
{1.0f, 0.0f, 0.0f},
{1.0f, 1.0f, 0.0f},
{1.0f, 0.0f, 1.0f},
};
m_program->setAttributeArray("posAttr", vertices);
m_program->setAttributeArray("colAttr", colors);
m_program->enableAttributeArray("posAttr");
m_program->enableAttributeArray("colAttr");
glDrawArrays(GL_TRIANGLES, 0, 3);
m_program->disableAttributeArray("posAttr");
m_program->disableAttributeArray("colAttr");
m_program->release();
++m_frame;
}
Depends on how you want to structure things.
If you have a detailed model that needs to be moved and rotated and transformed but without changing its shape, then a pretty clear way to do it is to load that model into e.g. a VBO (I'm not sure what your setAttributeArray does), and this has to happen only before the first frame, and subsequent frames can render that model with any transformation you want by simply setting the model view matrix uniform which is a much smaller chunk of data going over the bus.
Vertex shaders can and should be used for letting the GPU help or offload entirely the computation and/or application of these types of operations.

Qt/OpenGL - draw a 2D "scale line" on top of a 3D scene [duplicate]

This question already has answers here:
Opengl: 2d HUD over 3D
(3 answers)
Closed 6 years ago.
I have a subclass "GLWidget" of QGLWidget where I render a 3D scene. I can do rotations and zoom on it.
I call with a QTimer the following function :
void GLWidget::processCurrent()
{
draw();
printStats();
glFlush();
swapBuffers();
}
and the main OpenGL render function "draw()" is :
void GLWidget::draw()
{
if (isDisplayFirst)
{
isDisplayFirst = false;
glViewport(0, 0, w_width, w_height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrixi
gluPerspective(45.0f, (float)w_width / w_height, g_nearPlane, g_farPlane);
gluLookAt (0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glScalef(0.03f, 0.03f, 0.03f);
}
rotateScene();
glClearColor(0.0 ,0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE);
GLuint vbo_disk = 0;
glBindBuffer(GL_ARRAY_BUFFER, vbo_disk);
glVertexPointer(4, GL_DOUBLE, 4*sizeof(double), Galaxy->pos);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0f, 1.0f, 1.0f, 0.2f);
glDrawArrays(GL_POINTS, 0, Galaxy->getNumParticles_disk());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_BLEND);
glDisable(GL_POINT_SPRITE);
}
I have already rendered 2D text (statistics) on this GLWidget with "printStats()" function. I would like now to draw a "2D scale line" on this 3D scene.
I succeed in draw this line by doing into printStats():
glDisable(GL_TEXTURE_2D);
glColor3f(1.0f, 1.0f, 1.0f);
glLineWidth(3.0f);
glBegin(GL_LINES);
glVertex2d(5, 40);
glVertex2d(20, 40);
glEnd();
glEnable(GL_TEXTURE_2D);
but my problem is that when I do rotations or zoom, this line moves with the 3D scene.
What is the way to lock this 2D line while being able to do operations on the 3D object ?
I want to avoid to use "overpainting" with overriding paintEvent.
I also try to use glPush/Pop Matrix but there are conflicts between 2D and 3D.
Could you give me some advice to get it ?
You are trying to implement HUD functionality, in principle what you need to to draw your 3D scene normaly, then backup all the OpenGL states that you want to reuse, and set up a new projection matrix with gluOrtho2D or glOrtho. Additionally you want to turn off the depth check.
After the call to the ortho function you will most likely draw in screen scale, so you will have to calculate the size of your line accordingly. Once you are done with the hud, you can pop the changes off the stack so you can draw again.
There are a couple of questions on stackoverflow that deal with drawing an OpenGl HUD
OpenGl 2D HUD over 3D
OpenGl 2d HUD in 3D Application
and a pretty decent discussion on the gamedev forum
http://www.gamedev.net/topic/388298-opengl-hud/

Resources