Sign in to follow this  
n000b

Newbie questions about drawing primitives

Recommended Posts

Hi, I'm trying to teach myself DirectX and am having some difficulty drawing some primitives (just a triangle at the moment). Here is the relevant code: IDirect3DVertexBuffer9 *g_list_vb = NULL; #define D3DFVF_SIMPLEVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE) struct customVertex { float x, y, z; DWORD colour; }; ... // create a vertex buffer so that we can draw some things pD3DDevice9->CreateVertexBuffer(3*sizeof(customVertex), D3DUSAGE_WRITEONLY, D3DFVF_XYZ, D3DPOOL_MANAGED, &g_list_vb, NULL); ... customVertex vertices[3]; void *vb_vertices; vertices[0].x = -1.0f; vertices[0].y = 0.0f; vertices[0].z = 0.0f; vertices[0].colour = 0xffff0000; vertices[1].x = 0.0f; vertices[1].y = 1.0f; vertices[1].z = 0.0f; vertices[1].colour = 0xff00ff00; vertices[2].x = 1.0f; vertices[2].y = 0.0f; vertices[2].z = 0.0f; vertices[2].colour = 0xff00ffff; // to fill the vertex buffer, we have to lock it first g_list_vb->Lock(0, 0, (void**)&vb_vertices, 0); // now copy the vertices in to the vertex buffer memcpy( vb_vertices, vertices, 3*sizeof(customVertex)); // unlock the vertex buffer g_list_vb->Unlock(); pD3DDevice9->SetStreamSource( 0, g_list_vb, 0, sizeof(customVertex) ); pD3DDevice9->SetFVF( D3DFVF_SIMPLEVERTEX ); // draw the triangle pD3DDevice9->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1); -------------------- Ok, my program displays a triangle, however it is completely black even though I am specifying colours. What's wrong there? Also, how do I convert the co-ordinates that I use for my vertices in to pixels (I don't like having to work with values between -1 and 1!)?

Share this post


Link to post
Share on other sites
Quote:
Original post by n000b
Ok, my program displays a triangle, however it is completely black even though I am specifying colours. What's wrong there?

Make sure that the D3DRS_LIGHTING render-state is off. Also, you can use the D3DCOLOR_ARGB() macro to generate DWORD colors more easily.

Quote:
Also, how do I convert the co-ordinates that I use for my vertices in to pixels (I don't like having to work with values between -1 and 1!)?

Check out this Nexe article. You can always use D3DFVF_XYZRHW - ie vertices that are already in screen space.

Share this post


Link to post
Share on other sites
You can convert pixel space coordinates [0, SCREEN_DIMENSION] to screen space [-1, 1] with a translation and scale:
screen_x = SCREEN_WIDTH * (pixel_x + 1) / 2;
screen_y = SCREEN_HEIGHT * (pixel_y + 1) / 2;

and vica-versa with the inverse:
pixel_x = ((2 * screen_x) / SCREEN_WIDTH) - 1;
pixel_y = ((2 * screen_y) / SCREEN_HEIGHT) - 1;

You may find it useful, if you aren't already using your world matrix, to simply set it to
SW/2  0     0     SW/2
0 SH/2 0 SH/2
0 0 1 0
0 0 0 1
This is essentially the same as the first pair of equations. With this at the top of your matrix stack, you can work in pixels without needing to think about dimensionless screen coordinates.

Regards
Admiral

Share this post


Link to post
Share on other sites
Thanks for the info, I will try it out soon :)

I think I've got another problem that I need to sort out first though.

I changed my code to the following to try and draw a square:


customVertex vertices[4];
void *vb_vertices;

vertices[0].x = -0.75f;
vertices[0].y = -0.75f;
vertices[0].z = 0.0f;
vertices[0].colour = 0xffff0000;

vertices[1].x = -0.75f;
vertices[1].y = 0.75f;
vertices[1].z = 0.0f;
vertices[1].colour = 0xff00ff00;

vertices[2].x = 0.75f;
vertices[2].y = 0.75f;
vertices[2].z = 0.0f;
vertices[2].colour = 0xffff0000;

vertices[3].x = 0.75f;
vertices[3].y = -0.75f;
vertices[3].z = 0.0f;
vertices[3].colour = 0xff00ffff;


// to fill the vertex buffer, we have to lock it first
g_list_vb->Lock(0,
0,
(void**)&vb_vertices,
0);


// now copy the vertices in to the vertex buffer
memcpy( vb_vertices,
vertices,
4*sizeof(customVertex));


// unlock the vertex buffer
g_list_vb->Unlock();


pD3DDevice9->SetStreamSource( 0, g_list_vb, 0, sizeof(customVertex) );

pD3DDevice9->SetFVF( D3DFVF_SIMPLEVERTEX );

// draw the triangle
pD3DDevice9->DrawPrimitive( D3DPT_TRIANGLESTRIP,
0,
2);

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

My program only displays the top left triangle though (ie a triangle between the top left, top right and bottom left vertices), it doesn't draw the other triangle though. Anyone know why?

Share this post


Link to post
Share on other sites
You need to specify your vertices in the correct order, counter-clockwise triangles are culled by default. With triangle strips, the culling direction alternates for each triangle, so the first should have vertices in clockwise order, the second in CCW, the third in CW, etc.

The following order should work (Untested):

vertices[0].x = -0.75f;
vertices[0].y = -0.75f;
vertices[0].z = 0.0f;
vertices[0].colour = 0xffff0000;

vertices[1].x = 0.75f;
vertices[1].y = -0.75f;
vertices[1].z = 0.0f;
vertices[1].colour = 0xff00ff00;

vertices[2].x = -0.75f;
vertices[2].y = 0.75f;
vertices[2].z = 0.0f;
vertices[2].colour = 0xffff0000;

vertices[3].x = 0.75f;
vertices[3].y = 0.75f;
vertices[3].z = 0.0f;
vertices[3].colour = 0xff00ffff;

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
You need to specify your vertices in the correct order, counter-clockwise triangles are culled by default. With triangle strips, the culling direction alternates for each triangle, so the first should have vertices in clockwise order, the second in CCW, the third in CW, etc.

The following order should work (Untested):
*** Source Snippet Removed ***




I tried your code but it did not work. There may be something wrong in my other code - can someone look through my first post and confirm that my code is fine please?

Also, I don't understand what you mean about the triangle strips. After the first triangle for which you need all three vertices, don't you only need to define one vertice for each triangle after that? If so, how are you supposed to alternate the defining order for each triangle?

Share this post


Link to post
Share on other sites
Quote:
Original post by n000b
Also, I don't understand what you mean about the triangle strips. After the first triangle for which you need all three vertices, don't you only need to define one vertice for each triangle after that? If so, how are you supposed to alternate the defining order for each triangle?
Yes, every vertex you add makes a new triangle. The alternating vertex order is implicit. If you add a new vertex in the wrong place, you could end up with a back facing triangle, which will be culled.

Edit:

+--+--+--+--+
|\2|\4|\6|\8|
|1\|3\|5\|7\|
+--+--+--+--+

Triangles 1, 3, 5 and 7 have their vertices in clockwise order, 2, 4, 6 and 8 are anti-clockwise.

Share this post


Link to post
Share on other sites
Quote:

Edit:

+--+--+--+--+
|\2|\4|\6|\8|
|1\|3\|5\|7\|
+--+--+--+--+

Triangles 1, 3, 5 and 7 have their vertices in clockwise order, 2, 4, 6 and 8 are anti-clockwise.



I still don't understand how you're supposed to draw the second triangle in alternating order.

To draw the first triangle, would you do it in this order: bottom right, bottom left, top left. Then would you just draw the top right one to make triangle 2?

Share this post


Link to post
Share on other sites
Quote:
Original post by n000b
Quote:

Edit:

+--+--+--+--+
|\2|\4|\6|\8|
|1\|3\|5\|7\|
+--+--+--+--+

Triangles 1, 3, 5 and 7 have their vertices in clockwise order, 2, 4, 6 and 8 are anti-clockwise.



I still don't understand how you're supposed to draw the second triangle in alternating order.

To draw the first triangle, would you do it in this order: bottom right, bottom left, top left. Then would you just draw the top right one to make triangle 2?

No. The three vertices for the second triangle will always be the last two vertices from the previous triangle, in the order that they were originally specified, with the fourth vertex added at the end. Thus, you'd do something like the bottom left, top left, and bottom right for the first triangle, and then you'd be forced to do the top left and bottom right to start the second triangle, followed finally by the top right. So if you follow the vertices in that order, you'll see that the second triangle is in the reverse order of the first. The third triangle will then use the bottom right, top right, and then the next vertex along the bottom, and so on.

Share this post


Link to post
Share on other sites
Thanks, I've got it working now! :)

A question though, every time I want to add another vertice, I need to change the size of the array in three places: when creating the array, when setting up the vertex buffer and when calling memcpy. Is there any way this value dynamic or anything so that it is easier to maintain? I know I can create a constant to hold the value so that I only have to change it in one place, it still seems a little annoying though.

Also, am I correct in thinking that you can only create on vertex buffer? If so, how would you display multiple seperate objects to the screen? Just say I wanted to draw three seperate squares, how would I do this using DrawPrimitive?

Share this post


Link to post
Share on other sites
Quote:
Original post by n000b
A question though, every time I want to add another vertice, I need to change the size of the array in three places: when creating the array, when setting up the vertex buffer and when calling memcpy. Is there any way this value dynamic or anything so that it is easier to maintain? I know I can create a constant to hold the value so that I only have to change it in one place, it still seems a little annoying though.
It depends how exactly you're using your code. If your code is a static array you can do this:

Vertex g_pVertices[] =
{
Vertex(...),
Vertex(...),
...
};

// When you create the VB:
pDevice->CreateVertexBuffer(..., sizeof(g_pVertices), ...);

// When you copy the data:
memcpy(pLock, g_pVertices, sizeof(g_pVertices));


Not that'll only work if you use a static array. Otherwise sizeof() will return the size of a pointer (usually 4) instead of the size of the array itself.

Quote:
Original post by n000b
Also, am I correct in thinking that you can only create on vertex buffer? If so, how would you display multiple seperate objects to the screen? Just say I wanted to draw three seperate squares, how would I do this using DrawPrimitive?
You can use as many vertex buffers as you like, but for performance reasons, it's best to use as few as possible. A single Draw[Indexed]Primitive() call can only use one vertex buffer though. You can still do something like this, however:

pDevice->SetStreamSource(0, pVB);
pDevice->DrawPrimitive(...);
pDevice->SetStreamSource(0, pOtherVB);
pDevice->DrawPrimitive(...);
// Etc

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this