I got a problem with drawing on a QGLWidget. I have several quads on the widget which I can move around when pressing some keys. As long as I just draw quads, everything works fine but now I want to add some lines using:
glBegin(GL_LINE);
glColor3f(c[0], c[1], c[2]);
glVertex3f(v1.x, v1.y, v1.z);
glVertex3f(v2.x, v2.y, v2.z);
glEnd;
The drawing also works fine, but the clearing of the glwidget doesn't work anymore. Means that I see everything I ever drawed on it. Just to mention.
I tried the same with GLUT using the same initializations and it worked, but since I have switched to Qt it doesn't work anymore.
paintGL(), resizeGL() and initializeGL() are below.
void GLWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f, 0.0f, 0.0f, 0.0f, -10.0f, -20.0f, 0.0f, 20.0f, -10.0f);
glTranslatef(0.0f, -30.0f, -40.0f);
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glRotatef(s_deg, 0.0f, 0.0f, 1.0f);
glRotatef(s_deg2, cos(DEGRAD(s_deg)), sin(DEGRAD(s_deg)), 0.0f);
float colors[8][3] = {
0.5, 0.0, 0.0,
0.0, 0.5, 0.0,
0.0, 0.0, 0.5,
1.0, 0.5, 0.5,
0.5, 1.0, 0.5,
0.5, 0.5, 1.0,
0.9, 0.9, 0.9,
0.1, 0.1, 0.1,
}; //red, green, blue, red shiny, green shiny, blue shine, light grey, dark grey
for(int i=0;i<glBoxes.size();i++) {
glBoxes.at(i).setColor(colors[i]);
glBoxes.at(i).drawCuboid();
glBoxes.at(i).drawCuboidGrid();
}
}
void GLWidget::initializeGL() {
glDepthFunc(GL_LESS);
glClearColor(0.2, 0.2, 0.2, 0.2);
glClearDepth(1.0);
}
void GLWidget::resizeGL(int width, int height) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0.0f, 0.0f, (float)width, (float)height);
glLoadIdentity();
gluPerspective(45.0f, (float)width/(float)height, 0.5f, 100.0f);
glMatrixMode(GL_MODELVIEW);
}
any Ideas?
The tokens accepted by glBegin are
GL_POINTS
GL_LINES
GL_TRIANGLES
GL_TRIANGLE_FAN
GL_TRIANGLE_STRIP
GL_QUADS
GL_QUAD_STRIP
and
GL_POLYGON
The token used by you, GL_LINE (not the missing trailing S) is not valid for glBegin.
The statement glEnd; will evaluate the address of the function glEnd and silently discard the result. Could it be, that you have a Pascal or Delphi background? In C like languages you have to add a matched pair of parentheses to make it a function call. Functions that don't take a parameter are called with an empty pair of parentheses. E.g. in your case glEnd();.
Not related to your problem. All of the code in resizeGL should go to the head of paintGL (use the widget's width() and height() getters). Also what you have in initializeGL belongs to paintGL.
The proper use of initializeGL is to do one-time initialization, like loading textures, and shaders, preparing FBOs and such.
resizeGL is meant to re-/initialize stuff that depends on the window's size and which is quite time consuming to change, like renderbuffers and/or textures used as attachment in FBOs used for window sized post-processing or similar. Setting the projection matrix does not belong there, and neither does the viewport. Those go into paintGL.
glDepthFunc, glClearColor and glClearDepth directly influence the drawing process and as such belong with the drawing code.
Also you should not use the immediate mode (glBegin … glEnd) at all. It's been outdated ever since OpenGL-1.1 was released over 15 years ago. Use Vertex Arrays, with the possible addition of Buffer Objects.
glEnd; should be glEnd();. This may actually fix your problem.
GL_LINE isn't a valid token for glBegin. To draw lines, you need GL_LINES (that's subtle, and you're in good company - this is a common mistake).
GL_LINE is used to control how polygons are rendered, which is controlled by the glPolygonMode function.
It must be GL_LINES instead of GL_LINE. The symbols accepted by glBegin are plural (i.e. GL_QUADS, GL_LINE_STRIPS...).
Related
I was wondering if anyone could help me figure out how to add a light source to my 3D objects. I have four objects that are rotating and I want the light source to be at a fixed position, and I want to be able to see lighting on the object.
I tried doing this (********):
//*******Initializing the light position
GLfloat pos[] = {-2,4,5,1};
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
//*******adding the light to the display method
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, pos);
// rectangle
glPushMatrix();
glTranslatef(0.0f, 2.5f, -8.0f);
glRotatef(angleRectangle, 0.0f, 1.0f, 0.0f);
drawRectangle();
glPopMatrix();
//small cylinder
glPushMatrix();
glTranslatef(0.0f, 2.0f, -8.0f);
glRotatef(90, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 0.0f, 1.0f);
drawCylinder(0.2, 0.7);
glPopMatrix();
//big cylinder
glPushMatrix();
glTranslatef(0.0f, 1.5f, -8.0f);
glRotatef(90, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 0.0f, 1.0f);
drawCylinder(0.7, 2.7);
glPopMatrix();
//pyramid
glPushMatrix();
glTranslatef(0.0f, -2.2f, -8.0f);
glRotatef(180, 1, 0, 0);
glRotatef(anglePyramid, 0.0f, 1.0f, 0.0f);
drawPyramid();
glPopMatrix();
glutSwapBuffers();
anglePyramid += k * 0.2f; //- is CW, + is CCW
angleRectangle += -k * 0.2f;
}
//******* Then i added these to the main method
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
However when I do this and I run the entire program, my objects turn gray, and at certain points in the rotation they turn white. And this isnt what I want. I want to keep my colorful objects, but I want to be able to see the light source on them.
Any help would be greatly appreciated. Also let me know if you need to see more of my code to figure out the issue. Thanks
When lighting (GL_LIGHTING) is enabled, then the color is taken from the material parameters (glMaterial).
If you still want to use the current color, the you have to enable GL_COLOR_MATERIAL
and to set the color material paramters (glColorMaterial):
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
See also Basic OpenGL Lighting.
But note, that drawing by glBegin/glEnd sequences, the fixed function pipeline matrix stack and fixed function pipeline per vertex light model, is deprecated since decades.
Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.
To my understanding, GL_FLAT is supposed to make a face a single color. I can't get GL_FLAT to actually work though; it's as though my program is only using GL_SMOOTH. I'm using light sources, but both look the same.
The triangle should be just one color. Here's my scene rendering code. I no where mention GL_SMOOTH, and I've tried GL_FLAT everywhere (inits, main, before light/material definitions, before drawing, while drawing, after drawing, etc.)
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_LIGHTING);
//Light
glEnable(GL_LIGHT1);
//Define Light source ...
//Define Material ...
//Draw Triangle
glShadeModel(GL_FLAT);
glNormal3f(0,0,1);
glBegin(GL_POLYGON);
glVertex3f( -.5, -.5, 0);
glVertex3f( 0, .5, 0);
glVertex3f( .5, -.5, 0);
glEnd();
glFlush();
That's it. Everything else in the program is the bare minimum it needs to run. Is GL_FLAT broken or something?
I heard that I should use normals instead of colors, because colors are deprecated. (Is that true?) Normals have something to do with the reflection of light, but I can't find a clear and intuitive explanation. What is a normal?
A normal in general is a unit vector whose direction is perpendicular to a surface at a specific point. Therefore it tells you in which direction a surface is facing. The main use case for normals are lighting calculations, where you have to determine the angle (or practically often its cosine) between the normal at a given surface point and the direction towards a lightsource or a camera.
glNormal minimal example
glNormal is a deprecated OpenGL 2 method, but it is simple to understand, so let's look into it. The modern shader alternative is discussed below.
This example illustrates some details of how glNormal works with diffuse lightning.
The comments of the display function explain what each triangle means.
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
/* Triangle on the x-y plane. */
static void draw_triangle() {
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glEnd();
}
/* A triangle tilted 45 degrees manually. */
static void draw_triangle_45() {
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, -1.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glVertex3f( 1.0f, -1.0f, 0.0f);
glEnd();
}
static void display(void) {
glColor3f(1.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
/*
Triangle perpendicular to the light.
0,0,1 also happens to be the default normal if we hadn't specified one.
*/
glNormal3f(0.0f, 0.0f, 1.0f);
draw_triangle();
/*
This triangle is as bright as the previous one.
This is not photorealistic, where it should be less bright.
*/
glTranslatef(2.0f, 0.0f, 0.0f);
draw_triangle_45();
/*
Same as previous triangle, but with the normal set
to the photorealistic value of 45, making it less bright.
Note that the norm of this normal vector is not 1,
but we are fine since we are using `glEnable(GL_NORMALIZE)`.
*/
glTranslatef(2.0f, 0.0f, 0.0f);
glNormal3f(0.0f, 1.0f, 1.0f);
draw_triangle_45();
/*
This triangle is rotated 45 degrees with a glRotate.
It should be as bright as the previous one,
even though we set the normal to 0,0,1.
So glRotate also affects the normal!
*/
glTranslatef(2.0f, 0.0f, 0.0f);
glNormal3f(0.0, 0.0, 1.0);
glRotatef(45.0, -1.0, 0.0, 0.0);
draw_triangle();
glPopMatrix();
glFlush();
}
static void init(void) {
GLfloat light0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
/* Plane wave coming from +z infinity. */
GLfloat light0_position[] = {0.0, 0.0, 1.0, 0.0};
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
}
static void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0, 7.0, -1.0, 1.0, -1.5, 1.5);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(800, 200);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return EXIT_SUCCESS;
}
Theory
In OpenGL 2 each vertex has its own associated normal vector.
The normal vector determines how bright the vertex is, which is then used to determine how bright the triangle is.
OpenGL 2 used the Phong reflection model, in which light is separated into three components: ambient, diffuse and specular. Of those, diffuse and specular components are affected by the normal:
if the diffuse light is perpendicular to the surface, it makes is brighter, no matter where the observer is
if the specular light hits the surface, and bounces off right into the eye of the observer, that point becomes brigher
glNormal sets the current normal vector, which is used for all following vertexes.
The initial value for the normal before we all glNormal is 0,0,1.
Normal vectors must have norm 1, or else colors change! glScale also alters the length of normals! glEnable(GL_NORMALIZE); makes OpenGL automatically set their norm to 1 for us. This GIF illustrates that beautifully.
Why it is useful to have normals per vertexes instead of per faces
Both spheres below have the same number of polygons. The one with normals on the vertexes looks much smoother.
OpenGL 4 fragment shaders
In newer OpenGL API's, you pass the normal direction data to the GPU as an arbitrary chunk of data: the GPU does not know that it represents the normals.
Then you write a hand-written fragment shader, which is an arbitrary program that runs in the GPU, which reads the normal data you pass to it, and implements whatever lightning algorithm you want. You can implement Phong efficiently if you feel like it, by manually calculating some dot products.
This gives you full flexibility to change the algorithm design, which is a major features of modern GPUs. See: https://stackoverflow.com/a/36211337/895245
Examples of this can be found in any of the "modern" OpenGL 4 tutorials, e.g. https://github.com/opengl-tutorials/ogl/blob/a9fe43fedef827240ce17c1c0f07e83e2680909a/tutorial08_basic_shading/StandardShading.fragmentshader#L42
Bibliography
https://gamedev.stackexchange.com/questions/50653/opengl-why-do-i-have-to-set-a-normal-with-glnormal
https://www.opengl.org/sdk/docs/man2/xhtml/glNormal.xml
http://www.tomdalling.com/blog/modern-opengl/06-diffuse-point-lighting/
http://learnopengl.com/#!Advanced-Lighting/Normal-Mapping
Many things are now deprecated, including normals and colors. That just means that you have to implement them yourself. With normals you can shade your objects. It's up to you to make the calculations but there are a lot of tutorials on e.g. Gouraud/Phong shading.
Edit: There are two types of normals: face normals and vertex normals. Face normals point away from the triangle, vertex normals point away from the vertex. With vertex normals you can achieve better quality, but there are many uses also for face normals, e.g. they can be used in collision detection and shadow volumes.
First of all, as usual, thanks to all for the great support from the SO community.
So I wrote code to draw 6 gl_quads (to form a cube). Initially, this code was drawn immediately (explicitly made 24 vertex calls in the display function). I'd like to put these in a display list. I read a tutorial about display lists, and gave it a shot. Problem is, nothing is showing up, and I have a glulookat that definitely points in the direction of the cube (verified in immediate mode). So basically the code works perfectly when not using display lists, but doesn't when I try to use the list.
Ok, enough of that, let's have a look at the code:
2nd EDIT- Moved glGenLists call into initGl and it works fine. Thanks all
*EDIT-*The glGenList call is made globally:
GLuint skybox = glGenLists(1);
And I'm still getting the same result. Nothing is rendering to the screen.
Setup the list (in initgl function):
glViewport(0,0,WINDOW_WIDTH,WINDOW_HEIGHT);
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION); //setup the projection matrix
glLoadIdentity();
gluPerspective(45, WINDOW_WIDTH/WINDOW_HEIGHT,.1,200.0);
glMatrixMode(GL_MODELVIEW); //switch to modelview
glLoadIdentity();
gluLookAt(-2,2,2,0,0,0,0,1,0);
glClearColor(0, 0, 0, 0);
glNewList(skybox, GL_COMPILE_AND_EXECUTE); //draw the list once to compile/store
drawEnv(); //draw 6 quads
glEndList(); //end list
display function (irrelevant code ommitted):
/* Clear buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//-----Draw Skybox------
glEnable(GL_TEXTURE_2D);
glPushMatrix(); //save env settings (I've tried removing this push/pop pair with same results
glCallList(skybox);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
And the drawEnv() function:
//---------------------------
//--------RIGHT WALL---------
//---------------------------
//This code draws correctly if I move this to the display function (immediate drawing)
glBindTexture(GL_TEXTURE_2D,rightTextureId);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f( 1.0f, 1.0f, 1.0f); //V2
glTexCoord2f(0.0, 1.0); glVertex3f( 1.0f,-1.0f, 1.0f); //V1
glTexCoord2f(1.0, 1.0); glVertex3f( 1.0f,-1.0f,-1.0f); //V3
glTexCoord2f(1.0, 0.0); glVertex3f( 1.0f, 1.0f,-1.0f); //V4
glEnd();
//repeat 5 more times
You're almost there, you just need first to call glGenLists() to generate a contiguous set of empty display lists.
GLuint listID;
listID = glGenLists( 1 ); // generate 1 display list
glNewList( listID, GL_COMPILE );
// whatever you want in the display list
glEndList();
// call the display list
glCallList( listID );
You should also do some error checking to make sure glGenLists() returned a valid display list.
I'm using Win32 and OpenGL to to draw text onto a window. I'm using the bitmap font method, with wglUseFontBitmaps. Here is my main rendering function:
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glColor3f(1.0f, 0.0f, 1.0f);
glBegin(GL_QUADS);
glVertex2f(0.0f, 0.0f);
glVertex2f(128.0f, 0.0f);
glVertex2f(128.0f, 128.0f);
glVertex2f(0.0f, 128.0f);
glEnd();
glPopMatrix();
glPushMatrix();
glColor3f(1.0f, 1.0f, 1.0f);
glRasterPos2i(200, 200);
glListBase(fontList);
glCallLists(5, GL_UNSIGNED_BYTE, "Test.");
glPopMatrix();
SwapBuffers(hDC);
As you can see it's very simple and the only thing that it's supposed to do is draw a quadrilateral and draw the text "Test.". But the problem is that drawing a polygon seems to mess up any text operations I try to do after it. If I place the text drawing functions before the polygon, both the text and the polygon draw fine. Is there something I'm missing here?
Edit: This problem only happens when the window is run in Fullscreen, by ChangeDisplaySettings. Any reason why this would be??
I know this might be a very late reply but I came across this question looking for answers to this exact problem. The way I attempted to draw text over a polygon is slightly different. I have a method that looked like this:
glClear( GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
glRasterPos2f( pX, pY );
glPushAttrib( GL_LIST_BIT );
glListBase( base - 32 );
glCallLists( length( pText ), GL_UNSIGNED_BYTE, PChar( pText ) );
glPopAttrib();
I tried drawing a polygon and text over it like this:
glPushMatrix();
glBegin(GL_QUADS);
glColor( 1.0, 0.0, 0.0 );
glVertex2f( fX, fY );
glVertex2f( fX + fWidth, fY );
glVertex2f( fX + fWidth, fY + fHeight );
glVertex2f( fX, fY + fHeight );
glEnd( );
glColor( 0.0, 1.0, 0.0 );
Text( 100, 100, fCaption );
glPopMatrix();
But, similar to your problem, only the text would draw or in some case (after moving the Text method around a bit) nothing would draw at all. I realized that the method had
glClear( GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT );
which OBVIOUSLY cleared the buffer after I drew the polygon and before I drew the text... This was such a silly mistake and although I have failed to recognize any similar code in the code you have provided, it may be somewhere else. Either way this bit of code will help you if you just clear the glClear method from the Text method. Hope this helps or might help other people who are in a similar situation.