glViewport issue - getting stretched camera views - c++

Hello I've tried to split a window in four viewports where I want to render a scene in each viewport.
For simplicity I have simplified the code to only contain a single camera view.
The code look roughly as follows:
void setup_trf(const PolarCoords& pc, double aspect)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, aspect, 0.01, 1000);
//glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
double eye_x, eye_y, eye_z;
pc.to_cartesian(eye_x, eye_y, eye_z);
double look_x = 0;
double look_y = 0;
double look_z = 0;
double up_x = 0;
double up_y = 0;
double up_z = 1;
gluLookAt(
eye_x, eye_y, eye_z,
look_x, look_y, look_z,
up_x, up_y, up_z);
}
void draw_scene(int w, int h) {
glClearColor(0.0f, 0.75f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
double aspect = w / double(h);
glViewport(0, h / 2, w / 2, h);
setup_trf(app_state.m_polar, aspect);
draw_sphere();
glViewport(w / 2, h / 2, w, h);
setup_trf(app_state.m_polar, aspect*0.5);
draw_sphere();
glViewport(0, 0, w / 2, h/2);
setup_trf(app_state.m_polar, aspect);
draw_sphere();
glViewport(w / 2, 0, w, h / 2);
setup_trf(app_state.m_polar, aspect);
draw_sphere();
}
And the result is the following:
view of the sphere
Anyone knows why the image gets stretched in the different viewports?

The 1st and 2nd parameter of glViewport are the bottom left coordinate (origin) of the viewport rectangle. But the 3rd and 4th parameter are the width and height of the viewport rectangle rather than the top right coordinate.
This means the 3rd and 4th parameter have to be the half of the window size (w/2, h/2) in each case:
glViewport(0, h/2, w/2, h/2);
setup_trf(app_state.m_polar, aspect);
draw_sphere();
glViewport(w/2, h/2, w/2, h/2);
setup_trf(app_state.m_polar, aspect);
draw_sphere();
glViewport(0, 0, w/2, h/2);
setup_trf(app_state.m_polar, aspect);
draw_sphere();
glViewport(w/2, 0, w/2, h/2);
setup_trf(app_state.m_polar, aspect);
draw_sphere();

Related

Using GLM with GTK to make simple 3D drawing

I am jus trying to draw a 3D Cartesian axis to see if I can get 3D to work. I am using GTK with Cairo to do the drawing. Here is my code...
glm::vec3 camera_pos(0, 0, -10);
glm::vec3 camera_target(0, 0, 0);
glm::vec3 up(0, 1, 0);
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
{
guint width, height;
width = gtk_widget_get_allocated_width(widget);
height = gtk_widget_get_allocated_height(widget);
glm::mat4 model = glm::translate(glm::vec3(width / 2.0f, height / 2.0f, 0.0f)) *
glm::scale(glm::vec3(100.0f, 100.0f, 100.0f));
glm::mat4 camera = glm::lookAt(camera_pos, camera_target, up);
glm::mat4 perspective = glm::perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);
glm::mat4 transform = perspective * camera * model;
glm::vec4 xaxis = transform * glm::vec4(1, 0, 0, 1);
glm::vec4 yaxis = transform * glm::vec4(0, 1, 0, 1);
glm::vec4 zaxis = transform * glm::vec4(0, 0, 1, 1);
glm::vec4 orig = transform * glm::vec4(0, 0, 0, 1);
cout << orig.x << " " << orig.y << endl;
cairo_set_source_rgb(cr, 1.0, 0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, xaxis.x, -xaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 1.0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, yaxis.x, -yaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 0, 1.0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, zaxis.x, -zaxis.y);
cairo_stroke(cr);
return FALSE;
}
Can someone check the math here because I am getting a lot of negative coordinates. Nothing appears on my screen when I run this.
Edit:
I just modified my camera vectors like this.
gboolean draw_callback(GtkWidget* widget, cairo_t* cr, gpointer data)
{
guint width, height;
width = gtk_widget_get_allocated_width(widget);
height = gtk_widget_get_allocated_height(widget);
glm::vec3 camera_pos(0, 0, 1000);
glm::vec3 camera_target(width / 2.0f, height / 2.0f, 0);
glm::vec3 up(0, 1, 0);
glm::mat4 model = glm::translate(glm::vec3(width / 2.0f, height / 2.0f, 0.0f));// *
//glm::scale(glm::vec3(100.0f, 100.0f, 100.0f));
glm::mat4 camera = glm::lookAt(camera_pos, camera_target, up);
glm::mat4 perspective = glm::perspective(45.0f, (float)width / (float)height, 0.1f, 100.0f);
glm::mat4 transform = perspective * camera * model;
glm::vec4 xaxis = transform * glm::vec4(100, 0, 0, 1);
glm::vec4 yaxis = transform * glm::vec4(0, 100, 0, 1);
glm::vec4 zaxis = transform * glm::vec4(0, 0, 100, 1);
glm::vec4 orig = transform * glm::vec4(0, 0, 0, 1);
cout << xaxis.x << " " << xaxis.y << endl;
cairo_set_source_rgb(cr, 1.0, 0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, xaxis.x, -xaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 1.0, 0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, yaxis.x, -yaxis.y);
cairo_stroke(cr);
cairo_set_source_rgb(cr, 0, 0, 1.0);
cairo_move_to(cr, orig.x, -orig.y);
cairo_line_to(cr, zaxis.x, -zaxis.y);
cairo_stroke(cr);
return FALSE;
}
Now I can see a blue line from the corner of my screen but it is still wrong.
You are using a perspective projection, but you do not carry out the persepctive divide, which will totally screw up your results. glm::perspective will create a matrix which maps the viewing frustum with the given angle and apsect ratio along the negative z axis to a [-w,w]^3 "cube" in clip space. After the perspective divide by the w coordinate, the viewing frustum will be [-1,1]^3 in normalized device coords. Usually at this stage, the coordinates are further converted into window space, where the actual pixels come into play.
In your case, you seem to try to incorporate the window resolution in the model transform at the start of the transform chain, which is totally weird if you later apply a standard GL projection matrix.

