My problem is as follows:

I want to use a single render target texture for drawing 16 viewports where I want to display the 16 different combinations of the marching squares algorithm with my 3D tiles. Each viewport it's supposed to have its own camera and be located at a custom distance from the center of each tile set and this camera should be able to rotate around their center, zoom in and out, etc.

My current issue is that my current projection setting is placing the center of the camera view in the center of the target texture, instead of locating the center of the view in the center of the rectangle corresponding to that viewport.

I assumed I just had to push a translation to the final transform in order to translate the image within the normalized screen coordinates. However, when I tried to do this, it didn't work. How should I do this?

NOTE: Currently I achieved it by using the direct3d viewports, but I'd like to know how should I do if I want to use my custom transform pipeline.

  • \$\begingroup\$ Presumably you want triangles to be clipped to the boundaries of each sub-image, right? If so, setting the D3D viewport would be the normal way to do this, as that handles both the transform and the clipping. If you don't care about clipping, then multiplying your projection matrix by a translation ought to do the job. \$\endgroup\$ Jul 15, 2013 at 20:17
  • \$\begingroup\$ @NathanReed Hi Nathan, thanks for your help. I'm using the scissor test for clipping as I already had exposed by the abstraction interfaces, so I thought I would be missing only a transformation to do the job. I think I'm close to get it: now I added a division to scale the normalized target space to viewport space, which scaled the image the way I want (as I get the same size as by using d3d viewports), but when I try to add a translation I get only a distorted FoV. It seems I'm missing some operation but I'm not sure what it is. \$\endgroup\$ Jul 16, 2013 at 6:28
  • \$\begingroup\$ Can you post your code for calculating the matrix? \$\endgroup\$ Jul 16, 2013 at 6:30
  • \$\begingroup\$ @NathanReed I definitively solved it because you said I was on the right path, then I tried again with renewed hopes until I got it working. Thank you. \$\endgroup\$ Jul 16, 2013 at 7:21

2 Answers 2


As you say, this is exactly the sort of thing which viewports are intended to deal with. Setting up separate viewports would make all of this easy, and is the recommended way to handle this sort of rendering.

However, since you want to know how to do it using a single full-window viewport and instead use scissoring to restrict rendering to one bit of the screen (you could also do this with a stencil buffer, if you wanted something non-rectangular), then what you need to do is to multiply a translation matrix in front of your projection matrix. The translation you want is the offset from the middle of the window to where you want the projection center to be, measured in pixels. In effect, you're just offsetting the whole rendered image. You then use that combined pixel offset * projection matrix as your projection matrix, and proceed as normal.

This is the same method that people writing code for head mounted displays (VR goggles, etc) offset the rendered images so that each eye has a wider field of view further toward the ears than toward the nose; the image is biased so that the center of each eye's view is closer to the nose from that eye's point of view.

(Note that doing this can result in clipping issues, since you end up rendering a view frustum which is offset from the frustum you'd assume was visible based on a naive examination of the camera's matrix. In this specific instance, it should be fine. But if you decided to, for example, offset a whole-screen render by 50 pixels to the left, you'll be drawing 50 pixels further to the right than your clipping code thinks you will be, and so it may choose to throw out some models which actually would have been visible on-screen)

  • \$\begingroup\$ Thank you, I just solved it but your answer still adds! The hmd stuff is something I didn't think about before, definitively interesting. I'll be working with these kind of transforms for a while so everything helps! \$\endgroup\$ Jul 16, 2013 at 7:31

It seems I was missing some scaling. I get the code working by adding the following transformations after the projection transform.

GMatrix4 trans1;
float TargetWidth = (vp->nWidth*4.0f),     // our target is 4*4 viewports size
    TargetHeight = (vp->nHeight*4.0f); // 
switch( m_ProjectionType )
    m_mProjection.FieldOfView( pCameraData->fAngle, vp->nWidth/(float)vp->nHeight, pCameraData->fNearPlane, pCameraData->fFarPlane );

    // Scale to viewport units.
    trans1.Scale( vp->nWidth/TargetWidth, vp->nHeight/TargetHeight, 1.0f );

    // Move our center to the top-left screen corner.
    trans1._41  -= 1.0f;
    trans1._42  += 1.0f;

    // Add viewport offset in screen coordinates.
    trans1._41  += vp->x/(TargetWidth/2);
    trans1._42  -= vp->y/(TargetHeight/2);

    // Add offset from the top-left corner of the viewport to its center.
    trans1._41  += vp->nWidth/(TargetWidth);
    trans1._42  -= vp->nHeight/(TargetHeight);

    m_mProjection *= trans1; // push transform after projection.

Thank you!


You must log in to answer this question.

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