Projection Matrix

BlitzMax Forums/BlitzMax Beginners Area/Projection Matrix

Smurftra(Posted 2006) [#1]
Not sure if this is the right place to ask.

But i was reading the thread about indiepath's modules and was wondering:

what is that thing called projection matrix, what is its purpose, what does it eat in winter?

Thank you,

Smurftra


TartanTangerine (was Indiepath)(Posted 2006) [#2]
If you know Blitz3D then think of the Matrix as your Camera. Basically the matrix defines your view on the digital world - a matrix can make your image look constant across multiple resolutions/ratios.


Smurftra(Posted 2006) [#3]
Ok this triggers a new question for me:

(I'm a blitzmax user but i understand the 3d concept you explained)

I'm making a 2d game. So far i've settled for a 800x600 resolution.

If i used the projection matrix, i could make the resolution whatever the user wants because everything would be scaled accordingly (this is what i understand from your explanation)

Now, lets say in my game i have a sprite that is a 32x32 square fill with blue, with a white line on the four edge (1 pixel width). I guess if the user lowers the resolution the sprite might be distorted so we dont see the white line? Same if we up the resolution one edge could stay 1pixel while the other edge becomes 2 pixel width?

I'm not sure how to explain, what i mean is does a projection matrix try to ensure that details in the graphics stay visible or is it just a zoom/unzoom algorithm?


H&K(Posted 2006) [#4]
In Bmax, if you are using the Standard stuff you can simply use setScale(Float,float) to get the same effect.

Lets say your normal screen is 800 by 600, this is scale 1.0,1.0. If you suddenly wanted a resolution of (say), 400 by 300, you SetScale (0.5,0.5). Now when you DrawLine from 0,0 to 800,600, the computer draws 0,0 to 400,300, so it looks the same. And for 1024,768 setscale (1.28,1.28)

You really need to have planned to do this, because it doesnt work with DrawPixmap, only with DrawImage.


Smurftra(Posted 2006) [#5]
Ok so my question is answered: its sure to give ugly results as its not intelligent (meaning there are good odds it will skip a 1 pixel width line if you half the resolution)


H&K(Posted 2006) [#6]
No, I dont think it will, my understanding is that this is happening anyway, and that the screen driver is making the value Percentage values.

That is the screen coords you give are already being converted to numbers between 0 and 1.0

But simply try it. Increae the screen size, set a scale, and have a look.


Smurftra(Posted 2006) [#7]
ok, use this file:



and use this code (remember to replace the line where it loads the image to your image's path):

switch between:

graphics 800,600
SetScale 1,1

and:

graphics 400,300
SetScale 0.5,0.5


Local Img:TImage

Img = LoadImage ("C:\TEMP\BlitzMax\Garbage\test1.bmp")

While not KeyHit(KEY_ESCAPE)
DrawImage img, 50,50
Flip 0
Wend


----------------------------

So in 800x600 the picture is drawn ok (1 black line, 1 red line, and so on)

in 400x300 the picture is not drawn ok (only red line are drawn because it skips 1 in every line)

Now there are many intelligent approach to this problem, i was wondering if the projection matrix took that into account.

Its because of that problem that i decided that my game would be 800x600 and thats too bad for those who want higher res cuz it would be too much work.

smurftra


H&K(Posted 2006) [#8]
Thats what would happen whatever you did, either that or the red and the black would make a new red half as bright.

No matrix method, no matter how brilliant could make detail smaller than a pixel appear correct. To be honest I think that you are just expecting too much. All the projection matrix would do, is scale depending on Depth.

Explain to me exactly how you would like the Redbox drawn. Unlike you who have just stuck to one resolution, I have simply not used stupid textures. (ie one like that one)

Edit: Thats sounds nasty. But what I mean is that I dont use a texture that has been specificaly designed not to work.


Smurftra(Posted 2006) [#9]
Ok, i does sound nasty ;)

1) I'm not asking for much since im not asking that it works like i expect. I figured: why use a proj matrix if i simply can use Scale. I dont see the point. So i though that maybe it is more intelligent than a simple scale.

2) There are several ways to acheive what im talking about:

A) Scale with 'blur'
B) Scale while keeping details. (look for 1 pixel width lines and keep them and scale the areas that are bigger than that). It is time consuming but there are methods that make it fast enough to implement in real time, and you can always pre-render your sprites.



As far as stupid images, the image i linked too was just to make my point clear.

Now imagine yuo make a game that is 'cartoonish'. In cartoons, characters/objects often have a black outline. If you were to make your sprite and make that outline 1 pixel width, half of it would disapear making it look weird.

I'm always willing to learn so, could you help me out and tell me a way to avoid that in the making of the sprites?

Like, how would you do a game like mario bros and assure that mario doesnt lose his mustache? (without making the sprites ugly my having all the lines be 2pixel width, cuz then you lose the possibility of fine details).

1 idea i think its to make the sprites for the smallest possible resolution, scaling upwards doesnt lose info. But a doubled sprite looks kinda pixelated.

Vector graphics maybe? Pre-rendered at game boot?

Smurftra


H&K(Posted 2006) [#10]
1) Yep, A projection matrix is just, (in basic terms;- so dont flame me), a way to auto scale with depth.

2) (Just using your stupid Image ;)

a) Blur to what? It cannot blur less than a pixel, so a pixel is half red half black. so... Red or darker red. But all the pixels would blur the same, so you would just get the same as in the test.
b) You cannot. The detail on your image is too fine to keep any detail when shunk

Its not a stupid image in the sence of at least it is an image, But its an image you wouldnt use.

1) You dont want to make your game on a lower resotution. So why are you saying "Look, it looks bad on a lower res"?

2) I am using it, with 1024 *768 as MIN,
If I wanted "a mario" then His BlackOut Line would be bigger than 1 pixel at 1024*768 (Or Pos 512,384), and then scaled up with blend. I accept you dont want to do it. And fair enough your doing a Pre-sprite game, where as Im building them at run time.

But the image you posted is stupid. It cannot be scalled down at all and keep any detail in any scaling engine. It is at the lower limit of its size.


Smurftra(Posted 2006) [#11]
of course its stupid i wouldnt use such an image it was just to show what i meant, hence the other idea with the character with a black outline, that one would like to keep at 1 pixel width no matter the res


Abomination(Posted 2006) [#12]
Why enable the user to choose an other resolution, if the result will look the same?
Unless you want to zoom certain areas and keep others the same, as in f.e. Settlers IV?


H&K(Posted 2006) [#13]
ha Yes like settlers, but whereby the "Info" bit can contain more information at higher resoluions, but the game screen looks the same. (Or Homeworld, etc) As apposed to sat Diablo which at higher game res gives "more" game screen


Smurftra(Posted 2006) [#14]
Possibly to accomodate LCD user where res <> native res = ugly


Dreamora(Posted 2006) [#15]
Why let the user choose: 800x600 looks on my screen like a game boy window as my native is 1680x1050 with stretching disabled to prevent the crappy effect that happens when scaling 4:3 -> 16:10

games not allowing to choose the res find their way of my system faster than I can download them with 3MB/s at university.


Smurftra(Posted 2006) [#16]
dream:

i never toyed with widescreen monitors. so i have a question: if you have a game that is 800x600 full screen, will it still look ok (like having a portion on both side of the screen that stays black) or will it be stretched (convering the entire screen)?


Gabriel(Posted 2006) [#17]
It's my understanding that it will do both of your suggestions on different monitors. Some will leave borders left and right, and some will stretch it, making it look nasty.


FlameDuck(Posted 2006) [#18]
This is not only an issue with widescreen LCDs. It is also a problem with most other LCDs that have a 5:4 aspect ratio (like say one with a native resolution of 1280x1024).


Blitzplotter(Posted 2006) [#19]
This answers some hassles I was having with successfully doing image manipulation in a 'simple 'BMax exe, but upon trying to incorporate it into a more complex framework I couldn't fathom why my image manipulation was not working.


ImaginaryHuman(Posted 2006) [#20]
I haven't seen much mention of the viewport in this discussion but it's very closely tied into the projection matrix and I think it needs a clearer description.

BlitzMax's SetViewport() is misleading. It is used to stencil areas of the screen or window so that you can draw only to particular regions of your display. The way it is presented it has nothing to do with changing the size of the display or the size of the objects within the display. SetViewport() could otherwise be called SetDrawingArea() or SetScissorBox() or SetCanvasRectangle() etc. If you look at the OpenGL code for SetViewport() it doesn't even contain the glViewport() command to change the viewport, all it does is set a clipping window to make sure only pixels within the defined area are drawn. It's a practical use of `setting a viewport` and presumably because BRL doesn't want users to have to mess around with the more complicated scenario of actually setting up a real viewport. To know what a real viewport is for you need to know what the projection matrix is for.

The projection matrix contains a perspective transformation operation that converts the apperance of objects from 3D coordinates to 2D. The values in the matrix actually define the `shape` of 3D space ie how `wide an angle of view' you have vertically and horizontally - your field of view. It defines this `volume` of 3D space, which is called a frustum (frustrum?), as a pyramid whose base is flat against the camera and whose peak is the vanishing point in perspective, off in the distance. The projection matrix is therefore what defines the amount of perspective effect that the game world will be viewed with. You can set it up to seem like a wide angle lense or a narrow zoom lense or something close to `normal real life perspective`.

You can also set it up to have no perspective at all, which is called an orthographic projection. In the orthographic projection, rather than lines of sight converging at a vanishing point, they are all in parallel and just go straight out, so no matter how far in the `distance` something is, it doesn't get any smaller - as if there is no perspective at all. An orthographic projection is ideal for 2D games and gives you the pixel-perfect representation of objects on a totally flat surface with no warping at the corners of the `camera lense`. So the projection matrix contains the definition of 3D space, be it a cone/pyramid or an infinite column/rectangle. You could presumably set it up so that as objects get farther away they get bigger!

When the viewing frustum is set up, ie the projection matrix is set up, you also define what coordinate system you want to use to represent the far left, far right, far bottom and far top edges of the camera lense. Ie, at the extremes of what you can see, it defines what value that coordinate will have. Typically for 3D space you might have -1 to +1 for the horizontal space, and -1 to +1 for the vertical space. Any object you then place with an X coordinate of -1.0 is going to be right on the left edge of what the camera can see, for example. So then to define an object at the left of the screen you have to give it an X coordinate of -1. You could set up the frustum with other values, you could say that the left edge is 0 and the right edge is 800. Then, approximately, for what eventually might be an 800x600 screen, an object at a given X coordinate will be roughly at the pixel coordinates given, provided it hasn't been scaled with perspective.

So the projection matrix does NOT define at what pixel coordinates object appear. It only defines where within the *camera's view* the object apears, based on the camera's coordinate space. Within the perspective projection there is nothing to say how each coordinate in the frustrum/camera MAPS TO the screen or window. Screen coordinates certainly don't go from -1 to 1. You could be putting an object at 1,1 in spacial coordinates and it will appear in the bottom right corner of the camera's view, but this doesn't mean it's going to appear at pixel coordinate 1,1 or 799,599 or anything else. This is where the viewport comes in.

A viewport is a definition of screen/window space based on a value of 1 for each pixel. A viewport is a *scaling* operation that is applied on top of the perspective transformation, within the projection matrix. If you tell the system that you have an 800,600 viewport, which may or may not be within an 800,600 screen (which is also a separate thing), then the coordinates from the frustrum/camera are scaled to fit within that viewport area. If you had set up a projection matrix for 3D perspective projection and had put an object at -1,0 (on the left edge of the camera view), it would now show on the left edge of the viewport in the middle. X=-1 is converted to X=0 in the viewport, and Y=0 is converted to Y=300 in the viewport. The viewport scales the camera to a given size.

You could summarize by saying the objects in the game world are relative to the camera's coordinates, and the camera's coordinates are relative to the viewports coordinates, and the relative position of the viewport coordinates are relative to the screen coordinates. Object coordinates turn into camera coordinates which turn into viewport coordinates which are pixel coordinates.

You can use exactly the same perspective projection, and have your objects still defined in a -1 to +1 space, and have it scale the output to a 400x300 size viewport, which may be within an 800x600 screen. You could position this viewport wherever you like within the screen. Wherever you put it, it's as if you are dragging a window around - you are dragging the window onto the game world. You don't change WHERE in the game world you are looking, by moving the window, you are moving where on the screen the camera's output ends up, and at what size.

By adjusting the real viewport you can do what you were trying to achieve - to scale the output to fit a given screen resolution, or to even fit a given window or area within the screen. This doesn't change the aspect ratio, as far as I know. To change the aspect ratio you have to define that the camera's coordinate system is able to see more or less of the game world, e.g the coordinates might range from -1.3 to +1.3, and -1 to +1 vertical. Then with a widescreen viewport of say 1440x900 you would then see an extra strip of the game world at each side and the proportions/aspect ratio of the whole thing would not squash or stretch.

So you need to adjust the frustrum to adjust the aspect ratio, and you need to adjust the viewport to adjust how much of the screen is covered with the output. And BlitzMax's SetViewport() will do neither. SetViewport() will define a standard orthographic projection for 2D graphics, will set up a viewport the same size as the screen so all pixels are used, and then will define a clipping window within that full screen in the dimensions given. It restrains drawing to a given area of pixels, but it doesn't change which part of the game world is viewed or at what size or aspect ratio.

The perspective transformation to convert from 3D coords to 2D coords, and the spacial scaling to convert from 2D camera space to screen space, all takes place using the projection matrix. The matrix is applied to all geometry ie all objects you place in the scene that are within view, and all graphics primitives that you draw, so they end up being the appropriate size.

I don't know if this is the same for DirectX but this is how OpenGL does it. Maybe DX has a single projection matrix and doesn't separate it out into frustrum and viewport? In GL the viewport and the perspective projection are all done together in one matrix - the projection matrix. You could also do other things to the projection matrix - apply extra scaling, rotate it, squash it, translate it, etc If you can do something with a matrix you can do it with the projection matrix and alter the shape of space.