OpenGL texture not displayed (solid color instead texture) or displayed with artifacts

I'm using code to draw text as textures in OpenGL (Qt4.8.3 + Linux (debian-like)).
Code was ported from 2D project, where it is working good.
2D project was using gluOrtho2D, now I use gluLookAt for 3D.
The issue is that instead of text I'm seing colored rectangle.
If I turn on GL_DEPTH_TEST I see artifacts instead of text. BTW artifacts change if I move camera, which is quite strange.
Here's the code:
void GLWidget::paintGL() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //Set blending function.
glEnable(GL_BLEND); //Enable blending.
glShadeModel(GL_SMOOTH);
glEnable(GL_MULTISAMPLE);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60.0f, (GLdouble) width() / (GLdouble) height(), 0.001f, 10000.0f );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
// Set up current camera
gluLookAt( cameraDistance * sin(cameraTheta * M_PI / 180) * cos(cameraPhi * M_PI / 180),
cameraDistance * sin(cameraTheta * M_PI / 180) * sin(cameraPhi * M_PI / 180),
cameraDistance * cos(cameraTheta * M_PI / 180),
0.0, 0.0, 0.0,
0.0, 0.0, 1.0);
glTranslatef(-4.5355, -4.5355, 0.0);
glPushMatrix();
// draw text labels
drawLabel(1, 0, 90, "1");
drawLabel(2, 0, 90, "2");
drawLabel(3, 0, 90, "3");
drawLabel(4, 0, 90, "4");
drawLabel(5, 0, 90, "5");
glPopMatrix();
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glPopMatrix();
}
void GLWidget::drawLabel(float xpos, float ypos, float angle, char *txt) {
float labelHeight = 0.3;
float labelWidth = labelHeight / 2;
float margin = labelWidth / 10;
float len = (float) strlen(txt);
glPushMatrix();
glRotatef(-angle, 0, 0, -1);
glTranslatef(xpos, ypos, 0.0f);
glRotatef(angle, 0, 0, -1);
glScalef(1.0, -1.0, 1.0);
glTranslatef(- len * labelWidth / 2, -labelHeight / 2 + margin, 0.0f);
// background
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_QUADS);
glVertex3f(-margin, -margin, 0);
glVertex3f(len * labelWidth + margin, -margin, 0);
glVertex3f(len * labelWidth + margin, labelHeight + margin, 0);
glVertex3f(-margin, labelHeight + margin, 0);
glEnd();
// text
glColor3f(0.5f, 0.5f, 0.5f);
glEnable(GL_TEXTURE_2D);
glBindTexture( GL_TEXTURE_2D, glFont->getTextureID() );
glFont->drawText(labelWidth, labelHeight, txt);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
}
void oglFont::drawText(GLfloat cw, GLfloat ch, char *txt)
{
glBegin(GL_QUADS);
//character location and dimensions
GLfloat cx = 0.0f;
GLfloat cy = 0.0f;
//calculate how wide each character is in term of texture coords
GLfloat dtx = float(c_width) / float(m_width);
GLfloat dty = float(c_height) / float(m_height);
for (char * c = txt; *c != 0; c++, cx += cw) {
int index = getCharIndex(c);
int row = index / c_per_row;
int col = index % c_per_row;
if (index < 0) {
//qDebug() << "glFont: Character outside of font! char: " << c;
}
// find the texture coords
GLfloat tx = float(col * c_width) / float(m_width);
GLfloat ty = float(row * c_height) / float(m_height);
glTexCoord2f(0, 0);
glVertex2f(cx, cy);
glTexCoord2f(1, 0);
glVertex2f(cx + cw, cy);
glTexCoord2f(1, 1);
glVertex2f(cx + cw, cy + ch);
glTexCoord2f(0, 1);
glVertex2f(cx, cy + ch);
}
glEnd();
}
The reason for the artifacts is Z fighting.
This problem can be solved by increasing the depth buffer precision OR by making the different objects further apart from each-other (the ones from drawlable ).
Also make sure that your generated text doesn't get culled by the far plane / near plane (maybe you generate the geometry very near the edges ? ).
It turns out that because texture was loaded in QGLWidget constructor, context was either not created or not set.
I moved texture loading in initializeGL() method and it works great.

