I am making a GUIon in Qt and I am using QGLWidgt to dispaly motion of an object.
For debugging puposes, I hard coded on matrix for try to display a teapot, but nothing is showing up on the screen. I have tried many things, I just dont know what is wrong.
EDIT
I figured out that it is showing the teapot, but the scaling is way off.. If i change the position was far from where it was. When I changed the position from -2.700, 2.000, 0.000 to -0.0270, 0.0200, 0.000, I could see it. I guess my question now is how to set the size of the screen to show what is being displayed??
The paintGL, resideGL and intializeGL are given below.
void GLWidget::initializeGL()
{
glClearColor(1.0,1.0,1.0,1.0);
GLUquadricObj *qobj = gluNewQuadric();
gluQuadricDrawStyle(qobj,GLU_FILL);
gluQuadricNormals(qobj,GLU_SMOOTH);
glClearDepth( 1.0f );
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
double eqn[] = {0.01f,0.0f,0.01f,-1.0f};
// enable clip plane
::glClipPlane(GL_CLIP_PLANE0,eqn);
setupLight();
}
void GLWidget::paintGL() {
double MOpenGLStack[16] = {0.4314, 0.875, 0.2181, 0.000,
0.0567, -0.267, 0.961, 0.000,
0.900, -0.402, -0.165, 0.000,
-2.700, 2.000, 0.000, 1.000};
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0, 0.0, -5.0);
glRotatef(xRot / 16.0, 1.0, 0.0, 0.0);
glRotatef(yRot / 16.0, 0.0, 1.0, 0.0);
glRotatef(zRot / 16.0, 0.0, 0.0, 1.0);
glTranslated(xTrans / 16.0, yTrans/ 16.0, 0.0f);
::glPushMatrix();
::glMultMatrixd(MOpenGLStack);
glutSolidTeapot(0.15);
::glPopMatrix();
}
void GLWidget::resizeGL(int w, int h){
int side = qMin(w, h);
glViewport((w - side) / 2, (h - side) / 2, side, side);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0f, (double)w/(double)h, 0.1f, 1000.0f);
glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity ();
glTranslatef(0.0f, 0.0f, -10.0f);
}
There is a problem here:
gluPerspective(30.0f, (double)w/(double)h, 0.1f, 1000.0f);
glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
The first line is overriden by the second line - you cannot have both perspective and orthographic view at the same time. If you do not want to view the teapot in parallel view, you can comment the second line.
Related
I am trying to display 3d point (50,30,20) using opengl but noting is displayed on the screen. How can I solve it?
init:
void init()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(20.0, 70.0, 10.0, 40.0, 10.0, 30.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Display:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glPointSize();
glBegin(GL_POINTS);
glVertex3f(50.0, 30.0, 20.0);
glEnd();
glFlush();
glutSwapBuffers();
}
Your point is clipped by the near plane of the orthographic projection:
glOrtho(20.0, 70.0, 10.0, 40.0, 10.0, 30.0);
glVertex3f(50.0, 30.0, 20.0);
The OpenGL coordinate system is a right handed system (see Right-hand rule). In view space the y axis points upwards and the x axis points to the right. Since the z axis is the Cross product of the x and y axis, it points out of the view.
Hence you've to shift the point along the negative z axis in between the near and far plane:
glVertex3f(50.0, 30.0, 20.0);
glVertex3f(50.0, 30.0, -20.0);
I need to translate my wired sphere along z-axis back and forth while also changing camera angle. Whenever my sphere gets translated, it slowly turns into ellipsoid. I really don't understand why. Here you can see pieces of code where I believe is a mistake. Also, shapes shouldn't be changed when resizing the window, only their size.
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLoadIdentity();
gluLookAt(ex, ey, ez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glTranslatef(0.0,0.0,tra);
glScalef(0.65, 0.65, 0.65);
glColor3f(1.0f, 0.8f, 1.0f);
glutWireSphere(0.65, 10, 15);
glPopMatrix();
glPushMatrix();
glLoadIdentity();
gluLookAt(ex, ey, ez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glColor3f(0.1f, 0.8f, 1.0f);
glutWireTorus(0.25, 1.0, 15, 15);
glPopMatrix();
glFlush();
glFlush();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.0, (GLfloat)w / (GLfloat)h, 1.0, 80.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
[...] while also changing camera angle. Whenever my sphere gets translated, it slowly turns into ellipsoid.
That's caused by the Perspective distortion or wide-angle distortion and increases towards the edge of the view. The effect can be decreased by reducing the field of view angle, but the effect will never be canceled completely (except parallel projection).
See als How to fix perspective projection distortion?.
Also, shapes shouldn't be changed when resizing the window, only their size."
At perspective projection the size of the objects is always relative to the size of the viewport rather than the size of your screen.
If you don't want perspective distortion and if you want that the size of the objects has to be relative to the size of the screen (measured in pixel), then you have to use an orthographic projection, relative to the size of the viewport.
For instance:
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluPerspective(70.0, (GLfloat)w / (GLfloat)h, 1.0, 80.0);
float sx = w / 100.0f;
float sy = h / 100.0f;
glOrtho(-sx/2.0f, sx/2.0f, -sy/2.0f, sy/2.0f, 1.0f, 80.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
I'm trying to recognize a drawn object on a mousPressEvent in OpenGL in Qt with picking.
I did some research but wasn't able to find the problem.
Clearly it recognizes something (because the return value of glRenderMode(GL_RENDER) is often an integer > 0), but not necessarily when I click on an object.
I think gluPerspective is the problem right here, but i just don't know how to resolve it.
mousePressEvent:
void WorldView::mousePressEvent(QMouseEvent *e)
{
GLuint buff[256];
GLint hits;
GLint view[4];
//Buffer to store selection data
glSelectBuffer(256, buff);
//Viewport information
glGetIntegerv(GL_VIEWPORT, view);
//Switch to select mode
glRenderMode(GL_SELECT);
//Clear the name stack!
glInitNames();
//Restric viewing volume
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
//Restrict draw area
gluPickMatrix(e->x(), e->y(), 1.0, 1.0, view);
gluPerspective(40.0f, (GLfloat)view[2]/(GLfloat)view[3], 1.0, 100.0);
//Draw the objects onto the screen
glMatrixMode(GL_MODELVIEW);
//Draw only the names in the stack
paintGL();
//Back into projection mode to push the matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
hits = glRenderMode(GL_RENDER);//number of recognized objects
printf("\n%d\n",hits);
//Back to modelview mode
glMatrixMode(GL_MODELVIEW);
}
Draw function:
void WorldView::paintGL ()
{
this->dayOfYear = (this->dayOfYear+1);
this->hourOfDay = (this->hourOfDay+1) % 24;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// store current matrix
glMatrixMode( GL_MODELVIEW );
glPushMatrix( );
gluLookAt(camPosx ,camPosy ,camPosz,
camViewx,camViewy,camViewz,
camUpx, camUpy, camUpz );
//Draw Axes
glDisable( GL_LIGHTING );
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(10.0, 0.0, 0.0);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 10.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(0.0, 0.0, 10.0);
glEnd();
//Draw objects we want to pick
glPushName(0);
glBegin(GL_TRIANGLES);
glVertex3d(1,1,1);
glVertex3d(2,3,2);
glVertex3d(5,2,2);
glEnd();
glPopName();
glPushName(1);
glBegin(GL_TRIANGLES);
glVertex3d(7,-5,1);
glVertex3d(10,3,2);
glVertex3d(10,2,2);
glEnd();
glPopName();
glPushName(2);
glBegin(GL_TRIANGLES);
glVertex3d(1,-5,7);
glVertex3d(2,3,9);
glVertex3d(5,2,9);
glEnd();
glPopName();
}
EDIT1: Maybe completing the code could help?
Initializer:
void WorldView::initializeGL ()
{
this->dayOfYear = 0;
this->hourOfDay = 0;
// Initialize QGLWidget (parent)
QGLWidget::initializeGL();
glShadeModel(GL_SMOOTH);
// Black canvas
glClearColor(0.0f,0.0f,0.0f,0.0f);
// Place light
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glEnable(GL_DEPTH_TEST);
GLfloat light0_position [] = {0.1f, 0.1f, 0.1f, 0.1f};
GLfloat light_diffuse []={ 1.0, 1.0, 1.0, 1.0 };
glLightfv ( GL_LIGHT0, GL_POSITION, light0_position );
glLightfv ( GL_LIGHT0, GL_DIFFUSE, light_diffuse );
}
resizer:
void WorldView::resizeGL ( int width, int height )
{
if ((width<=0) || (height<=0))
return;
//set viewport
glViewport(0,0,width,height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//set persepective
//change the next line order to have a different perspective
GLdouble aspect_ratio=(GLdouble)width/(GLdouble)height;
gluPerspective(40.0f, aspect_ratio, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
Use bullet raycast and not gl_Select which is way too slow and unwieldy. This will also make you get away from calling paintGL manually and other glCalls...in qt mousepressevent. Dont do this!
#include <GL/glut.h>
GLint winWidth = 600, winHeight = 600;
GLfloat x0 = 100.0, y0 = 100.0, z0 = 50.0;
GLfloat xref = 50, yref = 50.0, zref = 0.0;
GLfloat Vx = 0.0, Vy = 1.0, Vz = 0.0;
GLfloat xwMin = -40.0, ywMin = -60.0, xwMax = 40.0, ywMax = 60.0;
GLfloat dnear = 25.0, dfar = 125.0;
void init (void)
{
glClearColor (1.0, 1.0, 1.0, 0.0);
//glMatrixMode(GL_MODELVIEW);
//gluLookAt(x0, y0, z0, xref, yref, zref, Vx, Vy, Vz);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glOrtho(0,1,0,1, 0,0.1);
//gluOrtho2D(0, 1,0,1);
//gluPerspective(45, 1.2, 1, 10);
glFrustum(0, 1, 0, 1, 0, 1);
//gluPerspective(45.0, 1, 1, 15);
}
void displayFcn (void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(0.0, 1.0, 0.0);
//glPolygonMode(GL_FRONT, GL_FILL);
//glPolygonMode(GL_BACK, GL_FILL);
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
glVertex3f(0.5, 1.0, 0.0);
glEnd();
glFlush();
}
void reshapeFcn(GLint newWidth, GLint newHeight)
{
glViewport(0,0,newWidth, newHeight);
winWidth = newWidth;
winHeight = newHeight;
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowPosition(400,200);
glutInitWindowSize(winWidth, winHeight);
glutCreateWindow("Test");
init();
glutDisplayFunc(displayFcn);
glutReshapeFunc(reshapeFcn);
glutMainLoop();
}
This is the full source code, you can copy and paste to your VS solution and compile.
You'll need to have glut installed.
The result comes up like this:
The center of the window is 0,0 in opengl. So, when you calculate the vertices, you have to calculate them such that the center of the triangle is 0,0.
glBegin(GL_TRIANGLES);
glVertex3f(0.0, 0.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
glVertex3f(0.5, 1.0, 0.0);
glEnd();
those coords will need to be updated, you can find a discussion on finding the centers of triangles at this question: finding center of 2D triangle which sounds like it's from a similar homework assignment.
glTranslatef(-0.5f, -0.5f, 0.0f);
The default perspective for OpenGL is the origin centered and the window x and y ranging from -1 to 1. You can either change this by changing the default viewing volume or changing the coordinates of your triangle.
Either
glTranslatef(-.5f, -.5f, .0f);
or
glBegin(GL_TRIANGLES);
glVertex3f(-.5, -.5, 0.0);
glVertex3f(.50, -.5, 0.0);
glVertex3f(0, .5, 0.0);
glEnd();
will work.
It looks like you're trying to use glFrustum where you want to use glOrtho
glFrustum is supposed to be used for generating a perspective matrix. zNear is never 0. The way you call it right now generates an error GL_INVALID_VALUE, so you get the default projection matrix, the identity.
I need to show the same object in OpenGL in two different viewports, for instance, one using ortographic projection and the other using perspective. In order to do this, do I need to draw again the object after each call to glViewport()?
Nehe has a good tutorial on how to do this, and his site is generally a good resource for OpenGL questions.
// normal mode
if(!divided_view_port)
glViewport(0, 0, w, h);
else
{
// right bottom
glViewport(w/2, h/2, w, h);
glLoadIdentity ();
gluLookAt(5.0f, 5.0f, 5.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
display();
// left bottom
glViewport(0, h/2, w/2, h);
glLoadIdentity();
gluLookAt (5.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
display();
// top right
glViewport(w/2, 0, w, h/2);
glLoadIdentity();
gluLookAt(0.0f, 0.0f, 5.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
display();
// top left
glViewport(0, 0, w/2, h/2);
glLoadIdentity();
gluLookAt(0.0f, 5.0f, 0.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f);
display();
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0,
-2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w,
-10.0, 100.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h,
-2.0, 2.0,
-10.0, 100.0);
glMatrixMode(GL_MODELVIEW);
Minimal runnable example
Similar to this answer, but more direct and compilable. Output:
main.c
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
static int width;
static int height;
static void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 0.0f, 0.0f);
glViewport(0, 0, width/2, height/2);
glLoadIdentity();
gluLookAt(0.0, 0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glutWireTeapot(1);
glViewport(width/2, 0, width/2, height/2);
glLoadIdentity();
gluLookAt(0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glutWireTeapot(1);
glViewport(0, height/2, width/2, height/2);
glLoadIdentity();
gluLookAt(0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
glutWireTeapot(1);
glViewport(width/2, height/2, width/2, height/2);
glLoadIdentity();
gluLookAt(0.0, -3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0);
glutWireTeapot(1);
glFlush();
}
static void reshape(int w, int h) {
width = w;
height = h;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow(argv[0]);
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_FLAT);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return EXIT_SUCCESS;
}
Compile and run:
gcc -o main.out main.c -lGL -lGLU -lglut
./main.out
I think that in modern OpenGL 4 you should just render to textures, and then place those textures orthogonaly on the screen, see this as a starting point: http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/
Tested on OpenGL 4.5.0 NVIDIA 352.63, Ubuntu 15.10.
yes,
and you should also change the scissor settings to have a clean separation between the two views if they are in the same window.
In GL 4 you can render to many viewports in one rendering pass. See ARB_viewport_array and related concepts.
Think of OpenGL as being nothing more than commands which prepare you to output to the window you're currently working with.
There's two commands with OpenGL that even NEHE's tutorials don't tell you the importance of:
wglCreateContext - which takes a window device context DC, can be obtained from ANY window - whether it's a user control, a windows form, a GL window, or another application window (like notepad). This creates an OpenGL device context - they refer to as a resource context - which you later use with ...
wglMakeCurrent - which takes two parameters, the Device Context you're dealing with (the parameter passed in for the Windows Device Context in wglCreateContext) - and the Resource Context that returns.
Leveraging ONLY these two things - here's my advice:
NEHE's tutorial provides a solution that leverages the existing window ONLY and segments the screen for drawing. Here's the tutorial: http://nehe.gamedev.net/tutorial/multiple_viewports/20002/
Leveraging glViewport you'll need to re-draw on every update.
That's one method.
But there's another - less graphically and processor intense method:
Create a window for each view by leveraging a user control.
Each window has it's own hWnd.
Get the DC, process the wglcreatecontext, and then, on a timer (mine is 30 frames a second), if you detect state change, then select wglMakeCurrent for that view and redraw. Otherwise, just skip the section entirely.
This conserves valuable processing power, and also reduces the code from having to manage the window and viewport calculations manually.