I write a program to draw one line.
The line sometimes disappear when I move camera to positive z-axis (especially when z-axis greater than 10000).
There are some test result.
When z set 20541, the line can be seen.
When z set 20542, the line CAN'T be seen.
When z set 30320, the line can be seen.
When z set 30321, the line CAN'T be seen.
and so forth ...
The code is attached. What's wrong?
P.S.
The code is written by OpenGL 1.0, but I can still get the same test result when written by OpenGL 3.0 + glm library.
#include <glut.h>
/*
System Info
-------------
OS: Win7 professional 64-bit SP1
CPU: Intel i3-4170 # 3.70GHz
GPU: HD Graphics 4400
*/
void display(void) {
// 20541 ok, 20542 not visible
// 30320 ok, 30321 not visible
const GLfloat z = 20541;
const GLfloat far = 1000, near = 0.1;
GLfloat vertices[4 * 3] = {
-far, -far, z - far,
far, far, z - far,
};
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, z, 0, 0, z - 1, 0, 1, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-0.1, 0.1, -0.1, 0.1, near, far);
glColor3f(0, 1, 1); // blue
glBegin(GL_LINES);
glVertex3f(vertices[0], vertices[1], vertices[2]);
glVertex3f(vertices[3], vertices[4], vertices[5]);
glEnd();
glFlush();
}
int main() {
glutCreateWindow("");
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
This issue seems to be a numerical instability of the floating point arithmetic. Since you are projecting points that are exactly on the far-plane, they get clipped when the floating-point result is a little bit larger than the expected result.
Let's assume a C++ implementation of what the gpu basically does:
glm::vec4 test_fp(float z)
{
//Construct matrices
auto ortho = glm::frustum(-0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1000.0f);
auto lookat = glm::lookAt(glm::vec3(0, 0, z), glm::vec3(0, 0, z - 1.0f), glm::vec3(0, 1, 0));
//We are only interested in the z-value
glm::vec4 tvec(0, 0, z - 1000.0f, 1);
//Calculate ndc vector
auto result = ortho * lookat * tvec;
//Homogenize
result /= result.w;
return result;
}
When now calling this function with the values you provided we get the following results:
auto a = test_fp(20541.0); //< [0, 0, 1.00000000, 1]
auto b = test_fp(20542.0); //< [0, 0, 1.00000191, 1]
auto c = test_fp(30320.0); //< [0, 0, 1.00000000, 1]
auto d = test_fp(30321.0); //< [0, 0, 1.00000191, 1]
As you can see, the results of b and d diverge from the mathematical correct result and are slightly above 1.0. Since values above 1.0 are behind the far-plane, they are clipped away and are not visible, which is exactly the behavior you have.
Related
I'm trying to draw in OpenGL 2 vectors with a given angle (in radians) between them, something like this:
I managed to draw the vectors but I'm not sure how to place them at the specific angle:
glBegin(GL_LINES); // Vx
glColor4f(1, .5, 0, 1);
glVertex3f(0, 0, 0);
glVertex3f(0, vectorYRScalingValue, 0); // vectorYRScalingValue is 5.0
glEnd();
glBegin(GL_LINES); // Vy
glColor4f(1, .5, 0, 1);
glVertex3f(0, 0, 0);
glVertex3f(0, vectorYRScalingValue, 0);
glEnd();
If β is the angle to be rotated in radians.
We rotate this vector anticlockwise around the origin.
float c = cos(β);
float s = sin(β);
NewX = x * c - y * s;
NewY = x * s + y * c;
I draw many lines to form a grid. I want to see the grid rotated on its X-axis, but I never get the intended result. I tried glRotatef and gluLookAt which does not work the way I want. Please see the pictures below.
this is the grid
this is how I want to see it
Edit: geez, posting the code here is also hard, lol, anyway here it is.
Edit2: removed, only leave the code that has issues.
Please find the code below, no matter how I set the gluLookAt, the grid result won't be in the perspective I want.
#include <GL/glut.h>
void display() {
...
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
for (int i = 0; i < 720; i += 3)
{
glColor3f(0, 1, 1);
glVertex3f(linePoints[i], linePoints[i + 1], linePoints[i + 2]);
}
glEnd();
glFlush();
}
void init() {
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 40);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -2, 1.25, 0, 0, 0, 0, 1, 0);
}
Lets assume, that you have a grid in the xy plane of the world:
glColor3f(0, 1, 1);
glBegin(GL_LINES);
for (int i = 0; i <= 10; i ++)
{
// horizontal
glVertex3f(-50.0f + i*10.0f, -50.0f, 0.0f);
glVertex3f(-50.0f + i*10.0f, 50.0f, 0.0f);
// vertical
glVertex3f(-50.0f, -50.0f + i*10.0f, 0.0f);
glVertex3f( 50.0f, -50.0f + i*10.0f, 0.0f);
}
glEnd();
Ensure that the distance of to the far plane of the projection is large enough (see gluPerspective). All the geometry which is not in between the near an far plane of the Viewing frustum is clipped.
Further more ensure that the aspect ratio (4.0 / 3.0) match the ratio of the viewport rectangle (window).
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0, 4.0 / 3.0, 1, 200);
For the use of gluLookAt, the up vector of the view has to be perpendicular to the grid. If the grid is arranged parallel to the xy plane, then the up vector is z axis (0, 0, 1).
The target (center) is the center of the grid (0, 0, 0).
The point of view (eye position) is ought to be above and in front of the grid, for instance (0, -55, 50). Note the point of view is used for a grid with the bottom left of (-50, -50, 0) and a top right of (50, 50, 0).
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, -55.0, 50.0, 0, 0, 0, 0, 0, 1);
The code below creates 2 square polygons, red and green.
I'm trying to place a red square on top of the green, but I can't.
The depth buffer is declared, cleaned when necessary, an orthogonal system is configured correctly.
If I specify a value outside the range (2;-2), the polygon disappears as it should.
#include <...>
constexpr auto FPS_RATE = 120;
int windowHeight = 600, windowWidth = 600, windowDepth = 600;
void init();
void idleFunction();
void displayFunction();
double getTime();
double getTime()
{
using Duration = std::chrono::duration<double>;
return std::chrono::duration_cast<Duration>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
}
const double frame_delay = 1.0 / FPS_RATE;
double last_render = 0;
void init()
{
glutDisplayFunc(displayFunction);
glutIdleFunc(idleFunction);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 2, -2);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void idleFunction()
{
const double current_time = getTime();
if ((current_time - last_render) > frame_delay)
{
last_render = current_time;
glutPostRedisplay();
}
}
void displayFunction()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
//move the red square to the foreground
glTranslatef(-32.5, -32.5, 2);
glColor3f(1, 0, 0);
glBegin(GL_POLYGON);
glVertex3i(-150, 150, 0);
glVertex3i(150, 150, 0);
glVertex3i(150, -150, 0);
glVertex3i(-150, -150, 0);
glEnd();
glPopMatrix();
glPushMatrix();
//move the green square to the background
glTranslatef(32.5, 32.5, -2);
glColor3f(0, 1, 0);
glBegin(GL_POLYGON);
glVertex3i(-150, 150, 0);
glVertex3i(150, 150, 0);
glVertex3i(150, -150, 0);
glVertex3i(-150, -150, 0);
glEnd();
glPopMatrix();
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(windowWidth, windowHeight);
glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2, (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);
glutCreateWindow("Window");
init();
glutMainLoop();
return 0;
}
You've to enable the Depth Test:
glEnable( GL_DEPTH_TEST );
The default depth test function (glDepthFunc) is < (GL_LESS).
If the distance to the far plane is 2.0 and the geometry is drawn with z coordinate of 2.0, then the geometry is clipped by the far plane, because the depth of the geometry is not less than the initialization depth of the depth buffer.
Change the depth function to <= (GL_LEQUAL):
glDepthFunc( GL_LEQUAL );
In a Right-handed system the viewspace z-axis points out of the viewport.
So if the z coordinate is "less than", then the object is "behind" an other object.
The projection matrix transforms from view space to normalized device space. In compare to the view space, the normalized device space is a left handed system, where the z-axis points in the viewport. The normalized device z-coordinate in range [-1, 1] (from the front to the back), is mapped to the depth value (in general in range [0, 1]), which is used for the depth test.
To deal with that glOrtho inverts the z-axis, if the near parameter is set less then the far parameter (this is how the function is suggested to be used).
This cause that the depth (z) order doesn't change, when the geometry is transformed form view space to normalized device space.
Note, glOrtho(-w, w, -h, h, -z, z) is the same as glScaled(1.0/w, 1.0/h, -1.0/z)
Since the z-axis is not inverted by the orthographic projection in your example, because near > far,
glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, 2, -2);
the z coordinate has to be greater, to be "behind".
If the green rectangle should be behind the red one, then you've to change the orthographic projection (near < far). e.g.:
glOrtho(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, -2, 2);
If you don't want to change the projection, then you've to swap the z-coordinates of the geometry:
glPushMatrix();
//move the red square to the foreground
glTranslatef(-32.5, -32.5, -2.0); // foreground because near > far
// ...
glPopMatrix();
glPushMatrix();
//move the green square to the background
glTranslatef(32.5, 32.5, 2.0); // background because near > far
// ...
glPopMatrix();
I am trying to write a own rotation function for a camera in OpenGL, but I can't get it to run. My camera is mainly from flipcode, with some minor changes:
Camera code:
Camera::Camera(float x, float y, float z) {
memset(Transform, 0, 16*sizeof(float));
Transform[0] = 1.0f;
Transform[5] = 1.0f;
Transform[10] = 1.0f;
Transform[15] = 1.0f;
Transform[12] = x; Transform[13] = y; Transform[14] = z;
Left=&Transform[0];
Up=&Transform[4];
Forward=&Transform[8];
Position=&Transform[12];
old_x = 0;
old_y = 0;
}
The view is set before every rendered frame:
void Camera::setView() {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float viewmatrix[16]={//Remove the three - for non-inverted z-axis
Transform[0], Transform[4], -Transform[8], 0,
Transform[1], Transform[5], -Transform[9], 0,
Transform[2], Transform[6], -Transform[10], 0,
-(Transform[0]*Transform[12] +
Transform[1]*Transform[13] +
Transform[2]*Transform[14]),
-(Transform[4]*Transform[12] +
Transform[5]*Transform[13] +
Transform[6]*Transform[14]),
//add a - like above for non-inverted z-axis
(Transform[8]*Transform[12] +
Transform[9]*Transform[13] +
Transform[10]*Transform[14]), 1};
glLoadMatrixf(viewmatrix);
}
Now to my problem, the rotation. Consider for example rotation around the y-axis. This is the rotation matrix stack:
// deg is the angle it is not working in degree or radiant
void Camera::rotateLocal_y(float deg){
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf(Transform);
rotateMatrixf_y(Transform, deg);
glGetFloatv(GL_MODELVIEW_MATRIX, Transform);
glPopMatrix();
}
So next I am going to show the rotation function:
//rotate a matrix around y axis
void rotateMatrixf_y(float *aMatrix, float angle){
// x y z t
float rotMatrix[] = {cos(angle),0,-1*sin(angle),0, 0, 1, 0, 0, sin(angle), 0, cos(angle), 0, 0, 0, 0, 1};
multMatrixMatrix(rotMatrix,aMatrix);
}
And finally the matrix multiplication function:
void multMatrixMatrix(float* m_a, float* m_b){
float m_c[16] = {m_a[0]*m_b[0]+m_a[4]*m_b[1]+m_a[8]*m_b[2]+m_a[12]*m_b[3],
m_a[0]*m_b[4]+m_a[4]*m_b[5]+m_a[8]*m_b[6]+m_a[12]*m_b[7],
m_a[0]*m_b[8]+m_a[4]*m_b[9]+m_a[8]*m_b[10]+m_a[12]*m_b[11],
m_a[0]*m_b[12]+m_a[4]*m_b[13]+m_a[8]*m_b[14]+m_a[12]*m_b[15],
m_a[1]*m_b[0]+m_a[5]*m_b[1]+m_a[9]*m_b[2]+m_a[13]*m_b[3],
m_a[1]*m_b[4]+m_a[5]*m_b[5]+m_a[9]*m_b[6]+m_a[13]*m_b[7],
m_a[1]*m_b[8]+m_a[5]*m_b[9]+m_a[9]*m_b[10]+m_a[13]*m_b[11],
m_a[1]*m_b[12]+m_a[5]*m_b[13]+m_a[9]*m_b[14]+m_a[13]*m_b[15],
m_a[2]*m_b[0]+m_a[6]*m_b[1]+m_a[10]*m_b[2]+m_a[14]*m_b[3],
m_a[2]*m_b[4]+m_a[6]*m_b[5]+m_a[10]*m_b[6]+m_a[14]*m_b[7],
m_a[2]*m_b[8]+m_a[6]*m_b[9]+m_a[10]*m_b[10]+m_a[14]*m_b[11],
m_a[2]*m_b[12]+m_a[6]*m_b[13]+m_a[10]*m_b[14]+m_a[14]*m_b[15],
m_a[3]*m_b[0]+m_a[7]*m_b[1]+m_a[11]*m_b[2]+m_a[15]*m_b[3],
m_a[3]*m_b[4]+m_a[7]*m_b[5]+m_a[11]*m_b[6]+m_a[15]*m_b[7],
m_a[3]*m_b[8]+m_a[7]*m_b[9]+m_a[11]*m_b[10]+m_a[15]*m_b[11],
m_a[3]*m_b[12]+m_a[7]*m_b[13]+m_a[11]*m_b[14]+m_a[15]*m_b[15]
};
m_b = m_c;
}
I though this must be it, but it seems as if something is fundamentaly wrong. It is not moving at all. the camera is properly set. The method order is: cam.rotate then cam.setView.
Flipcodes originial rotate function:
void Camera::rotateLoc(float deg, float x, float y, float z) {
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadMatrixf(Transform);
glRotatef(deg, x,y,z);
glGetFloatv(GL_MODELVIEW_MATRIX, Transform);
glPopMatrix();
}
Your code is pretty messy and incomplete.
I think your problem is here :
glPushMatrix();
glLoadMatrixf(Transform); // give the Transform matrix to GL (why?)
rotateMatrixf_y(Transform, deg); // modify the Transform matrix
glGetFloatv(GL_MODELVIEW_MATRIX, Transform); // (3) retrieve the original Tranform matrix
glPopMatrix();
(3) just undoes whatever changes you've been doing in 'Transform' by calling 'rotateMatrixf_y'.
The flipcode code you added is using OpenGL to update the Tranform matrix, by calling glRotatef' and reading back the result, which is fine. In your method code, you should just remove every reference to OpenGL and just keep the call to rotateMatrixf_y, which does all the work in its own.
Do you really understand what's the use of the GL matrix stack ? You should perhaps go back to the basics by either using only GL functions or using your own, but get to know why it works in either way before mixing the uses.
While attempting to render a 3D object using OpenGL (and the GLFW library), the model experiences lots of flickering. Im reading the .obj file using a library that I've written on my own.
Written below is my render function:
Unfortunately, in order to understand how faces and vertices are being inputted, I will have to provide all my code, which is linked:
Zipped code along with executable and sample .obj:
Source
Im using .obj files from here to test the program. Right now, the program doesn't support normals and textures, which isnt an issue since most of the models on the site dont have them. Also, (right now) it only reads from "123.obj" so the file should'nt be named anything else. And it only accepts a single space, not more than that.
float render()
{
glfwSetTime(0.0f);
int win_width;
int win_height;
glfwGetWindowSize(&win_width, &win_height);
float win_aspect = (float)win_width / (float)win_height;
glViewport(0, 0, win_width, win_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90, win_aspect, 0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, 50.0, 0, 0, 0, 0.0, 1.0, 0.0);
glEnable(GL_DEPTH);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glEnable(GL_NORMALIZE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glRotatef(angle , 0 , 1, 0);
glColor3f(0.0f, 0.0f, 0.0f);
int index = 0;
for(int a = 0; a < faces.size(); a++)
{
if(faces[a].vertices.size() == 3)
{
glBegin(GL_TRIANGLES);
}
else
{
glBegin(GL_QUADS);
}
for(int b = 0; b < faces[a].vertices.size(); b++)
{
index = faces[a].vertices[b];
glVertex3f(vertices[index].Dimensions[_x], vertices[index].Dimensions[_y], vertices[index].Dimensions[_z]);
}
glEnd();
}
glfwSwapBuffers();
return (float)glfwGetTime();
Here's the problem
gluPerspective(90, win_aspect, 0, 100.0);
You cannot set 0 as your nearclip, set it to something larger like 0.1, or 1.0.
gluPerspective(90, win_aspect, 1.0, 100.0);
With nearclip at 0, all of your depths get mapped to z = 1, and you get z fighting.
EDIT : if you're interested, here's some theory on perspective depth:
For a given distance from the camera x, your perspective transform outputs a certian depth value z. At the farclip, this value will be the maximum of 1, and at nearclip it will be 0.
Between these values however, relationship is not linear like you may expect. The curve looks similar to the following diagrams:
Diagram
When you go to the extreme of setting your nearclip to 0, your curve is heavily warped, so now all distances map to z = 1.
Because of all this, you should also try to keep the ratio far:near smaller than 10000:1