XNA: Orthographic window resizing without stretching - c#

I've been working on a game project for Windows for a while now. I used to have a static 1600 x 900 resolution, which worked fine for me. But not so much for some of my beta testers.
This got me looking into resolution independence in XNA-based games. I've gone through a lot of the Virtual Resolution systems that draw everything on a RenderTarget2D and stretch that to fit the window size. But that doesn't work for me.
What I want to know is how I could calculate a similar projection matrix as to what Terraria uses. For those who don't know how it works in terraria (now days anyway, I think it used to be different) is that once you resize the game window, you see more stuff on the screen.
Currently my projection matrix is defined as such:
Projection = Matrix.CreateOrthographicOffCenter(-25 * _graphics.Viewport.AspectRatio,
25 * _graphics.Viewport.AspectRatio,
-25, 25,
-1, 1 );
This works when the window's size changes horizontally. I see more stuff sideways and everything is fine. But once I resize the window vertically, everything clamps together.
Is there a way to calculate the projection matrix so that it'd allow me to resize the window both horizontally and vertically?
EDIT:
I am using a camera class indirectly. Everything is in Farseer Physics coordinate space, and when something is getting drawn to the screen, its converted via Viewport.Unproject().
SOLUTION:
As gareththegeek pointed out in the comment section of the chosen answer, my particular projection matrix I was after is formed like this:
Projection = Matrix.CreateOrthographicOffCenter(-(_graphics.Viewport.Width / 1600f * 44),
(_graphics.Viewport.Width / 1600f * 44),
-(_graphics.Viewport.Height / 900f * 25), (_graphics.Viewport.Height / 900f * 25),
-1, 1);

If you include the resolution of the display in the orthographic projection you can achieve the desired effect I think.
Projection = Matrix.CreateOrthographicOffCenter(
0.0f, _graphics.Viewport.Width,
_graphics.Viewport.Height, 0.0f,
-1.0f, 1.0f);

Related

How to design a game for multiple resolutions?

Trying to figure out a good solution for handling different resolutions and resizing in a 2D side-scrolling shooter game build with OpenTK (OpenGL).
Ortho is setup as follows.
private void Setup2DGraphics()
{
const double halfWidth = 1920 / 2;
const double halfHeight = 1080 / 2;
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, -1.0, 1.0);
GL.MatrixMode(MatrixMode.Modelview);
GL.LoadIdentity();
}
Ortho fixes to 1920*1080 to keep the ortho fixed size. Changing size would change game behaviour. Objects movement is set to pixels/sec etc.
public void ResizeWindow(int width, int height)
{
var screenSize = GetOptimalResolution(width, height);
var offsetHeight = screenSize.Y < height ? (height - screenSize.Y) / 2 : 0;
var offsetWidth = screenSize.X < width ? (width - screenSize.X) / 2 : 0;
// Set the viewport
GL.Viewport((int)offsetWidth, (int)offsetHeight, (int)screenSize.X, (int)screenSize.Y);
}
GetOptimalResolution returns the viewport size in order to maintain a 16:9 aspect ratio. Example: If screensize is 1024*768, it resturns 1024*576 (shrinking height). It then places the ortho higher in the viewport using half of the height difference as offset. This results in black bars above and below the windows.
This setup works. It prevents aspect ratio issues on all resolutions. However I'm questioning myself if this is the right way to do it? The issues I can think of with this design:
- On resolutions lower then 1920*1080, the view is scaled down. This has an effect of how sprites look. For example, text starts to look horrible when scaled down.
- If turning down resolution for performance, will this have an effect if the ortho stays the same size?
Did a lot of searching on this topic but so far the only things I can find is plain instructions on how to perform actions, rather then to build solutions. I also found out that using Mipmap's might solve my scaling issue. However the question remains, am I on the right track? Should I look at the aspect ratio problem from a different angle?
For example, text starts to look horrible when scaled down.
Don't use textures for text. Use a technique like signed distance fields for rendering clear text at any resolution.
For artwork, the ideal would be to have resolution specific artwork for a variety of common resolutions / DPIs. Failing that, mipmaps will drastically improve the quality of the rendered texture if it's scaled down from the source texture image.
It also might be easier to work the problem if you stop using pixel coordinates to do stuff. The default OpenGL screen coordinates are (-1,-1) lower left to (1,1) upper right. However, you can alter these using an ortho transform to account for aspect ratio like this
const double aspect = windowWidth / windowHeight;
if (aspect > 1.0) {
GL.Ortho(-1 * aspect, 1 * aspect, -1, 1, -1.0, 1.0);
} else {
GL.Ortho(-1, 1, -1 / aspect, 1 / aspect, -1.0, 1.0);
}
This produces a projection matrix that is at least 1 in both dimensions. This lets you treat the screen as a 2x2 square with the origin in the middle, and any additional stuff the viewer can see because of the aspect is cake.

Trying to draw textured cube primitive in XNA with quads

