finding out triangles inside the projection plane - opengl

Lets assume the following three lines represent the vertices of a triangle in 3D space after projection transformation (these are just arbitrary values just for example):
0.0000000 0.0000000 0.9797980
0.1191754 0.0000000 0.9797980
0.0000000 0.1191754 0.9797980
If the projection plane is a square of length 2 (top left point (-1,1) and bottom right point (1,-1), and I have already performed clipping with respect to z-axis, z co-ordinates will be within [-1,1] by now. So, how will I determine the triangles which are totally outside the projection area like the image below ? Will they have all their x, y values of each vertex >1 or <-1 ?

No. Even if all vertices are outside of the visible area, the triangle can still be visible. This would, for example, be the case for this points:
-2 -2 0.5
2 2 0.5
2 -2 0.5
Although both, the x and y component are outside of [-1, 1] the triangle still covers half of the screen.
Actually, there is no easy solution to exactly determine which triangles are outside (or inside) the visible region. Depending on your needs there are several options:
If it is acceptable to classify some triangles as visible although they are not, you could test whether all points are outside the same side of the visible region. For example, if all points have x < -1 and so on.
If you really need a perfect classification, the Sutherland–Hodgman algorithm might be an option. When the output list is empty, the triangle is completely invisible.

Related

Perspective division explanation?

According to a number sources NDC differs from clip space in that NDC is just clip space AFTER division by the W component. Primitives are clipped in clip space, which in OpenGL is -1 to 1 along X, Y, and Z axes (Edit: this is wrong, see answer). In other words, clip space is a cube. Clipping is done within this cube. If it falls inside, it's visible, if it falls outside, it's not visible.
So let's take this simple example, we're looking from the top down on a viewing frustum, down the negative Y axis. The HALFFOV is 45 degrees, which means the NEAR and the RIGHT are both the same (in this case length 2). The example point is (6, 0, -7).
Now, here is the perspective projection matrix:
For simplicity we'll use an aspect ratio of 1:1. So:
RIGHT = 2
LEFT = -2
TOP = 2
BOTTOM = -2
NEAR = 2
FAR = 8
So filling in our values we get a projection matrix of:
Now we add the homogenous W to our point, which was (6, 0, -7), and get get (6, 0, -7, 1).
Now we multiply our matrix with our point, which results in (6, 0, 6.29, 7).
This point now (the point after being multiplied by the projection matrix, is supposed to lie in "clip space". Supposedly the clipping is done at this stage, figuring out whether a point lies inside or outside the clipping cube, and supposedly BEFORE division with W. Here is how it looks in "clip space":
From the sources I've seen the clipping is done at this stage, as it looks as above, BEFORE dividing by W. If you divide by W NOW, the point ends up in the right area of the clip space cube. This is why I don't understand why everyone says that perspective division is done AFTER the clipping space. In this space, prior to perspective division the point lies completely outside and would be judged to be outside the clipping space, and not visible. However after the perspective division, division by W, here is how it looks:
Now the point lies within the clip space cube, and can be judged to be inside, and visible. This is why I think perspective division is done BEFORE clipping, because if clipping space is in -1 to +1 in each axis, and the clipping stage checks against these dimensions, for a point to be inside this cube it must have already undergone division by W, otherwise almost ANY point lies outside the clipping space cube and is never visible.
So why does everyone say that first comes clipping space which is a result of the projection matrix, and ONLY then there is perspective division (division by W) which results in NDC?
In clip space, clipping is not done against a unit cube. It is done against a cube with side-length w. Points are inside the visible area if each of their x,y,z coordinate is smaller than their w coordinate.
In the example you have, the point [6, 0, 6.29, 7] is visible because all three coordinates (x,y,z) are smaller than 7.
Note, that for points inside the visible area, this is exactly equivalent to testing x/w < 1. The problems start with points in-front of the far-plane since they might get projected to the visible area by the homogeneous divide because their w-value is negative. As we all know, dividing by a negative number in an inequality would switch the operator, which is impracticable on hardware.
Further readings:
OpenGL sutherland-hodgman polygon clipping algorithm in homogeneous coordinates
Why clipping should be done in CCS, not NDCS
Why does GL divide gl_Position by W for you rather than letting you do it yourself?

Why Z is affected by the perscpective division?

I recently realized that OpenGL performs perspective division not only for x and y, but for z too.
In my understanding x /= w; and y /= w; would be enough. Of course, then we would need different projection matrixes.
So, why OpenGL does z /= w;? To make z-buffer more precise on short distances but less precise on long ones?
Mathematically, dividing all components is the correct way. That way, interpolating z in screen space linearily (perspective correct interpolation is not done for position data, as it is supposed to be interpolated in screen space).
The linear interpolation in sceen space of course means that looking at this in eye or object space, it appears nonlinear. It simply means for an object not parallel to the image plane, going one pixel to the left on the screen does mean going a variable amount along + or -z, depending on the distance - so the perspecitve actually does distort the z axis, too.
The side effect is that Z buffer precision is highest at the near plane, and that is actually a good thing for most scenes.
Using an "undivided" Z for depth test is called W buffer. But that means that the linear interpolation can't be used any more. However, with modern GPUs, that is not a too big issue.
The projection transformation has the role of moving the objects from World Space to Projection Space (Actually it will be the Camera Space before Projection space, but it's not in the scope ).
Visually every other space is a cube going from -1 to 1 , while The Projection space is a Pyramid section, with the near plane at Z0 and the FarPlane at Z1 (or Z-1 depending on right hand or left hand system) . So z gets morphed as well (unless you have an orthonormal projection). Z goes from 0 to 1 because it doesn't really make any sense for objects behind near plane to get into the rendering pipeline.
You mentioned yourself and in the comment as well about the Z Buffer precision. It's precision won't be changed, however, after Projection Transformation, the objects Z deltas will be less between objects near the far plane and more near the objects near the near plane (In less fancier words : the distance on the Z axis between objects close to the NearPlane will be increased, while the distance on the Z axis between objects near the FarPlane will be decreased).
This is why reducing the Near Plane and Far Plane distance sometimes fixes Z Fighting : The distance between far away objects will be reduced with less if the distance between the two planes is lesser.

OpenGL: Size of a 3D bounding box on screen

I need a simple and fast way to find out how big a 3D bounding box appears on screen (for LOD calculation) by using OpenGL Modelview and Projection matrices and the OpenGL Viewport dimensions.
My first intention is to project all 8 box corners on screen by using gluProject() and calculate the area of the convex hull afterwards. This solution works only with bounding boxes that are fully within the view frustum.
But how can a get the covered area on screen for boxes that are not fully within the viewing volume? Imaging a box where 7 corners are behind the near plane and only one corner is in front of the near plane and thus within the view frustum.
I have found another very similar question Screen Projection and Culling united but it does not cover my problem.
what about using queries and get samples that passes rendering?
http://www.opengl.org/wiki/Query_Object and see GL_SAMPLES_PASSED,
that way you could measure how many fragments are rendered and compare it for proper LOD selection.
Why not just manually multiply the world-view-projection with the vertex positions? This will give you the vertices in "normalized device coordinates" where -1 is the bottom left of the screen and +1 is the top-right of the screen?
The only thing is if the projection is perspective, you have to divide your vertices by their 4th component, ie if the final vertex is (x,y,z,w) you would divide by w.
Take for example a position vector
v = {x, 0, -z, 1}
Given a vertical viewing angle view 'a' and an aspect ration 'r', the position of x' in normalized device coordinates (range 0 - 1) is this (this formula taken directly out of a graphics programming book):
x' = x * cot(a/2) / ( r * z )
So a perspective projection for given parameters these will be as follows (shown in row major format):
cot(a/2) / r 0 0 0
0 cot(a/2) 0 0
0 0 z1 -1
0 0 z2 0
When you multiply your vector by the projection matrix (assuming the world, view matrices are identity in this example) you get the following (i'm only computing the new "x" and "w" values cause only they matter in this example).
v' = { x * cot(a/2) / r, newY, newZ, z }
So finally when we divide the new vector by its fourth component we get
v' = { x * cot(a/2) / (r*z), newY/z, newZ/z, 1 }
So v'.x is now the screen space coordinate v.x. This is exactly what the graphics pipeline does to figure out where your vertex is on screen.
I've used this basic method before to figure out the size of geometry on screen. The nice part about it is that the math works regardless of whether or not the projection is perspective or orthographic, as long you divide by the 4th component of the vector (for orthographic projections, the 4th component will be 1).

Orientation of figures in space

I have a sphere in my program and I intend to draw some rectangles over at a distance x from the centre of this sphere. The figure looks something below:
The rectangles are drawn at (x,y,z) points that I have already have in a vector of 3d points.
Let's say the distance x from centre is 10. Notice the orientation of these rectangles and these are tangential to an imaginary sphere of radius 10 (perpendicular to an imaginary line from the centre of sphere to the centre of rectangle)
Currently, I do something like the following:
For n points vector<vec3f> pointsInSpace where the rectnagles have to be plotted
for(int i=0;i<pointsInSpace.size();++i){
//draw rectnagle at (x,y,z)
}
which does not have this kind of tangential orientation that I am looking for.
It looked to me of applying roll,pitch,yaw rotations for each of these rectangles and using quaternions somehow to make them tangential as to what I am looking for.
However, it looked a bit complex to me and I wanted to ask about some better method to do this.
Also, the rectangle in future might change to some other shape, so a kind of generic solution would be appreciated.
I think you essentially want the same transformation as would be accomplished with a LookAt() function (you want the rectangle to 'look at' the sphere, along a vector from the rectangle's center, to the sphere's origin).
If your rectangle is formed of the points:
(-1, -1, 0)
(-1, 1, 0)
( 1, -1, 0)
( 1, 1, 0)
Then the rectangle's normal will be pointing along Z. This axis needs to be oriented towards the sphere.
So the normalised vector from your point to the center of the sphere is the Z-axis.
Then you need to define a distinct 'up' vector - (0,1,0) is typical, but you will need to choose a different one in cases where the Z-axis is pointing in the same direction.
The cross of the 'up' and 'z' axes gives the x axis, and then the cross of the 'x' and 'z' axes gives the 'y' axis.
These three axes (x,y,z) directly form a rotation matrix.
This resulting transformation matrix will orient the rectangle appropriately. Either use GL's fixed function pipeline (yuk), in which case you can just use gluLookAt(), or build and use the matrix above in whatever fashion is appropriate in your own code.
Personally I think the answer of JasonD is enough. But here is some info of the calculation involved.
Mathematically speaking this is a rather simple problem, What you have is a 2 known vectors. You know the position vector and the spheres normal vector. Since the square can be rotated arbitrarily along around the vector from center of your sphere you need to define one more vector, the up vector. Without defining up vector it becomes a impossible solution.
Once you define a up vector vector, the problem becomes simple. Assuming your square is on the XY-plane as JasonD suggest above. Then your matrix becomes:
up_dot_n_dot_n.X up_dot_n_dot_n.Y up_dot_n_dot_n.Z 0
n.X n.y n.z 0
up_dot_n.x up_dot_n.x up_dot_n.z 0
p.x p.y p.z 1
Where n is the normal unit vector of p - center of sphere (which is trivial if sphere is in the center of the coordinate system), up is a arbitrary unit vector vector. The p follows form definition and is the position.
The solution has a bit of a singularity at the up direction of the sphere. An alternate solution is to rotate first 360 around up, the 180 around rotated axis dot up. Produces same thing different approach no singularity problem.

OpenGL: 2D Vertex coordinates to 2D viewing coordinates?

I'm implementing a rasterizer for a class project, and currently im stuck on what method/how i should convert vertex coordinates to viewing pane coordinates.
I'm given a list of verticies of 2d coordinates for a triangle, like
0 0 1
2 0 1
0 1 1
and im drawing in a viewing pane (using OpenGL and GLUT) of size 400X400 pixels, for example.
My question is how do i decide where in the viewing pane to put these verticies, assuming
1) I want the coordinate's to be centered around 0,0 at the center of the screen
2) I want to fill up most of the screen (lets say for this example, the screen is the maximum x coordinate + 1 lengths wide, etc)
3) I have any and all of OpenGL's and GLUT's standard library functions at my disposal.
Thanks!
http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xml
To center around 0 use symmetric left/right and bottom/top. Beware the near/far which are somewhat arbitrary but are often chosen (in examples) as -1..+1 which might be a problem for your triangles at z=1.
If you care about the aspect ratio make sure that right-left and bottom-top are proportional to the window's width/height.
You should consider the frustum which is your volumetric view and calculate the coordinates by transforming the your objects to consider their position, this explains the theory quite thoroughly..
basically you have to project the object using a specified projection matrix that is calculated basing on the characteristics of your view:
scale them according to a z (depth) value: you scale both y and x in so inversely proportionally to z
you scale and shift coordinates in order to fit the width of your view