DirectX viewports

Started by
23 comments, last by Evil Steve 16 years, 2 months ago
You probably want an orthogonal projection matrix, along with a view matrix looking down your Z axis (Assuming the tiles are on the XY plane). You'll want to make sure you avoid rendering tiles that are outside the visible area though (You'd want to do that with any method), for performance reasons.
Advertisement
And what do I do with that matrix so make it do what I want?
Quote:Original post by Sync Views
And what do I do with that matrix so make it do what I want?
I knew there was something I forgot to mention [smile]

You set it as your projection matrix.

How are you doing 2D at the moment? Are you using transformed vertices (A FVF containing D3DFVF_XYZRHW)? And what is your projection matrix like at the moment?
The best way to do 2D is to use an orthogonal projection matrix, and real 3D vertices (Not RHW verts), since then you can get rotation or vertex shaders for free if you wish. A perspective projection matrix will make object further from the camera smaller (As normal perspective does in the real world), which probably isn't what you want for sprites.

EDIT: I may have mis-understood your question...
For the parameters to the matrix, you set the b and l parameters to the top left of your view, and the t and r to the bottom right corners (So it's flipped in Y). The zn and zf values should be a sensible Z range like 1.0f and 1000.0f, which gives you a reasonable range of Z values for if you want to use the Z-buffer.
So a view of 100x100 units, with the top left corner at (2000, 3000) would be:
D3DXMATRIX mat;D3DXMatrixOrthoOffCenterLH(&mat, 2000.0f, 2100.0f, 3000.0f, 3100.0f, 1.0f, 1000.0f);pDevice->SetTransform(D3DTS_PROJECTION, &mat);
The vertext format i;m setting is:
const DWORD d3d_vertexformat = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1;


I assume your refering to the "D3DFVF_XYZRHW" bit? I really have no idea what RHW even is, i'm just setting it to 1.0 on all my vertices as the tutorial did (2d useing textured quads one on this site somewhere...)

Right now I'm just adding vertices with rhw as 1.0 and z as 0.0 (as seen in the code snipet above) and drawing a primitives with it. 0,0 is the top left of the screen with 1 unit on the vertices being 1 unit on the screen (so a vertex with 800,600 would be the bottom right of my window).
Quote:Original post by Sync Views
The vertext format i;m setting is:
*** Source Snippet Removed ***

I assume your refering to the "D3DFVF_XYZRHW" bit? I really have no idea what RHW even is, i'm just setting it to 1.0 on all my vertices as the tutorial did (2d useing textured quads one on this site somewhere...)

Right now I'm just adding vertices with rhw as 1.0 and z as 0.0 (as seen in the code snipet above) and drawing a primitives with it. 0,0 is the top left of the screen with 1 unit on the vertices being 1 unit on the screen (so a vertex with 800,600 would be the bottom right of my window).
RHW stands for "Reciprocal of Homogenous W" and effectively means "depth". When you use the D3DFVF_XYZRHW flag, you're telling D3D that you're drawing things in screen space, so it shouldn't do any transformation of the vertices (and shouldn't run the vertex shaders on them, if you have them), because you're giving the final position of the vertex how you want it. That means that the only way you can change their position (which is what you want) is to physically move the vertices, by locking the vertex buffer containing them, update the position, and then unlock the vertex buffer - something that the GPU should do wherever possible, since it does them for "free", and can handle e.g. rotation if you need it.

To get the GPU to do the transformation for you, you need to use untransformed vertices; that is you need D3D to pass the vertices through the world, view and projection matrices. For that, you'd use D3DFVF_XYZ to tell D3D you're passing in a XYZ coordinate (And remove the RHW member of your vertex struct), set up a projection matrix, and set an identity matrix for the view and world matrices (Which is the default, so you can leave the view and world matrices alone if you never change them).
If you do that, every vertex you pass in will be transformed by the three matrices, so you can just change the matrix to change the transform. For instance, you could rotate all the vertices (I know, I keep going on about rotation, rotation is cool [smile]), or you could move them all by a (X,Y) amount to move your world around (The same idea as changing the bounds of the projection matrix).