draw two objects using openGL in a same time

I have several functions:
drawGrid() -> which draws a grid on the ground;
drawAxes() -> which is draw axes using the gluCylinder
Arrows() -> which is used in drawAxes to draw cones as arrows;
I cant understand why I can not call drawGrid and drawAxes in a same time; in this case the output is like this link:
http://www.4shared.com/photo/8YTsc17s/wrong.html
if I comment the drawGrid() I can see the axes fine; but I want to draw them simultaneously;
http://www.4shared.com/photo/KI3DER-5/Axis.html
this is the codes I used:
1. drawGrid
void Golsa::drawGrid(float size, float step)
{
// disable lighting
glDisable(GL_LIGHTING);
glBegin(GL_LINES);
glColor3f(0.3f, 0.3f, 0.3f);
for(float i=step; i <= size; i+= step)
{
glVertex3f(-size, 0, i); // lines parallel to X-axis
glVertex3f( size, 0, i);
glVertex3f(-size, 0, -i); // lines parallel to X-axis
glVertex3f( size, 0, -i);
glVertex3f( i, 0, -size); // lines parallel to Z-axis
glVertex3f( i, 0, size);
glVertex3f(-i, 0, -size); // lines parallel to Z-axis
glVertex3f(-i, 0, size);
}
}
2. drawAxes:
void Golsa:: drawAxes(double length)
{
glPushMatrix();
glTranslatef(-length,0,0);
Arrow(0,0,0, 2*length,0,0,0.2);
glPopMatrix();
glPushMatrix();
glTranslatef(0,-length,0);
Arrow(0,0,0, 0,2*length,0,0.2);
glPopMatrix();
glPushMatrix();
glTranslatef(0,0,-length);
Arrow(0,0,0, 0,0,2*length,0.2);
glPopMatrix();
}
3. Arrow
void Golsa::Arrow(GLdouble x1,GLdouble y1,GLdouble z1,GLdouble x2,GLdouble y2,GLdouble z2,GLdouble D)
{
double x=x2-x1;
double y=y2-y1;
double z=z2-z1;
double L=sqrt(x*x+y*y+z*z);
GLUquadricObj *quadObj;
GLUquadric* cyl = gluNewQuadric();
GLUquadric* cy2 = gluNewQuadric();
GLUquadric* cy3 = gluNewQuadric();
glPushMatrix ();
glTranslated(x1,y1,z1);
if((x!=0.)||(y!=0.)) {
glRotated(atan2(y,x)/RADPERDEG,0.,0.,1.);
glRotated(atan2(sqrt(x*x+y*y),z)/RADPERDEG,0.,1.,0.);
} else if (z<0){
glRotated(180,1.,0.,0.);
}
//glTranslatef(0,0,L-4*D);
gluQuadricDrawStyle(cyl, GLU_FILL);
gluQuadricNormals(cyl, GLU_SMOOTH);
glTranslatef(0,0,0);
glColor3f(1,1,1);
gluQuadricDrawStyle(cyl, GLU_FILL);
//gluQuadricNormals(cyl, GLU_SMOOTH);
gluCylinder(cyl, 0.1, 0.1,4.0, 12,1);
//glColor3f (1,1,1);
glColor3f(1,1,1);
glTranslatef(0.0,0.0,4);
glColor3f(1,1,1);
gluQuadricNormals(cyl, GLU_SMOOTH);
gluCylinder(cy2, 0.2, 0,0.4, 12,1);
gluDeleteQuadric(cyl);
glPopMatrix();
}
this function call others :
void Golsa::drawSub()
{
float Xangle, Yangle, Zangle;
float Xposition, Yposition, Zposition;
/*Mat rvec1i = Mat(3,1,CV_64FC1,Scalar::all(0));
Mat tvec1i = Mat(3,1,CV_64FC1,Scalar::all(0));*/
// set bottom viewport (perspective)
glViewport(0, 0, windowWidth, windowHeight);
glScissor(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(FOV_Y, windowWidth/(windowHeight/2.0f), 1, 1000);
// switch to modelview matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// clear buffer
glClearColor(bgColor[0], bgColor[1], bgColor[2], bgColor[3]); // background color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glPushMatrix();
// First, transform the camera (viewing matrix) from world space to eye space
glTranslatef(0, 0, -cameraDistance);
glRotatef(cameraAngleX, 1, 0, 0); // pitch
glRotatef(cameraAngleY, 0, 1, 0); // heading
// draw grid
drawGrid(10, 1);
FindingCameraPosition(Xposition,Yposition,Zposition,Xangle,Yangle,Zangle);
glPopMatrix();
}
Turning my comment into an answer.
drawGrid() has a call to glBegin(), but no matching call to glEnd().

Why isn't this square in the middle of the screen?

I wrote some code, expecting to see a square in the middle of the screen, instead the square appears higher up, in some aspect ratios near the top of the screen, and slightly to the left.
With another aspect ratio:
Here's the relevant part of my code:
void resize(uint32_t height, uint32_t width){
glViewport(0, 0, width, height);
glMatrixMode (GL_PROJECTION); //set the matrix to projection
glLoadIdentity();
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 1000.0);
}
void draw(){
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
//set up camera
glLoadIdentity();
gluLookAt(0,10,0,0,0,0,0.001,0.999,0);
//draw a square in the center of the screen
glBegin(GL_TRIANGLE_FAN);
glColor4f(0,1,1,1);
glVertex3f(-1,0,-1);
glVertex3f(-1,0,1);
glVertex3f(1,0,1);
glVertex3f(1,0,-1);
glEnd();
glPopMatrix();
}
Isn't 0,0,0 supposed to be the middle of the screen? And isn't gluLookAt supposed to put whatever coordinate i specify in the center of the screen?
Change the value of up vector
gluLookAt(0,10,0,0,0,0,0,0,1);
your eyes is at positive y-axis and reference point at center and up (head) vector must be along z-axis.
You have done another mistake in your resize function
void resize(uint32_t height, uint32_t width){
glViewport(0, 0, width, height);
.....................
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 1000.0);
}
your variable height stores width of screen and variable width stores height, you have defined the glViewport and in gluPerspective you think your are taking ratio width by height, but actually you are taking ratio height by width, so it occurs the problem. Edit you code as follows:
void resize(uint32_t width, uint32_t height){
glViewport(0, 0, width, height);
..................
gluPerspective(60, (GLfloat)width / (GLfloat)height, 1.0, 1000.0);
}

