I am having an issue setting up the viewing projection. I am drawing a cube with the vertices (0, 0, 0) (0, 0, 1) (0, 1, 1) (0, 1, 0) (1, 0, 0) (1, 1, 0) (1, 1, 1) and (1, 0, 1). This is how I am initializing the view:
void initGL(int x,int y, int w, int h)
{
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );
glutInitWindowPosition( x, y );
glutInitWindowSize( w, h );
glutCreateWindow( "CSE328 Project 1" );
glutDisplayFunc(draw);
glFrontFace(GL_FRONT_AND_BACK);
glMatrixMode(GL_PROJECTION);
glFrustum(-10.0, 10.0, -10.0, 10.0, 2.0, 40.0);
glMatrixMode(GL_MODELVIEW);
gluLookAt(10, 10, 10, 0.5, 0.5, 0, 0, 1.0, 0);
glutMainLoop();
}
For some reason, the cube is filling the entire screen. I have tried changing the values of the frustum and lookAt methods, and either the cube is not visible at all, or it fills the entire viewport. In glLookAt I assume the 'eye' is positioned at (10, 10, 10) and looking at the point (0.5, 0.5, 0), which is on the surface of the cube. I thought this would give enough distance so the whole cube would be visible. Am i thinking about this in the wrong way? I have also tried moving the cube in the z direction so that it lies from z = 10 to z = 11, and so is in the clipping plane, but it gives similar results.
The cube has length 1, the viewing volume spans 20 units in x and y dimensions. The cube occupies some pixels in the middle even with orthographic projection; unless there is some other transformation applied during drawing.
I suggest making the frustum smaller (e.g. +/- 2.0f) and moving the camera closer; (4.0f, 4.0f, 4.0f).
Moving the eye position further from the cube by changing the first 3 parameters of gluLookAt() should make it smaller.
You could also replace your call to glFrustum() with a call to gluPerspective() which would make it easier to configure the perspective projection to your liking.
Related
I'm trying to understand what I'm doing wrong displaying two different cubes with a grid through the x and z axis. I'm using gluLookAt() to view both cubes at the same angle. I'm very confused why the first viewport does not show the grid but the second one does. Here's my code and an example picture of why I'm confused.
def draw(c1, c2):
glClearColor(0.7, 0.7, 0.7, 0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glBegin(GL_LINES)
for edge in grid_edges:
for vertex in edge:
glColor3fv((0.0, 0.0, 0.0))
glVertex3fv(grid_vertices[vertex])
glEnd()
glViewport(0, 0, WIDTH // 2, HEIGHT)
glLoadIdentity()
gluPerspective(90, (display[0] / display[1]) / 2, 0.1, 50.0)
gluLookAt(c1.center_pos[0], c1.center_pos[1], c1.center_pos[2] + 8, c1.center_pos[0], c1.center_pos[1], c1.center_pos[2], 0, 1, 0)
glPushMatrix()
glTranslatef(c1.center_pos[0], c1.center_pos[1], c1.center_pos[2])
glRotatef(c1.rotation[0], c1.rotation[1], c1.rotation[2], c1.rotation[3])
glTranslatef(-c1.center_pos[0], -c1.center_pos[1], -c1.center_pos[2])
glBegin(GL_LINES)
for edge in c1.edges:
for vertex in edge:
glColor3fv((0, 0, 0))
glVertex3fv(c1.vertices[vertex])
glEnd()
glPopMatrix()
glViewport(WIDTH // 2, 0, WIDTH // 2, HEIGHT)
glLoadIdentity()
gluPerspective(90, (display[0] / display[1]) / 2, 0.1, 50.0)
gluLookAt(c2.center_pos[0], c2.center_pos[1], c2.center_pos[2] + 8, c2.center_pos[0], c2.center_pos[1], c2.center_pos[2], 0, 1, 0)
glPushMatrix()
glTranslatef(c2.center_pos[0], c2.center_pos[1], c2.center_pos[2])
glRotatef(c2.rotation[0], c2.rotation[1], c2.rotation[2], c2.rotation[3])
glTranslatef(-c2.center_pos[0], -c2.center_pos[1], -c2.center_pos[2])
glBegin(GL_LINES)
for edge in c2.edges:
for vertex in edge:
glColor3fv((0, 0, 0))
glVertex3fv(c2.vertices[vertex])
glEnd()
glPopMatrix()
OpenGL is a state machine. Once a state is set, it persists even beyond frames. This means if you change the viewport or set a matrix, that viewport and matrix are the same at the beginning of the next frame. These states are not "reset" from one frame to the next. You need to set the viewport and set the identity matrix at the beginning of draw:
def draw(c1, c2):
glClearColor(0.7, 0.7, 0.7, 0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glViewport(0, 0, WIDTH, HEIGHT)
glLoadIdentity()
glBegin(GL_LINES)
for edge in grid_edges:
for vertex in edge:
glColor3fv((0.0, 0.0, 0.0))
glVertex3fv(grid_vertices[vertex])
glEnd()
# [...]
I'm trying to render a scene with OpenGL 2.1 but the borders on overlapping shapes are weird. I tested some OpenGL initialisations but without any change. I reduce my issue to a simple test application with 2 sphere with the same result.
I tried several things about Gl_DEPTH_TEST, enable/disable smoothing without success.
Here is my result with 2 gluSphere :
We can see some sort of aliasing when a line will be enough to separate blue and red faces...
I use SharpGL but I think that it's not significant (as I use it only as a an OpenGL wrapper). Here my simplest code to render the same thing (You can copy it in a Form to test it) :
OpenGL gl;
IntPtr hdc;
int cpt;
private void Init()
{
cpt = 0;
hdc = this.Handle;
gl = new OpenGL();
gl.Create(SharpGL.Version.OpenGLVersion.OpenGL2_1, RenderContextType.NativeWindow, 500, 500, 32, hdc);
gl.Enable(OpenGL.GL_DEPTH_TEST);
gl.DepthFunc(OpenGL.GL_LEQUAL);
gl.ClearColor(1.0F, 1.0F, 1.0F, 0);
gl.ClearDepth(1);
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.Perspective(30, 1, 0.1F, 1.0E+7F);
gl.MatrixMode(OpenGL.GL_MODELVIEW);
gl.LookAt(0, 3000, 0, 0, 0, 0, 0, 0, 1);
}
private void Render(int angle)
{
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
RenderSphere(gl, 0, 0, 0, 0, 300, Color.Red);
RenderSphere(gl, 0, 0, 100, angle, 300, Color.Blue);
gl.Blit(hdc);
}
private void RenderSphere(OpenGL gl, int x, int y, int z, int angle, int radius, Color col)
{
IntPtr obj = gl.NewQuadric();
gl.PushMatrix();
gl.Translate(x, y, z);
gl.Rotate(angle, 0, 0);
gl.Color(new float[] { col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f });
gl.QuadricDrawStyle(obj, OpenGL.GLU_FILL);
gl.Sphere(obj, radius, 20, 10);
gl.Color(new float[] { 0, 0, 0, 1 });
gl.QuadricDrawStyle(obj, OpenGL.GLU_SILHOUETTE);
gl.Sphere(obj, radius, 20, 10);
gl.DeleteQuadric(obj);
gl.PopMatrix();
}
Thanks in advance for your advices !
EDIT :
I tested that without success :
gl.Enable(OpenGL.GL_LINE_SMOOTH);
gl.Enable(OpenGL.GL_POLYGON_SMOOTH);
gl.ShadeModel(OpenGL.GL_SMOOTH);
gl.Hint(OpenGL.GL_LINE_SMOOTH_HINT, OpenGL.GL_NICEST);
gl.Hint(OpenGL.GL_POLYGON_SMOOTH_HINT, OpenGL.GL_NICEST);
gl.Hint(OpenGL.GL_PERSPECTIVE_CORRECTION_HINT, OpenGL.GL_NICEST);
EDIT2 : With more faces, image with and without lines
It is ... different... but not pleasing.
The issue has 2 reasons.
The first one indeed is a Z-fighting issue, which is cause by the monstrous distance between the near and far plane
gl.Perspective(30, 1, 0.1F, 1.0E+7F);
and the fact that at perspective projection, the depth is not linear. See also How to render depth linearly ....
This can be improved by putting the near plane as close as possible to the geometry. Since the distance to the object is 3000.0 and the radius of the sphere is 300, the near plane has to be less than 2700.0:
e.g.
gl.Perspective(30, 1, 2690.0F, 5000.0F);
The second issue is caused by the fact, that the sphere consist of triangle primitives. As you suggested in your answer, you can improve that by increasing the number of primitives.
I will provide an alternative solution, by using a clip plane. Clip the red sphere at the bottom and the blue sphere at the top. Exactly in the plane where the spheres are intersecting, so that a cap is cut off from each sphere.
A clip plane can be set by glClipPlane and to be enabled by glEnable.
The parameters to the clipping plane are interpreted as a Plane Equation.
The first 3 components of the plane equation are the normal vector to the clipping plane. The 4th component is the distance to the origin.
So the clip plane equation for the red sphere has to be {0, 0, -1, 50} and for the blue sphere {0, 0, 1, -50}.
Note, when glClipPlane is called, then the equation is transformed by the inverse of the modelview matrix. So the clip plane has to be set before the model transformations like rotation, translation and scale.
e.g.
private void Render(int angle)
{
gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT | OpenGL.GL_STENCIL_BUFFER_BIT);
double[] plane1 = new double[] {0, 0, -1, 50};
RenderSphere(gl, 0, 0, 0, 0, 300, Color.Red, plane1);
double[] plane2 = new double[] {0, 0, 1, -50};
RenderSphere(gl, 0, 0, 100, angle, 300, Color.Blue, plane2);
gl.Blit(hdc);
}
private void RenderSphere(
OpenGL gl, int x, int y, int z, int angle, int radius,
Color col, double[] plane)
{
IntPtr obj = gl.NewQuadric();
gl.ClipPlane(OpenGL.GL_CLIP_PLANE0, plane);
gl.Enable(OpenGL.GL_CLIP_PLANE0);
gl.PushMatrix();
gl.Translate(x, y, z);
gl.Rotate(angle, 0, 0);
gl.Color(new float[] { col.R / 255f, col.G / 255f, col.B / 255f, col.A / 255f });
gl.QuadricDrawStyle(obj, OpenGL.GLU_FILL);
gl.Sphere(obj, radius, 20, 10);
gl.Color(new float[] { 0, 0, 0, 1 });
gl.QuadricDrawStyle(obj, OpenGL.GLU_SILHOUETTE);
gl.Sphere(obj, radius, 20, 10);
gl.DeleteQuadric(obj);
gl.PopMatrix();
gl.Disable(OpenGL.GL_CLIP_PLANE0);
}
Solution 1 (not a good one): Applying gl.Scale(0.0001, 0.0001, 0.0001); to the ModelView matrix
Solution 2 : The near plane has to be as far as possible to avoid compressing z value in a small range. In this case, use 10 instead of 0.1 is enough. The best is to compute an adapted value depending on objects distance (in this case the nearest object is at 2700)
I think we can focus on z is stored non-linearly in the #PikanshuKumar link and the implicit consequencies.
Result :
Only the faces are cutted by a line: there is a straight line as separator at the equator.
Those lines disappear as expected when we increase the number of faces.
You're killing depth buffer precision with the way you setup your projection matrix
gl.MatrixMode(OpenGL.GL_PROJECTION);
gl.Perspective(30, 1, 0.1F, 1.0E+7F);
Essentially this compresses almost all of the depth buffer precision into the range 0.1 to 0.2 or so (I didn't do the math, just eyeballing it here).
In general you should choose the distance for the near clip plane to be as far away as possible, still keeping all the objects in your scene. The distance of the far plane doesn't matter that much (in fact, with the right matrix magic you can place it at infinity), but in general it's also a good idea to keep it as close as possible.
I'm trying to create a 3D manipulation program using C++ and openGL. I'm relatively new to openGL so I often have to look up the documentation to find the right function to do what I want. I thought I had a good understanding of orthogonal vs perspective projections (in that glOrtho creates an orthogonal projection where different z-values don't look different and glFrustum creates a perspective projection where z-values that are closer look bigger). However, when I swap out glOrtho and glFrustum in my program, I don't see any difference. I replicated a small program below that shows the effects. For reference, I'm using openGL with freeglut.
#include "GL/freeglut.h"
void initFunc()
{
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1, 1, -1, 1, -1, 1);
}
void displayFunc()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glColor3f(1.0f, 1.0f, 0.0f);
glLineWidth(1.0f);
glutWireTeapot(0.3);
glTranslatef(0, -0.5, -0.5);
glutWireTeapot(0.3);
glutSwapBuffers();
}
int main(int argc, char ** argv)
{
glutInit(&argc, argv);
glutInitWindowSize(600, 600);
glutInitWindowPosition(0, 0);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutCreateWindow("Teapot Perspective");
initFunc();
glutDisplayFunc(displayFunc);
glutMainLoop();
}
I'm drawing two teapots slightly offset in both the y and z axes. From what I understand, the glOrtho should render the two teapots as identical with only a y offset, whereas the glFrustum should render one of them bigger than the other. However, both of them render the teapots identically.
Am I missing something here? Are there other steps I have to take to properly set up a perspective projection? Or am I misunderstanding how glFrustum works? I've also tried using gluPerspective instead of glFrustum but I can't seem to find the right values to use. I experimented with a FOV of 90, aspect of 1, and various z values but they all either produce no teapot, or a teapot distorted beyond recognition. Furthermore, the gluPerspective appears to have different behavior than a glFrustum call with corresponding parameters. I'm not sure what I'm missing here.
At Orthographic Projection the coordinates in the view space are linearly mapped to clip space coordinates and the clip space coordinates are equal to the normalized device coordinates, because the w component is 1 (for a cartesian input coordinate).
The values for left, right, bottom, top, near and far define a box. All the geometry which is inside the volume of the box is "visible" on the viewport.
The Orthographic Projection Matrix, defined by glOrtho is:
r = right, l = left, b = bottom, t = top, n = near, f = far
x: 2/(r-l) 0 0 0
y: 0 2/(t-b) 0 0
z: 0 0 -2/(f-n) 0
t: -(r+l)/(r-l) -(t+b)/(t-b) -(f+n)/(f-n) 1
At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
The eye space coordinates in the camera frustum (a truncated pyramid) are mapped to a cube (the normalized device coordinates).
A perspective projection matrix can be defined by a frustum (glFrustum).
The distances left, right, bottom and top, are the distances from the center of the view to the side faces of the frustum, on the near plane. near and far specify the distances to the near and far plane on the frustum.
r = right, l = left, b = bottom, t = top, n = near, f = far
x: 2*n/(r-l) 0 0 0
y: 0 2*n/(t-b) 0 0
z: (r+l)/(r-l) (t+b)/(t-b) -(f+n)/(f-n) -1
t: 0 0 -2*f*n/(f-n) 0
A specification like this from you question:
glFrustum(-1, 1, -1, 1, -1, 1);
does not define a proper frustum, because the value for the near plane is negative and the value for the far plane is positive.
If you would check for OpenGL errors (by glGetError), then you would get an INVALID_OPERATION error.
OpenGL 4.6 API Compatibility Profile Specification; 12.1. FIXED-FUNCTION VERTEX TRANSFORMATIONS; page 501:
>
void Frustum( double l, double r, double b, double t, double n, double f );
the coordinates (l b −n)T and (r t −n)T specify the points on the near clipping plane that are mapped to the lower left and upper right corners of the window, respectively (assuming that the eye is located at (0 0 0)T). f gives the distance from the eye to the far clipping plane.
Errors
An INVALID_VALUE error is generated if n <= 0, f <= 0, l == r, b == t, or n == f.
I am making 3d open gl project which contain camera object as a shooting bullet but it is render with very big size and contain whole screen in white lines like this
i want to display object as a center of camera with small size how to do this
code is here
static GLdouble ort1[] = { -200, 200, -33, 140 };
static GLdouble viewer[] = { 525, 25, -180 };
static GLdouble up[] = { 0, 1, 0 };
static GLdouble objec[] = { 525.0, 25, -350 };
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
gluLookAt(viewer[0], viewer[1], viewer[2], objec[0], objec[1], objec[2], 0, 1, 0);
glMatrixMode(GL_PROJECTION);
//glOrtho(-1, 1, -1, 1, -1, 100);
glLoadIdentity();
//gluPerspective(fov, 1.333, n, f);
gluPerspective(fov, 1, 0.001, 1000);
//gluPerspective(50, screenWidth / screenHeight, 0.000001, 2000);
glPointSize(2.0);
glMatrixMode(GL_MODELVIEW);
//cube.drawFace(10, 20, 10, 22);
drawFlorr();
glPushMatrix();
glTranslatef(viewer[0], viewer[1], viewer[2]); // Translation to the camera center
glRotatef(camAngle * 57.2957795, 0, 1, 0); // Rotate to correspond to the camera
//glTranslatef(0.016, 0, -0.05); // Offset to draw the object
glutWireCone(0.005, 1, 20, 20);
glPopMatrix();
i am new in game prgramming and stuck in this problem ?
You're not setting up the projection matrix correctly.
You need to set the mode to GL_PROJECTION, then set the projection matrix to look at the target (shooter's object of attention) and have a perspective correct with right field of view.
Then set the modelview matrix, mode GL_MODELVIEW.
The gun sight needs to be placed so that it is looking at the camera, and the camera is looking at it. So on the line between the shooter's eyes and his object of attention, perpendicular to it. Do this in the modelview matrix, and call gluLookAt again, on the model.
(Ultimately projection and modelview get multiplied, but Open GL handles that for you).
Can someone enlighten me what the correct parameters to gluPerspective would be, for the wire cube to be visible similar to how glOrtho renders it in this example? (glOrtho works if you swap it for gluPerspective). As is, this displays a blank window.
I tried cargo-culting (a) many different values to gluPerspective, (b) different sized cubes, (c) different camera angles, (d) translating to different spots on Z; none seem to work. I didn't try adjusting glViewport, my understanding is that it's not needed for a simple example like this.
Also do I understand correctly that glOrtho, gluPerspective and glFrustum are normally mutually exclusive (they're all different ways of specifying a viewing volume) and all are equally usable with gluLookAt?
void display() {
glClearColor (1, 1, 1, 0);
glClear (GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glOrtho (0, 500, 0, 500, -100, 100);
gluPerspective (20, 1, 1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt (0, 0, 0, 0, 0, -1, 0, 1, 0); // these are the defaults
glColor3f(1, 0, 0);
glTranslatef (250, 250, 0);
glScalef (2, 2, 2);
glutWireCube (100.0);
glFlush();
}
void main (int argc, char **argv) {
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH) ;
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
int windowHandle = glutCreateWindow ("COMP 390 TME 2 Question 1");
glutSetWindow (windowHandle);
glutDisplayFunc (display);
glutMainLoop();
}
It is simply impossible to visualize the full cube with only modifying the perspetive parameters. What you have set up is the following, in top view, where +x is going right, +z is going down:
viewing direction ^
| +-+
+ | |
+-+
camera at cube, centered
origin around (250,250,0)
Now with an orthogonal view, you can actually include object behind the camera. But with a perspecitve one, this is not possible (at least not in a useful sense, you of course can shift the frustum around, but the projection center will then shift with it, so you basically would move the camera). All you can do is using an insanely wide field of view angle (near to 180 degree) to get part of the cube visble. But you cannot set up anything with gluPerspecitve() that making you see the front half of that cube.
I suggest you use some more normal projection and just look at the direction of the cube. If you change that lookat to
gluLookAt (0, 0, 0, 1, 1, 0, 0, 1, 0);
so that you look to the cube, you can use some usual perspective like
gluPerspective (90, aspect, 10, 1000);
Note that aspect should be the width of your viewport divided by the height. This is required so that the image is undistorted, and a square is acutally shown as a square.
The cube might appear very small, since it is only 4 units big, but 250 apart. YOu could of course use a smaller field of view angle ("zooming" with a camera), or just move the camera closer to the cube, or the other way around.