Google has loads of info on orthogonal projection matrices, this one looks interesting (Although I haven't read the whole thing).
I couldn't find much useful on your search. Lots of stuff about the concept but nothing on how to actauly use it :(

I'll continue to experiment to see if I can get something to work for now...

EDIT: ok got something to work having played with the numbers and stuff (eg setting the z for my vertices to 1.0 instead of 0.0).

	D3DXMatrixOrthoOffCenterLH(		&matrix,		view_x, view_x + view_w,		view_y, view_y + view_h,		1.0f, 1000.0f);


Only problem is it flips the y axis... How can I stop this?

also how can I make my text be effected by this as it seems to still be working in screen cordinates?

bool draw_text(int ft, int x, int y, std::string str, unsigned long colour){	if(d3d_lost)return true;	if(!font_exists(ft)) return false;   	RECT rct;	rct.left=x;	rct.right=x+999;	rct.top=y;	rct.bottom=1;	rct.bottom = y + cgm::font_list[ft]->DrawTextA(NULL, str.c_str(), -1, &rct,DT_EXPANDTABS | DT_CALCRECT | DT_NOCLIP | align, colour);	cgm::font_list[ft]->DrawTextA(NULL, str.c_str(), -1, &rct,DT_EXPANDTABS | DT_NOCLIP | align, colour);	return true;}


[Edited by - Sync Views on February 19, 2008 6:44:44 PM]
Whoops, I'm an idiot. Swap your "view_y" and "view_y + view_h" parameters to prevent it flipping in Y.

ID3DXFont is designed to draw in screen space, so you'll have to just adjust the RECT you pass in according to your view area, or write your own font system (Which I wouldn't recommend).
You could try posting in the DirectX forum and asking if anyone knows if you can get it to draw in world space rather than screen space, I don't know of any way.
Well I could could draw it to some kind of surface then draw the surface I assume? Still need to check out how this effects my render target system for drawing to surfaces though...

btw: You said this lets me do stuff like rotation etc for free but I'm still not seeing anyway to do it other than to transform the vertices of my quad eg:
bool draw_sprite_rot(const int id, double x, double y, double rot){return draw_sprite_rot(id, x, y, rot, c_white, c_white, c_white, c_white);}bool draw_sprite_rot(const int id, double x, double y, double rot, unsigned long c1){return draw_sprite_rot(id, x, y, rot, c1, c1, c1, c1);}bool draw_sprite_rot(const int id, double x, double y, double rot, unsigned long c1, unsigned long c2, unsigned long c3, unsigned long c4){	if (!sprite_exists(id))return false;	if (d3d_lost)return true;	if (rot == 0) return draw_sprite(id, x, y, c1, c2, c3, c4);	cgm::d3d_device->SetTexture (0, cgm::sprite_list[id]->image);	rot = degtorad(rot);	x -= cgm::sprite_list[id]->offset_x;	y -= cgm::sprite_list[id]->offset_y;	return draw_quad(		x+(cgm::sprite_list[id]->offset_x + (-cgm::sprite_list[id]->offset_x)*cos(rot) - (-cgm::sprite_list[id]->offset_y)*sin(rot)),		y+(cgm::sprite_list[id]->offset_y + (-cgm::sprite_list[id]->offset_x)*sin(rot) + (-cgm::sprite_list[id]->offset_y)*cos(rot)),		x+(cgm::sprite_list[id]->offset_x + ((cgm::sprite_list[id]->w) - cgm::sprite_list[id]->offset_x)*cos(rot) - (-cgm::sprite_list[id]->offset_y)*sin(rot)),		y+(cgm::sprite_list[id]->offset_y + ((cgm::sprite_list[id]->w) - cgm::sprite_list[id]->offset_x)*sin(rot) + (-cgm::sprite_list[id]->offset_y)*cos(rot)),		x+(cgm::sprite_list[id]->offset_x + ((cgm::sprite_list[id]->w) - cgm::sprite_list[id]->offset_x)*cos(rot) - ((cgm::sprite_list[id]->h) - cgm::sprite_list[id]->offset_y)*sin(rot)),		y+(cgm::sprite_list[id]->offset_y + ((cgm::sprite_list[id]->w) - cgm::sprite_list[id]->offset_x)*sin(rot) + ((cgm::sprite_list[id]->h) - cgm::sprite_list[id]->offset_y)*cos(rot)),			x+(cgm::sprite_list[id]->offset_x + (-cgm::sprite_list[id]->offset_x)*cos(rot) - ((cgm::sprite_list[id]->h) - cgm::sprite_list[id]->offset_y)*sin(rot)),		y+(cgm::sprite_list[id]->offset_y + (-cgm::sprite_list[id]->offset_x)*sin(rot) + ((cgm::sprite_list[id]->h) - cgm::sprite_list[id]->offset_y)*cos(rot)),		c1, c2, c3, c4);}



EDIT: Also as I can use the matrix to scale and translate everything to screen space can I also get it to rotate the "view" as well as move it?
Quote:Original post by Sync Views
Well I could could draw it to some kind of surface then draw the surface I assume? Still need to check out how this effects my render target system for drawing to surfaces though...
Ah yes, that's a good way to do it.

Quote:Original post by Sync Views
btw: You said this lets me do stuff like rotation etc for free but I'm still not seeing anyway to do it other than to transform the vertices of my quad eg:
*** Source Snippet Removed ***

EDIT: Also as I can use the matrix to scale and translate everything to screen space can I also get it to rotate the "view" as well as move it?
You'd change the world matrix to include rotation as well as translation as required by multiplying the matrices (I don't know if you've covered matrices, I covered them in Higher (A-level) maths).
I suppose I'll cover them in the next two years then....not sure I really want to wait that long though so can you explain what I basicly need to do? eg looking at that matrix function I'm realy not seeing what I'm meant to change to do rotation as well :( (I'm asuming it's not as simple as how many degress/radians as it would need to take into acount where the "centre" of my object is?)

This topic is closed to new replies.

Advertisement