1
\$\begingroup\$

I'm trying to figure out how to perform tiled rendering of my 3d scene (OpenGL). The motivation is to cut the scene up into several textures, combining them into a single image for saving at a very high resolution, or for printing.

I've done some reading on this and apparently I just need to put appropriate parameters into my projection matrix for each tile in the scene. This is where I'm failing (miserably). I can't see where or what to use for it.

My perspective projection matrix is pretty standard, like this:

const T fov2 = Math::Tan(fov / 2), extent = (farPlane - nearPlane);

assert(fov2 != 0);

Matrix4x4<T> r;

r.m11 = 1 / (aspect * fov2);    r.m12 = 0;          r.m13 = 0;                                      r.m14 =  0;
r.m21 = 0;                      r.m22 = 1 / fov2;   r.m23 = 0;                                      r.m24 =  0;
r.m31 = 0;                      r.m32 = 0;          r.m33 = -(farPlane + nearPlane) / extent;       r.m34 = -1;
r.m41 = 0;                      r.m42 = 0;          r.m43 = -(2.f * farPlane * nearPlane) / extent; r.m44 =  0;

return r;

I tried an implementation of glFrustum (no longer available as I'm using core profile of course) as follows:

Matrix4x4<T> r(InitialiseAs::InitialiseIdentity);

r.m11 = 2.0f * nearPlane / (right - left);  r.m12 = 0;                                  r.m13 = (right + left) / (right - left);                    r.m14 = 0;
r.m21 = 0;                                  r.m22 = 2.0f * nearPlane / (top - bottom);  r.m23 = (top + bottom) / (top - bottom);                    r.m24 = 0;
r.m31 = 0;                                  r.m32 = 0;                                  r.m33 = -(farPlane + nearPlane) / (farPlane - nearPlane);   r.m34 = -(2.0f * farPlane * nearPlane) / (farPlane - nearPlane);
r.m41 = 0;                                  r.m42 = 0;                                  r.m43 = -1;                                                 r.m44 = 0;

return r;

But, alas I'm not sure what parameters I need to use for left, top, right and bottom when iterating across the scene, viewport or screen.

Can anyone assist me?

Edit: I found this example (unfortunately D3D) of someone doing something similar. The author seems to be just multiplying _11 and _22 by the width (scale up) and then modifying _31 and _32 according to the current tile position - iterating through the whole grid.

I did try this but I got a black screen of doom.

\$\endgroup\$
4
  • \$\begingroup\$ Not putting this as an answer because I'm not that fluent in it, but googling on "off axis projection" and "off center projection matrix" I found en.wikibooks.org/wiki/GLSL_Programming/Vertex_Transformations, "oblique perspective projection" on that page seems to be what you're looking for. \$\endgroup\$ Jan 23, 2015 at 17:41
  • \$\begingroup\$ Oh thanks for that. Haven't come across those terms before. \$\endgroup\$
    – Robinson
    Jan 23, 2015 at 17:49
  • \$\begingroup\$ Found an answer on stackoverflow (datenwolf's answer). \$\endgroup\$
    – Robinson
    Jan 26, 2015 at 15:19
  • \$\begingroup\$ @Robinson You can provide the solution in your own words here and how it applied to your situation. \$\endgroup\$
    – House
    Jan 26, 2015 at 15:39

2 Answers 2

1
\$\begingroup\$

From Datenwolf in this answer on stackoverflow:

We can render tiles with a 2-loop:

for m in 0 to M: 
    for n in 0 to N:
        render_tile(n, m)

where render_tile(n, m) starts by setting the viewport to the surface size (render target):

glViewport(0, 0, W_t, H_t), for tile width and height W_t, H_t

Somehow we've to shift the projection along with the tile (n, m) in the projection plane. The projection plane is also known as the 'near' plane. The extents of the near plane are right - left and top - bottom, so we're splitting the near plane into tiles of size (right - left) / N×(top - bottom) / M so that's what we need to use as shift step size:

shift_X = (right - left) / N
shift_Y = (top - bottom) / M

glMatrixMode(GL_PROJECTION)
glLoadIdentity()

switch Projection:
    case Ortho:
        glOrtho(left + shift_X * n, left + shift_X * (n+1), 
            bottom + shift_Y * m, bottom + shift_Y * (n+1),
            near, far)
    case Perspective:
        glFrustum( left + shift_X * n, left + shift_X * (n+1), 
            bottom + shift_Y * m, bottom + shift_Y * (n+1),
            near, far)

render_scene()

How we get left, right, top, bottom for perspective is:

right = -0.5 * tan(fov) * near
left = -right;
top = aspect * right
bottom = -top
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Note that glOrtho, glFrustum, and all gl matrix manipulations are deprecated \$\endgroup\$
    – Khlorghaal
    Jan 27, 2015 at 0:07
  • \$\begingroup\$ Yes, I've got my own implementation of glFrustum (and glm has one too). \$\endgroup\$
    – Robinson
    Jan 27, 2015 at 10:46
1
\$\begingroup\$

All you have to to is set glViewport then invert its transformation.

Create a matrix
s= tilecount; for(int x=0; x!=tilecount; x++) for(int y=0; y!=tilecount; y++)
[s 0 0 x]
[0 s 0 y]
[0 0 1 0]
[0 0 0 1]

And multiply it * your modelviewprojection

However this only works directly for ortho, for perspective, you'll have to w divide manually then apply this matrix.

\$\endgroup\$
5
  • \$\begingroup\$ Thanks for this. I tried making the above and multiplying the projection matrix by it and got a weird fish-eye projection. So where do I perform the multiply? My shader is vec4 position = Model_WorldView * vec4(attrib_Position, 1.0); gl_Position = Camera_Projection * position; \$\endgroup\$
    – Robinson
    Jan 26, 2015 at 11:39
  • \$\begingroup\$ Actually I got that backwards because i forgot glViewport, set your viewport appropriately then apply the inverse in the matrix \$\endgroup\$
    – Khlorghaal
    Jan 27, 2015 at 0:35
  • \$\begingroup\$ Edited answer. Also you should consolidate your uniforms on cpu as much as possible, so try to only do one matrix multiply. \$\endgroup\$
    – Khlorghaal
    Jan 27, 2015 at 0:38
  • \$\begingroup\$ I still don't quite get it though. I set my viewport to cover the area of the texture I'm rendering to. \$\endgroup\$
    – Robinson
    Jan 27, 2015 at 10:56
  • \$\begingroup\$ Oh, i just realized this will only work with an ortho projection. Do the w divide manually then apply this matrix, should work then. Experiment with a 2d scene/texture with no depth and see what you can get \$\endgroup\$
    – Khlorghaal
    Jan 29, 2015 at 10:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .