7
\$\begingroup\$

Can the rendering resolution of OpenGL and the window size (at least for the Windows OS) be separated? For example, I may only want to render at 400x300 resolution, but I want my window size to be 800x600. If so, how is this done?

\$\endgroup\$

2 Answers 2

7
\$\begingroup\$

Yes, but keep in mind the default frame buffer will always be the same size of the window. What you can do is to render your scenes internally into an off-screen (400x300) frame buffer, and then up-scale it to (800x600), you can do this by rendering this into a texture and applying it on a full screen quad, the advantage you will get is your shaders will run less often than with higher resolution. But you will lose quality due to scaling up which will need interpolating the original data in order to fill the bigger image.

\$\endgroup\$
1
\$\begingroup\$

One approach to this requirement is to adjust the projection matrix according to the different dimensions. To me you are describing a device dimension (i.e. 800x600) and virtual dimension (400x300)

Note: I use the word dimension instead of resolution and I am assuming an orthographic projection.

If this is the case, and you want to code for the virtual dimension, then you can do this by applying an aspect ratio correction to the projection matrix, without modifying the viewport matrix as I have seen in other examples.

For example:

// Calc ratio correction based on the two dimensions
float correction;
float deviceRatio = deviceWidth / deviceHeight;
float virtualRatio = virtualWidth / virtualHeight;
float xCorrection = deviceWidth / virtualWidth;
float yCorrection = deviceHeight / virtualHeight;

if (virtualRatio < deviceRatio) {
   correction = yCorrection;
} else {
   correction = xCorrection;
}

// Now when you calc your ortho projection--in this case centered--
// just divide by the correction
float left = -width / 2.0f / correction;
float right = width / 2.0f / correction;
float bottom = -height / 2.0f / correction;
float top = height / 2.0f / correction;

// Now set matrix which includes correction.
glm::mat4 projMatrix = glm::ortho(left, right, bottom, top, 0.1, 100.0f);

// Your viewport remains unchanged and is simply lower-left aligned
// For example
glViewport(0, 0, deviceWidth, deviceHeight);

// For your view matrix I simply "pull it back" a bit.
viewMatrix = glm::translate(viewMatrix, glm::vec3(0, 0, -1.0);

// And then finally you would multiply all your matrices together
// when rendering.
// For example
glm::mat4 mvp = projMatrx * viewMatrix * triangleModelMatrix;

// Then send "mvp" to your shader via some uniform
glUniformMatrix4fv(_mvpLocId, 1, GL_FALSE, glm::value_ptr(mvp));

// Now draw your object etc....

What the above code does is adjust the projection so that everything remains "square" rather than incorrectly stretched. I have seen examples where they manipulate the viewport instead.

My test code clears the background to orange and then renders a grey square that is the size of the virtual dimensions, this way I can see how the grey area adjusts when the device dimensions change, for example, moving between a phone and tablet. If your device is different than your virtual you should see some orange border(s) and if they are equal your grey virtual area should cover the orange exactly.

\$\endgroup\$
1
  • \$\begingroup\$ This is what I'm looking for ... I think. 😬 \$\endgroup\$
    – IAbstract
    Commented Jun 16 at 14:26

You must log in to answer this question.

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