say I have given a plane P in eye coordinates in 4D space with origin (x,y,z,1) and normal vector (dx,dy,dz,0).
Is this still a plane in clip space?
Regards
Points which are co-planar in camera space will still be co-planar in 4D homogeneous clip space. Indeed, this is also true of points which are co-linear. Indeed, lines which are parallel in camera space are also parallel in 4D homogeneous clip space.
But remember: we're talking about 4D homogeneous clip space. So you're talking about 4-dimensional planes and 4-dimensional lines. That's ultimately not what gets rendered. You render by transforming from 4D clip space into 3D NDC space (and then to window space, but never mind that now).
In NDC space, points that were co-planar and co-linear in camera space will still be co-planar and co-linear in NDC space. But parallel lines will not be preserved by the division-by-W transformation.
Yes. In reality eyes see to a curve, but in computer graphics we simplify it to a truncated pyramid with a straight bottom / end plate.
Related
Where is the mapping to NDC?
According to my understanding, the projection matrix does two things: First, it clips the view space to form the frustum. It only keeps the vertices that fall into the frustum but clips others that fall outside. Second, it maps the coordinates within the clipped space to NDC [-1, 1].
But I only see that we create a frustum (to use for clipping) by define a perspective matrix with glm::perspective or glm::ortho. Where is the steps to do the mapping between frustum and NDC?
Or we just need to define the frustum and OpenGL will do the two steps for us automatically?
According to my understanding, the projection matrix do two things: first, it clipped the view space to form the frustum. It only keeps the vertice that's fall into the frustum but clipped others fall outside. Second, it maps the coordinates within the clipped space to NDC [-1, 1].
It does neither of these things.
A 4x4 matrix is just a transformation. A transformation by itself cannot clip anything. And while a matrix can transform coordinates into a [-1, 1] space, that's not necessarily what the clip space provided by the vertex shader will be. And it's certainly not the clip space used by 3D projection matrices.
The only mandated job of the vertex shader (or the last vertex processing shader stage) is to generate a clip-space position for each vertex. Clip-space is defined by OpenGL to be the 4D space where the XYZ components of the position are within the range [-W, W] are considered "visible". Here, "W" is the W component of the position. So for each XYZW, "visible" is defined as where the XYZ components are in the range of W.
The actual clipping of primitives happens after the vertex shader. Each primitive's vertices are clipped against the previously-defined 4D clip space.
A projection frustum is created by transforming positions into a clip-space such that those 4D positions outside of the frustum are outside of the [-W, W] range, and those inside of the frustum are inside of that range.
So it is not that the transformation clips anything; it merely sets up the data so that OpenGL's clipping system will clip things correctly.
Similarly, clip-space is not NDC space (unless the W component for the position is 1). NDC space is defined by taking the XYZ of a clip-space position and dividing it by that position's W component (and if W is 1, then this obviously changes nothing). Clip and NDC space are two separate spaces, and clipping happens before NDC space. You can conceptually think of clipping as being done against the [-1, 1] range of NDC space. After all, clip-space is on the [-W, W] range, so if you divide that by W, you get the range [-1, 1].
But it's still important to remember that clip space isn't NDC space.
I am confused about the position of objects in opengl .The eye position is 0,0,0 , the projection plane is at z = -1 . At this point , will the objects be in between the eye position and and the plane (Z =(0 to -1)) ? or its behind the projection plane ? and also if there is any particular reason for being so?
First of all, there is no eye in modern OpenGL. There is also no camera. There is no projection plane. You define these concepts by yourself; the graphics library does not give them to you. It is your job to transform your object from your coordinate system into clip space in your vertex shader.
I think you are thinking about projection wrong. Projection doesn't move the objects in the same sense that a translation or rotation matrix might. If you take a look at the link above, you can see that in order to render a perspective projection, you calculate the x and y components of the projected coordinate with R = V(ez/pz), where ez is the depth of the projection plane, pz is the depth of the object, V is the coordinate vector, and R is the projection. Almost always you will use ez=1, which makes that equation into R = V/pz, allowing you to place pz in the w coordinate allowing OpenGL to do the "perspective divide" for you. Assuming you have your eye and plane in the correct places, projecting a coordinate is almost as simple as dividing by its z coordinate. Your objects can be anywhere in 3D space (even behind the eye), and you can project them onto your plane so long as you don't divide by zero or invalidate your z coordinate that you use for depth testing.
There is no "projection plane" at z=-1. I don't know where you got this from. The classic GL perspective matrix assumes an eye space where the camera is located at origin and looking into -z direction.
However, there is the near plane at z<0 and eveything in front of the near plane is going to be clipped. You cannot put the near plane at z=0, because then, you would end up with a division by zero when trying to project points on that plane. So there is one reasin that the viewing volume isn't a pyramid with they eye point at the top but a pyramid frustum.
This is btw. also true for real-world eyes or cameras. The projection center lies behind the lense, so no object can get infinitely close to the optical center in either case.
The other reason why you want a big near clipping distance is the precision of the depth buffer. The whole depth range between the front and the near plane has to be mapped to some depth value with a limited amount of bits, typically 24. So you want to keep the far plane as close as possible, and shift away the near plane as far as possible. The non-linear mapping of the screen-space z coordinate makes this even more important, as that the precision is non-uniformely distributed over that range.
I was studying the rendering pipeline and when I got to the clipping stage it was explained that from the view (eye or camera) space we have to pass to the clip space, also called normalized device space (NDC), that is a cubic space from -1 to 1.
However, now I don't understand when the passage from this space to the screen coordinates space happens:
Right after clipping and before rasterization?
After rasterization and before scissor and z-test?
At the end just before writing on the frame buffer?
No, clip space and NDC space are not the same thing.
Clip space is actually one step away from NDC, all coordinates are divided by Clip.W to produce NDC. Anything outside of the range [-1,1] in resulting NDC space corresponds to a point that is outside of the clipping volume. There is a reason the coordinate space before NDC is called clip space ;)
Strictly speaking, however, NDC space is not necessarily cubic. It is true that NDC space is a cube in OpenGL, but in Direct3D it is not. In D3D the Z coordinate in NDC space ranges from 0.0 to 1.0, while it ranges from -1.0 to 1.0 in GL. X and Y behave the same in GL and D3D (that is, they range from -1.0 to 1.0). NDC is a standard coordinate space, but it has different representation in different APIs.
Lastly, NDC space to screen space (AKA window space) occurs during rasterization and is defined by your viewport and depth range. Fragment locations really would not make sense in any other coordinate space, and this is what rasterization produces: fragments.
Update:
Introduced in OpenGL 4.5, the extension GL_ARB_clip_control allows you to adopt D3D's NDC convention in GL.
Traditional OpenGL behavior is:
glClipControl (GL_LOWER_LEFT, GL_NEGATIVE_ONE_TO_ONE);
Direct3D behavior can be achieved through:
glClipControl (GL_UPPER_LEFT, GL_ZERO_TO_ONE); // Y-axis is inverted in D3D
Clip space and NDC (normalized device coordinates) are not the same thing, otherwise they wouldn't have different names.
Clip space is where the space points are in after the point transformation by the projection matrix, but before the normalisation by w.
NDC space is the space points are in after the normalisation by w.
http://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-GPU-rendering-pipeline-clipping
Camera space -->
x projection matrix --->
Clip space (before normalisation) --->
Clipping --->
Normalisation by w (x/w, y/w, z/w) --->
NDC space (in the range [-1, 1] in x and y)
Apparently, according to Apple, clip space is the same as NDC.
https://developer.apple.com/documentation/metal/hello_triangle
Quote:
"The main task of a vertex function (also known as a vertex shader) is to process incoming vertex data and map each vertex to a position in the viewport. This way, subsequent stages in the pipeline can refer to this viewport position and render pixels to an exact location in the drawable. The vertex function accomplishes this task by translating arbitrary vertex coordinates into normalized device coordinates, also known as clip-space coordinates."
Another quote from comments in sample code:
"The output position of every vertex shader is in clip space (also known as normalized device coordinate space, or NDC)."
Perhaps this is because the tutorial is in 2D? Misleading statements..
You can think the transition from clip space (-1 to +1 on every axis, for anything inside your image) to Screen Coordinates, also called viewport space (0 to ResX in X, 0 to rexY in Y, and 0 to 1 in Z, aka depth), as occurring just before the rasterization, after the vertex processor.
When you write a Vertex shader, you output is the projected position of the vertex in Clip space, but in the Fragment shader, each fragment comes with its own Screen coordinates and depth.
About Clip Space VS NDC
Clip Space is, as the name implies, is a Space, that is, a Reference Frame, a Coordinate System, that is, a particular choice of origin and set of three axis that you use to specify points and vectors.
Its origin is in the middle of the clip volume, its three axis are aligned as specified by the API. For example, the point with Cartesian coordinates (+1,0,0) of this Space appears on the right end of the image, and the point with Cartesian coordinates (-1,0,0) of the left.
NDC (Normalized Device Coordinates) is, as the name implies, a set of coordinates: they are the three Cartesian coordinates of a point in Clip Space. For example, take a point in Clip space of homogeneous coordinates (3,0,0,3), which you can also express as (30,0,0,30), and in many other ways, and which has Cartesian coordinates (1,0,0): its NDC are (1,0,0).
NDC space is clip space, NDC space to window space is done by hardware, happened after NDC and before rasterization.
There is API to set the width and height, the default value is same size with window size.
// metal
func setViewport(_ viewport: MTLViewport)
// OpenGL
void glViewport(GLint x, GLint y, GLsizei width, GLsizei height);
NDC space for OpenGL, xyz range [-1, 1]. For Metal, Z is from 0 to 1
NDC space is usually left hand system.
I have a question for opengl clip coordinate. For example, a triangle, three vetices, now have transformed to camera coordinate, multiply with perspective projection matrix to clip coordinate, begin to clip,
-w=<x<=w, -w=<y<=w, -w=<z<=w,
does x,y,z,w mean to each vertex's clip coordinate? So w may not be same in these three vertices?
Yes, that w will vary per vertex. Most people imagine the clip space as the cube [-1,1]^3. However, that is not the clip space, but the normalized device space (NDC). You get from clip space to NDC by doing the perspective divide, so dividing each vertex by it's w component. So, in NDC, that clip condition would transform to -1 <= x/w <= 1. However, the clipping cannot be done in NDC (withpout extra information).
The problem here is that points which lie behind the camera would appear in front of the camera in NDC space. Think about it: x/w is the same as -x/-w. With a typical GL projection matrix, w_clip == z_eye of the vertex. Also, a point that lies in the camera plane (the plane parallel to the projection plane, but going through the camera itself) will have w=0 and you can't do any clipping after that divide. The solution is to always do the clipping before the divide, hence the clip space is called "clip space"...
How can i render a textured plane at some z-pos to be visible towards infinity?
I could achieve this by drawing really huge plane, but if i move my camera off the ground to higher altitude, then i would start to see the plane edges, which i want to avoid being seen.
If this is even possible, i would prefer non-shader method.
Edit: i tried with the 4d coordinate system as suggested, but: it works horribly bad. my textures will get distorted even at camera position 100, so i would have to draw multiple textured quads anyways. perhaps i could do that, and draw the farthest quads with the 4d coordinate system? any better ideas?
Edit2: for those who dont have a clue what opengl texture distortion is, here's example from the tests i did with 4d vertex coords:
(in case image not visible: http://img828.imageshack.us/img828/469/texturedistort.jpg )
note that it only happens when camera gets far enough, in this case its only 100.0 units away from middle! (middle = (0,0) where my 4 triangles starts to go towards infinity). usually this happens around at 100000.0 or something. but with 4d vertices it seems to happen earlier for some reason.
You cannot render an object of infinite size.
You are more than likely confusing the concept of projection with rendering objects of infinite size. A 4D homogeneous coordinate who's W is 0 represents a 3D position that is at infinity relative to the projection. But that doesn't mean a point infinitely far from the camera; it means a point infinitely close to the camera. That is, it represents a point who's Z coordinate (before multiplication with the perspective projection matrix) was equal to the camera position (in camera space, this is 0).
See under perspective projection, a point that is in the same plane as the camera is infinitely far away on the X and Y axes. That is the nature of the perspective projection. 4D homogeneous coordinates allow you to give them all finite numbers, and therefore you can do useful mathematics to them (like clipping).
4D homogeneous coordinates do not allow you to represent an infinitely large surface.
Drawing an infinitely large plane is easy - all you need is to compute the horizon line in screen coordinates. To do so, you have to simply take two non-collinear 4D directions (say, [1, 0, 0, 0] and [0, 0, 1, 0]), then compute their position on the screen (by multiplying manually with the view-matrix and the projection matrix, and then clipping into viewport coordinates. When you have these two points, you can compute a 2D line through the screen and clip it against it. There, you have your infinity plane (the lower polygon). However, it is difficult to display a texture on this plane, because it would be infinitely large. But if your texture is simple (e.g. a grid), then you can compute it yourself with 4D coordinates, using the same schema like above - computing points and their corresponding vanishing point and connecting them.