Question

Allright - seems my question was as cloudy as my head. Lets try again.

I have 3 properties while configuring viewports for a D3D device: - The resolution the device is running in (full-screen). - The physical aspect ratio of the monitor (as fraction and float:1, so for ex. 4:3 & 1.33). - The aspect ratio of the source resolution (source resolution itself is kind of moot and tells us little more than the aspect ratio the rendering wants and the kind of resolution that would be ideal to run in).

Then we run into this:

// -- figure out aspect ratio adjusted VPs  -- 

m_nativeVP.Width = xRes;
m_nativeVP.Height = yRes;
m_nativeVP.X = 0;
m_nativeVP.Y = 0;
m_nativeVP.MaxZ = 1.f;
m_nativeVP.MinZ = 0.f;

FIX_ME // this does not cover all bases -- fix!
uint xResAdj, yResAdj;  
if (g_displayAspectRatio.Get() < g_renderAspectRatio.Get())
{
    xResAdj = xRes;
    yResAdj = (uint) ((float) xRes / g_renderAspectRatio.Get());
}
else if (g_displayAspectRatio.Get() > g_renderAspectRatio.Get())
{
    xResAdj = (uint) ((float) yRes * g_renderAspectRatio.Get());
    yResAdj = yRes;     
}
else // ==
{
    xResAdj = xRes;
    yResAdj = yRes;
}

m_fullVP.Width = xResAdj;
m_fullVP.Height = yResAdj;
m_fullVP.X = (xRes - xResAdj) >> 1; 
m_fullVP.Y = (yRes - yResAdj) >> 1; 
m_fullVP.MaxZ = 1.f;
m_fullVP.MinZ = 0.f;

Now as long as g_displayAspectRatio equals the ratio of xRes/yRes (= adapted from device resolution), all is well and this code will do what's expected of it. But as soon as those 2 values are no longer related (for example, someone runs a 4:3 resolution on a 16:10 screen, hardware-stretched) another step is required to compensate, and I've got trouble figuring out how exactly.

(and p.s I use C-style casts on atomic types, live with it :-) )

Was it helpful?

Solution

I'm assuming what you want to achieve is a "square" projection, e.g. when you draw a circle you want it to look like a circle rather than an ellipse.

The only thing you should play with is your projection (camera) aspect ratio. In normal cases, monitors keep pixels square and all you have to do is set your camera aspect ratio equal to your viewport's aspect ratio:

viewport_aspect_ratio = viewport_res_x / viewport_res_y;
camera_aspect_ratio = viewport_aspect_ratio;

In the stretched case you describe (4:3 image stretched on a 16:10 screen for example), pixels are not square anymore and you have to take that into account in your camera aspect ratio:

stretch_factor_x = screen_size_x / viewport_res_x;
stretch_factor_y = screen_size_y / viewport_res_y;
pixel_aspect_ratio = stretch_factor_x / stretch_factor_y;
viewport_aspect_ratio = viewport_res_x / viewport_res_y;
camera_aspect_ratio = viewport_aspect_ratio * pixel_aspect_ratio;

Where screen_size_x and screen_size_y are multiples of the real size of the monitor (e.g. 16:10).

However, you should simply assume square pixels (unless you have a specific reason no to), as the monitor may report incorrect physical size informations to the system, or no informations at all. Also monitors don't always stretch, mine for example keeps 1:1 pixels aspect ratio and adds black borders for lower resolutions.

Edit

If you want to adjust your viewport to some aspect ratio and fit it on an arbitrary resolution then you could do like that :

viewport_aspect_ratio = 16.0 / 10.0; // The aspect ratio you want your viewport to have
screen_aspect_ratio = screen_res_x / screen_res_y;

if (viewport_aspect_ratio > screen_aspect_ratio) {
    // Viewport is wider than screen, fit on X
    viewport_res_x = screen_res_x;
    viewport_res_y = viewport_res_x / viewport_aspect_ratio;
} else {
    // Screen is wider than viewport, fit on Y
    viewport_res_y = screen_res_y;
    viewport_res_x = viewport_res_y * viewport_aspect_ratio;
}

camera_aspect_ratio = viewport_res_x / viewport_res_y;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top