Multiple viewport problem

I'm setting up so I can switch between either one or four viewports but I got some trouble.
In my bottom right viewport I got camera view, the same camera that I can switch to full view on. The other three viewports are working with fixed locations but the bottom right viewport is compressed on the y scale and half of the picture on the x scale is missing.
void display(int what)
{
if(what==5){glViewport(0, 0, w, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ca.lookAt();}
if(what==1){glViewport(0, 0, w/2, h/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(75,15,-5,0,5,-5,0,1,0);}
if(what==2){glViewport(w/2, h/2, w, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,110,0,20,0,20,1,0,0);}
if(what==3){glViewport(w/2, 0, w, h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, float(320) / float(240), 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
ca.lookAt();}
if(what==4){glViewport(0, h/2, w/2, h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(185,75,25,0,28,0,0,1,0);}
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
////gluLookAt(cos(shared.time) * shared.distance, 10, sin(shared.time) * shared.distance, 0, 0, 0, 0, 1, 0); // Roterar kameran kring origo genom att skapa en ny vymatris varje bildruta
////ca.orbitYaw(0.05);
//ca.lookAt();
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
drawScene();
drawCamera();
glutSwapBuffers();
}
void viewport(){
glEnable(GL_SCISSOR_TEST);
if(!divided_view_port)
{
glViewport(0, 0, w, h);
glScissor(0,0,640,480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 100.0f);
display(5);
}
else
{
////////////////////// bottom left - working
glViewport(0, 0, w/2, h/2);
glScissor(0,0,w/2,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(1);
//////////////////////
////////////////////// top right - working
glViewport(w/2, h/2, w, h);
glScissor(w/2,h/2,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(2);
//////////////////////
////////////////////// bottom right -working
glViewport(w/2, 0, w, h/2);
glScissor(w/2,0,w,h/2);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(3);
////////////////////////
////////////////////////// top left
glViewport(0, h/2, w/2, h);
glScissor(0,h/2,w/2,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, w / h, 0.1f, 300.0f);
display(4);
///////////////////////////
}
glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_MODELVIEW);
}
glViewport() takes an offset and a size.
Your code seems to be passing lower-left and upper-right coordinates.
Try these:
glViewport( 0, 0, w/2, h/2); // lower-left
glViewport(w/2, 0, w/2, h/2); // lower-right
glViewport(w/2, h/2, w/2, h/2); // upper-right
glViewport( 0, h/2, w/2, h/2); // upper-left