Right now I'm using XNA 4.0 with Windows Phone Developer Tools to create a textured cube using a predefined quad class on MSDN.
The front/back/left/right faces of the cube will draw fine (for every cube that I make), however the top and bottom faces won't render. The rasterizer state's cull mode is set to none and the quad that represents the top face exists, and it seems as if it would draw, but for some reason it won't.
Is there a problem with my code, or is this not happening for some other reason?
Here's the code:
Game1.cs: http://pastebin.com/RHU7jNXA
Quad.cs & Cube.cs: http://pastebin.com/P9gz5q4C
It's because your top and bottom faces have a height to them. They should have 0 height.
Here you are passing in a value as height:
Faces[4] = new Quad(topFaceOrigin, Vector3.Normalize(Vector3.Down), Up, Size, Size);
And then here in Quad constructor it's being used to give incorrect LowerLeft & LowerRight values:
LowerLeft = UpperLeft - (Up * height);
LowerRight = UpperRight - (Up * height);
I would recommend changing how you create all your quads; each face really should have different parameters. Right now all your faces are passing in practically the same stuff.

xna depth of field increase? i see backround color!

i created a scene in 3d max which is pretty huge, the thing is , this represents the galaxy and i will have a camera in there , but because its so big, the camera's view distance isnt covered by all the field , causing the background to be displayed at places, so how can i increase the view distance of my camera to view all the field? This is in XNA, visual studio.
aspectRatio = ((float)viewport.Width) / ((float)viewport.Height);
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(40.0f),
this._aspectRatio,
1.0f,
10000.0f); // Increase this number to increase the "depth"

How to scale texture2d in XNA with window resizing

I'm developing an UI for a project for school, and I've tried similar methods to scaling my texture as listed here, but here is the issue:
Our project is developed at 1440 x 900, so I've made my own images that fit that screen resolution. When we have to demo our project in class, the projector can only render up to 1024 x 768, thus, many things on the screen goes missing. I have added window resizing capabilities, and I'm doing my scaling like this. I have my own class called "button" which has a texture 2d, and a Vector2 position contruscted by Button(Texture2d img, float width, float height).
My idea is to set the position of the image to a scalable % of the window width and height, so I'm attempting to set the position of the img to a number between 0-1 and then multiply by the window width and height to keep everything scaled properly.
(this code is not the proper syntax, i'm just trying to convey the point)
Button button = new Button(texture, .01, .01 );
int height = graphicsdevice.viewport.height * button.position.Y;
int width = graphicsdevice.viewport.width * button.position.X;
Rectangle rect = new Rectangle(0,0,width, height);
sprite.being()
sprite.draw (button.img, rect, color.white);
sprite.end
it doesn't end up scaling anything when i go to draw it and resize the window by dragging the mouse around. if i hard code in a different bufferheight and bufferwidth to begin with, the image stays around the same size regardless of resolution, except that the smaller the resolution is, the more pixelated the image looks.
what is the best way to design my program to allow for dynamic texture2d scaling?
As Hannesh said, if you run it in fullscreen you won't have these problems. However, you also have a fundamental problem with the way you are doing this. Instead of using the position of the sprite, which will not change at all during window resize, you must use the size of the sprite. I often do this using a property called Scale in my Sprite class. So instead of clamping the position of the sprite between 0 and 1, you should be clamping the Size property of the sprite between 0 and 1. Then as you rescale the window it will rescale the sprites.
In my opinion, a better way to do this is to have a default resolution, in your case 1440 x 900. Then, if the window is rescaled, just multiply all sprites' scaling factors by the ratio of the new screensize to the old screensize. This takes only 1 multiplication per resize, instead of a multiplication per update (which is what your method will do, because you have to convert from the clamped 0-1 value to the real scale every update).
Also, the effects you noticed during manual rescale of the sprites is normal. Rescaling images to arbitrary sizes causes artifacts in the rendered image because the graphics device doesn't know what to do at most sizes. A good way to get around this is by using filler art during the development process and then create the final art in the correct resolution(s). Obviously this doesn't apply in your situation because you are resizing a window to arbitrary size, but in games you will usually only be able to switch to certain fixed resolutions.

DirectX meshes not being displayed properly after switching view and projection matrices

In my program, the meshes were being displayed properly, but when I change the device.transform.view and the device.transform.projection matrices from the left handed to the right handed system, the meshes are not displayed properly anymore, i.e the back faces are being illuminated and the front faces are transparent!
Does anyone have an idea what more needs to be changed to have a proper display
Original matrices:
device.Transform.View = Matrix.LookAtLH(vFrom, vAt, vUp);
device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, fAspect, 0f, 100f);
modification:
device.Transform.View = Matrix.LookAtRH(vFrom, vAt, vUp);
device.Transform.Projection = Matrix.PerspectiveFovRH((float)Math.PI / 4, fAspect, 0f, 100f);
Well I'd expect both of those matrices to fail terribly on the basis that you set the near plane to 0. It really ought to be some small epsilon like 0.0001f.
The other thing to bear in mind is that by swapping the handedness of the system you are most likely inverting the winding order of the tris.
You need to set the culling render state to clockwise instead of anti/counter-clockwise.
ie
dxDevice.SetRenderState( RenderState.CullMode, Cull.Clockwise );

Categories