17

I want to render a plane so that it looks as if it goes to infinity in all directions. I want the plane boundary in the distance to be the horizon.

Using a simple mesh does not work - the computer can't render infinitely many triangles. Even if this was possible, the camera frustum would cut out the distant polygons and create a gap between the plane boundary and the horizon.

A workaround is to compute the horizon mathematically: finding points on the plane, which also lie on the plane at infinity. Connecting these points and two corners of the viewport creates a trapezoid which represents the sought plane. However, this way the plane can not be lit properly, or applied a texture, or anything else which requires a fine triangulation...

Violin Yanev
  • 1,507
  • 2
  • 16
  • 23

2 Answers2

22

You can draw an infinite plane using the standard rasterization pipeline. The homogeneous coordinates it uses can represent "ideal" points (otherwise known as vanishing points or points at infinity) just as happily as regular Euclidean points, and likewise it is perfectly practical to set up a projection matrix which places the far plane at infinity.

A simple way to do this would be to use one triangle per quadrant, as follows:

vertices [x,y,z,w], for drawing an (x,y) coordinate plane, at (z==0):
  0: [ 0, 0, 0, 1 ]
  1: [ 1, 0, 0, 0 ]
  2: [ 0, 1, 0, 0 ]
  3: [-1, 0, 0, 0 ]
  4: [ 0,-1, 0, 0 ]

draw 4 triangles using indices:
  (0,1,2); (0,2,3); (0,3,4); (0,4,1)

If you want a test pattern (like an infinite checkerboard), you will have to deal with the fact that stretching your triangles to infinity will distort any standard texture. However, you can write a pixel shader that determines the color based on the actual 3D point (i.e., use x and y from the worldspace (x,y,z) coordinates), ignoring the (distorted) texture coords altogether.

You could choose between two constant colors based on parity (for a checkerboard), or tile a texture by sampling it based on the fractional part of your chosen coordinates.


Note that OpenGL's clip space is [-1..1] for each of x, y, and z. You can compute the appropriate projection matrix by evaluating the limits as far clip distance f increases without bound:

clip coords: [x]  =  [ n/r             ]  * view coords [x]
             [y]     [     n/t         ]                [y]
             [z]     [          -1 -2n ]                [z]
             [w]     [          -1   0 ]                [w]

Where (as in the link): n is the near clip plane, r is half the frustum width at the near clip plane, and t is half the frustum height at the near clip plane.

I have not tested the above matrix, so it's worth what you paid for it. Also be aware that the depth value will lose its precision as you approach infinity...

Although, the precision at closer distances will be likely be fine -- e.g., at any given distance, the depth resolution in the (near:infinity) case should be about 10% less than the case where the (near:far) ratio is (1:10).

comingstorm
  • 25,557
  • 3
  • 43
  • 67
  • +1 for this. I'd have written similar, but you beat me to it. – datenwolf Oct 19 '12 at 10:17
  • This looks exactly like what I'm looking for! I gave you +1, and I'll accept your answer if it works. My concern is that using the pixel-shader approach will create artifacts... I want to tile the floor with a wireframe grid, but if I render it with a pixel shader, woudln't it be jagged? – Violin Yanev Oct 21 '12 at 12:16
  • A wireframe grid tends to alias no matter how you draw it, simply because it is so skinny. You can fight this tendency using a mip-mapped texture to draw your wireframe, and further by turning on anisotropic filtering. – comingstorm Oct 22 '12 at 18:13
  • Fair warning: I suspect the details of actually using the mip-map + aniso may be a bit more fiddly than usual -- because you are generating your texture coordinates "by hand", you may need to do a bit more work to hook everything up properly. But it shouldn't really be too complicated; think of it as educational 8^) – comingstorm Oct 23 '12 at 00:55
  • 1
    I tried to do as you suggested, but there is a problem: when the camera is close to the ground plane (but still above), it can see "below" the plane, as if I was swimming on the surface of a lake. Here is a screenshot: https://dl.dropbox.com/u/6282693/device-2012-11-01-202949.png – Violin Yanev Nov 01 '12 at 19:31
  • 1
    That looks like it could be the near clip plane. Try tweaking the near clip distance while the camera remains otherwise stationary: if the edge of the hole moves, that's your problem. If you want a usable depth map, you will always need a near clip plane; you may need to reduce the near clip distance, or simply avoid getting too close to an object you want to draw... – comingstorm Nov 01 '12 at 20:44
3

Your viewing frustum, which is a capped pyramid built from 4 clip planes on the sides and on the top/bottom, and on a near and a far plane is "infinite" (it is not infinite, but since you cannot see anything outside the frustum, it is as infinite as it can be).

Drawing the bottom side of your capped pyramid (a quad, or two triangles) therefore is a plane that is "infinite", going to the horizon. Or, for that matter, any quad with its corner points on the near and far planes.

Damon
  • 67,688
  • 20
  • 135
  • 185
  • This is true, but the limited frustum just creates the *illusion* of infinity. If you compute the horizon mathematically and render it on top of the scene, it will be not the same as the horizon resulting from the rendered plane. My application requires mathematical exactness, not just visual appearance. – Violin Yanev Oct 21 '12 at 12:20