• Advertisement
Sign in to follow this  

Drawing Shape on top of Sprites

This topic is 2646 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am currently using sprites to fill my background. If I wanted to draw a rectangle on my map, what would I need to do?

Can I get by with creating a Vertex Buffer, locking that, and generating a quad after I have rendered the background?

[Edited by - nlraley on October 26, 2010 4:08:59 PM]

Share this post


Link to post
Share on other sites
Advertisement
Would this just be a manner of locking the memory buffer and drawing the shape as I would normally create a shape with vertices?

Share this post


Link to post
Share on other sites
After calling ID3DXSprite::Begin(), you could disable Z-writes (SetRenderState(D3DRS_ZWRITEENABLE, FALSE);). That way the sprite won't write anything to the Z buffer (Although I'm not sure if it currently does anyway), and you can render whatever you like on top.

Share this post


Link to post
Share on other sites
Quote:
Original post by nlraley
And just create it by creating a 4 point vector and calling draw primitive?
However you like. If you just want to draw a single colour, then yes, I'd fill a vertex buffer with the 4 points and draw them as a quad. If you want a texture applied, you could also use ID3DXSprite again.

Share this post


Link to post
Share on other sites
What is going to be the best way to do this?

After I call my draw sprite should I create me vertices that I need for all my rectangles, then create a new vertex buffer, lock it, then pass it the size of my vertices?

What I was wanting to do is go through a list of my objects, which I know their x,y positions and everything ( some of which aren't going to be in view ) and then draw a rectangle for each of these, but not sure exactly how to go about doing that on top of a sprite.

Here is what I am trying atm, here is my Render:

//-------------------
if ( SUCCEEDED( hr = d3d9Device->BeginScene() ) )
{
//-------------------
// Scene Rendering takes place Here
//-------------------
// Draw the triangles in the vertex buffer. This is broken into a few
// steps. We are passing the vertices down a "stream", so first we need
// to specify the source of that stream, which is our vertex buffer. Then
// we need to let D3D know what vertex shader to use. Full, custom vertex
// shaders are an advanced topic, but in most cases the vertex shader is
// just the FVF, so that D3D knows what type of vertices we are dealing
// with. Finally, we call DrawPrimitive() which does the actual rendering
// of our geometry (in this case, just one triangle).
//------------------- Begin Sprite Drawing
d3d9Sprite->Begin(D3DXSPRITE_ALPHABLEND );
//------------------- Draw the Map Tiles
DXTexture dxt = DXTexture(this);
dxt.DrawSprites();
//------------------- Draw the Navigation Control
hr = d3d9Sprite->Draw(
navTexture,
NULL,
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
&D3DXVECTOR3(0.0f, 0.0f, 0.0f),
D3DCOLOR_ARGB(255, 255, 255, 255)
);
if (FAILED(hr))
return;
//-------------------
DrawIntersections();
//-------------------
DrawVehicles();
//------------------- End Sprite Drawing
d3d9Sprite->End();
//------------------- Draw Test Zone
DrawZones();
//------------------- End the Scene
d3d9Device->EndScene();
}
//------------------- Present the Backbuffer contents to the display
d3d9Device->Present( NULL, NULL, NULL, NULL);
//-------------------


As you see, after I draw my sprites I call DrawZones, which is supposed to draw my rectangles. Here is that function:

VOID* pVertices;
Vertex vertices[] =
{
{0.0f, 0.0f, 2.0f, 1.0f, 0, 0, 0xff0000ff},
{256.0f, 0.0f, 2.0f, 1.0f, 1, 0, 0xff0000ff},
{0.0f, 256.0f, 2.0f, 1.0f, 0, 1, 0xff0000ff},
{256.0f, 256.0f, 2.0f, 1.0f, 1, 1, 0xff0000ff}
};
//-------------------
if( FAILED( d3d9VertexBuffer->Lock( 0, sizeof( vertices[4] ), ( void** )&pVertices, 0 ) ) )
return E_FAIL;
memcpy( pVertices, vertices, sizeof( vertices[4] ) );
d3d9VertexBuffer->Unlock();
//-------------------
if (FAILED( hr = d3d9Device->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ) ) )
{
const char* szError = DXGetErrorDescription9(hr);
MessageBox (MainForm->Handle, szError, "Error", MB_OK );
return E_FAIL;
}


This does not fail; however, there is no rectangle being drawn. Any ideas?

[Edited by - nlraley on October 26, 2010 3:50:46 PM]

Share this post


Link to post
Share on other sites
Well, I'm not really sure why the quad isn't being rendered.

I created my vertex with 4 points. Locked the VertexBuffer. Filled the VertexBuffer with the points. Unlocked the VertexBuffer. Then called DrawPrimitive telling it to draw the 2 primitives using TRIANGLESTRIP. However my sprites show up yet my primitive does not.

I'm sure I'm probably missing something minor.

Share this post


Link to post
Share on other sites
I think you've got your vertices in the wrong order. For a triangle strip to be drawn as a quad, the vertex order is lower-left, upper-left, lower-right, upper right. Try:

{0.0f, 256.0f, 2.0f, 1.0f, 0, 0, 0xff0000ff},
{0.0f, 0.0f, 2.0f, 1.0f, 1, 0, 0xff0000ff},
{256.0f, 256.0f, 2.0f, 1.0f, 0, 1, 0xff0000ff},
{256.0f, 0.0f, 2.0f, 1.0f, 1, 1, 0xff0000ff}

Share this post


Link to post
Share on other sites
I'll give it a try but in the examples in the SDK adding a 4th point like this:
CUSTOMVERTEX vertices[] =
{
{ 0.0f, 0.0f, 0.5f, 1.0f, 0xffff0000, }, // x, y, z, rhw, color
{ 250.0f, 0.0f, 0.5f, 1.0f, 0xff00ff00, },
{ 0.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
{ 250.0f, 250.0f, 0.5f, 1.0f, 0xff00ffff, },
};


And declaring it a strip draws the rectangle perfectly fine.

I didn't think the order mattered as long as the ends "connected" properly? For example, a triangle strip uses 1 point to define each triangle. The last 2 points from the previous triangle are used in creating the next triangle and basically connect to the new point.

Using my example would work as I have:
A B




C

Creating triangle ABC, when I add a 4th point as such:
A B




C D

The new triangle uses points B and C, previously used in Triangle ABC to create triangle BCD. Your example works the same way but in a different order.

[Edited by - nlraley on October 26, 2010 3:24:03 PM]

Share this post


Link to post
Share on other sites
Although, oddly enough, that solution worked. That's odd. Was the source I read wrong?

Share this post


Link to post
Share on other sites
The order of vertices only matters for the backface culling that DirectX does. The default behavior is that the face of a primitive with the vertices in clockwise order are drawn, while the back of that face (which, if it were to be drawn, would have the same vertices, but in counter-clockwise order) is not drawn.

In the case of a triangle strip it gets a bit funky because the second vertex is used in a clockwise fashion for the first triangle but in a counter-clockwise fashion for the second triangle.

You also have your first three vertices in clockwise order, so I'm not sure why DirectX regards that differently, and maybe my backface culling theory doesn't hold water in this case. Maybe there are some other specifics to triangle strips that require such a specific vertex order. In any case, I'm glad it worked out for you.

Share this post


Link to post
Share on other sites
The winding order of vertices is relative to your camera. Your original code's vertices are in clockwise order only if your camera looks along +Z. If it looks along -Z, then they're in anti-clockwise order.
What is the FVF / vertex declaration you're using for your vertex struct?

You could also just disable backface culling when drawing your 2D, by calling SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE).

That method for drawing quads looks fine to me, although some performance improvements would be:
1. Make sure the vertex buffer is allocated as dynamic (You have the D3DUSAGE_DYNAMIC flag set when creating it). Dynamic vertex buffers are much faster to update.
2. If you're drawing multiple rectangles, draw as many as possible in one go. That means creating a vertex buffer large enough for a "lot" of vertices (say 1024 verts or so), filling it with all the rectangles, then drawing them all in a single DrawPrimtive() call. That requires...
3. Use an index buffer. That way you can do the above (render all rectangles in one draw call), by rendering the rectangles as an indexed triangle list instead of a series of short triangle strip. That way the GPU's vertex cache can kick in, and it should be quicker than rendering triangle strips.
3b. The index buffer can be static and can be pre-filled - the order of vertices will never change, no matter how many rectangles you draw.

ID3DXSprite internally performs all of the above optimisations, so if you do that you'll get performance at least as good as ID3DXSprite.

Share this post


Link to post
Share on other sites
One final question. I am drawing this rectangle on top of my sprites now. Is there any way to get the red to fade into a transparency as opposed to black which it is currently fading to?

I'd prefer a solid red with probably 40-60% opacity if that's possible in this situation.

Share this post


Link to post
Share on other sites
I'm using DirectX 8, so there may be a better way to do this in newer versions, but here's how I do it:

Turn on alpha blending:

SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);

then bind the alpha component of the of the vertices to that of the texture (if applicable):

SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);

then set the alpha component of the vertices of the quad to whatever transparancy I need:

myDrawVertices[].diffuse & 0x00FFFFFF;
myDrawVertices[].diffuse | alpha; //where alpha is between 0 and 255

The texture part might not be relevant for you in this case. I just set it up this way in case I decide to use textured quads.

Share this post


Link to post
Share on other sites
Whoops. The alpha part should be:

myDrawVertices[].diffuse & 0x00FFFFFF;
alpha = alpha << 24; //where the original alpha was between 0 and 255
myDrawVertices[].diffuse | alpha;

Also, you can turn alpha blending on and off during a frame (using SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE/FALSE)). I've read that it's a pretty expensive operation, so I would only turn it on while drawing your transparent item(s).

Share this post


Link to post
Share on other sites
Ah, I had set those render settings before but had turned them off when I was trying to figure out why my sprites were all tranlucent.

That gives me a fade from top heading to the bottom when the bottom being transparent it seems. How can I get this to not have a gradient effect but rather be solid but semi transparent? The values I am passing for my colors when defining my vertices:
Vertex vertices[] =
{
{Data-&gt;Zones.i-&gt;dxPosition[0].X, Data-&gt;Zones.i-&gt;dxPosition[0].Y, 0.0f, 0.0f, 0, 0, 0xff0000ff},
{Data-&gt;Zones.i-&gt;dxPosition[1].X, Data-&gt;Zones.i-&gt;dxPosition[1].Y, 0.0f, 0.0f, 1, 0, 0xff0000ff},
{Data-&gt;Zones.i-&gt;dxPosition[2].X, Data-&gt;Zones.i-&gt;dxPosition[2].Y, 0.0f, 0.0f, 0, 1, 0xff0000ff},
{Data-&gt;Zones.i-&gt;dxPosition[3].X, Data-&gt;Zones.i-&gt;dxPosition[3].Y, 0.0f, 0.0f, 1, 1, 0xff0000ff}
};


The value for the A of the ARGB color doesn't seem to affect the transparency at all. Any idea what I'm doing wrong?

*edit*
I wanted to add my settings just in case I was setting them wrong:

if (FAILED(hr = d3d9Device-&gt;SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE))) return hr;
if (FAILED(hr = d3d9Device-&gt;SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA))) return hr;
if (FAILED(hr = d3d9Device-&gt;SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA))) return hr;
if (FAILED(hr = d3d9Device-&gt;SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE))) return hr;



[Edited by - nlraley on October 26, 2010 3:10:26 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Evil Steve
The winding order of vertices is relative to your camera. Your original code's vertices are in clockwise order only if your camera looks along +Z. If it looks along -Z, then they're in anti-clockwise order.
What is the FVF / vertex declaration you're using for your vertex struct?

You could also just disable backface culling when drawing your 2D, by calling SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE).

That method for drawing quads looks fine to me, although some performance improvements would be:
1. Make sure the vertex buffer is allocated as dynamic (You have the D3DUSAGE_DYNAMIC flag set when creating it). Dynamic vertex buffers are much faster to update.
2. If you're drawing multiple rectangles, draw as many as possible in one go. That means creating a vertex buffer large enough for a "lot" of vertices (say 1024 verts or so), filling it with all the rectangles, then drawing them all in a single DrawPrimtive() call. That requires...
3. Use an index buffer. That way you can do the above (render all rectangles in one draw call), by rendering the rectangles as an indexed triangle list instead of a series of short triangle strip. That way the GPU's vertex cache can kick in, and it should be quicker than rendering triangle strips.
3b. The index buffer can be static and can be pre-filled - the order of vertices will never change, no matter how many rectangles you draw.

ID3DXSprite internally performs all of the above optimisations, so if you do that you'll get performance at least as good as ID3DXSprite.


Do you have an example of how this is done by chance steve?

Share this post


Link to post
Share on other sites
Quote:
Original post by nlraley
Do you have an example of how this is done by chance steve?
Not really. What part? It should all be straightforward just following the DirectX docs.

Share this post


Link to post
Share on other sites
Quote:
Original post by nlraley
Creating the indexed triangle list.


Untested:

#define MAX_RECTS 1024 // Maximum number of rectangles that can be drawn
LPDIRECT3DINDEXBUFFER9 pIndexBuffer = NULL;

// At init time:

// Create the index buffer with 6*MAX_RECTS indices in it (3 per triangle, 2 triangles per rect)
HRESULT hResult = d3d9Device->CreateIndexBuffer(sizeof(WORD)*MAX_RECTS*6, D3DUSAGE_WRITEONLY,
D3DFMT_INDEX16, D3DPOOL_MANAGED, &pIndexBuffer, NULL);
if(FAILED(hResult))
{
// Error, abort
}

// Fill the index buffer with indices. Assume vertices are always added in order:
// top left, top right, bottom left, bottom right
WORD* pIndices;
hResult = pIndexBuffer->Lock(0, 0, (void**)&pIndices, 0);
if(FAILED(hResult))
{
// Error, abort
}
for(int i=0; i<MAX_RECTS; ++i)
{
// First triangle (top left, top right, bottom left)
*pIndices++ = i*4;
*pIndices++ = i*4 + 1;
*pIndices++ = i*4 + 2;

// Second triangle (top right, bottom right, bottom left)
*pIndices++ = i*4 + 1;
*pIndices++ = i*4 + 3;
*pIndices++ = i*4 + 2;
}
pIndexBuffer->Unlock();



// At render time:

// Fill vertex buffer with all the rectangles you want to draw (Add vertices in
// the same order as you have already)

// Set the index buffer as the index source
d3d9Device->SetIndices(pIndexBuffer);

// Draw num_rectangles as an indexed triangle list:
d3d9Device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, num_rectangles*4,
0, num_rectangles*2);




And at shutdown time, remember to Release() pIndexBuffer.

Share this post


Link to post
Share on other sites
Thanks, I should be able to get something like that working pretty easy. I technically already have the points and everything indexed, b/c each object I will be using drawprimitive for is an object that I have its coordinates for. It's just a matter of dynamically using the buffer now.

I still don't have my blending working the way I want it however. What do I have to do to have the rectangle be solid red with a transparency? Right now it has a transparency but its the equivalent of having a gradient. I am just wanting solid color with partial transparency to the background. Do I have one of the options set wrong?

Share this post


Link to post
Share on other sites
Quote:
Original post by nlraley
I still don't have my blending working the way I want it however. What do I have to do to have the rectangle be solid red with a transparency? Right now it has a transparency but its the equivalent of having a gradient. I am just wanting solid color with partial transparency to the background. Do I have one of the options set wrong?
Your current setup will blend the texture and diffuse alpha - do you have a texture set? Does it make any difference if you call device->SetTexture(NULL); before rendering your rectangles?

Share this post


Link to post
Share on other sites
Ah, that could be it. I wasn't wanting to load a texture into the quad. I wanted the quad to be a solid color and diffuse it with the sprites loaded into the background.

Will setting the texture to null mess up the sprites?

Share this post


Link to post
Share on other sites
It looks like the parts of your Vertex struct are in the wrong order. If you specified

D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1

as your vertex shader, then the data in the vertex buffer needs to be in this order:

float x
float y
float z
float rhw
D3DCOLOR diffuse
float u
float v

I think you've got your UV values before your diffuse values, so it's reading the wrong numbers for the wrong properties.

The good news is that, because you're seeing the gradient, you've got alpha blending set up properly.

Share this post


Link to post
Share on other sites
Ah, that could be it and would explain why it appeared to be fading into black. I had my structure defined in a different order than that which is the reason I had them in a different order. I should have caught that one. Let me give it a try.

*edit*
Changing the order results in no rectangle being drawn at all.

*edit*
Never mind, I forgot that while messing around with various settings I had changed my vector format. Now I have a solid blue rectangle.

*final edit*
I forgot that I had disabled the call to the device settings, therefore my rendering wasn't being set up. Its all up and running now. Thanks guys.

The solution was to set the device settings as follows:
if (FAILED(hr = d3d9Device-&gt;SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE)))                  return hr;
if (FAILED(hr = d3d9Device-&gt;SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA))) return hr;
if (FAILED(hr = d3d9Device-&gt;SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA))) return hr;
if (FAILED(hr = d3d9Device-&gt;SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE))) return hr;


Followed by defining my Vector in this order, yes order does matter:
typedef struct
{
FLOAT x, y, z, rhw; // The transformed position for the vertex
DWORD color; // The vertex color
FLOAT tu, ty;
} Vertex;


And finally creating the rectangle as follows:
Vertex vertices[] =
{
{Data-&gt;Zones.i-&gt;dxPosition[0].X, Data-&gt;Zones.i-&gt;dxPosition[0].Y, 0.0f, 0.0f, 0x7f0000ff, 0, 0},
{Data-&gt;Zones.i-&gt;dxPosition[1].X, Data-&gt;Zones.i-&gt;dxPosition[1].Y, 0.0f, 0.0f, 0x7f0000ff, 1, 0 },
{Data-&gt;Zones.i-&gt;dxPosition[2].X, Data-&gt;Zones.i-&gt;dxPosition[2].Y, 0.0f, 0.0f, 0x7f0000ff, 0, 1 },
{Data-&gt;Zones.i-&gt;dxPosition[3].X, Data-&gt;Zones.i-&gt;dxPosition[3].Y, 0.0f, 0.0f, 0x7f0000ff, 1, 1 }
};
if( FAILED( d3d9Device-&gt;CreateVertexBuffer(
4 * sizeof( Vertex ), // Length
0, // Usage -
D3DFVF_TLVERTEX, // Specifies Vertex Format
D3DPOOL_MANAGED, // D3DPool
&d3d9VertexBuffer, // Pointer to the Direct3D Vertex Buffer
NULL // HANDLE
) ) )
{
//-------------------
return E_FAIL;
//-------------------
}
//-------------------
if( FAILED( d3d9VertexBuffer-&gt;Lock( 0, sizeof( vertices ), ( void** )&pVertices, 0 ) ) )
return E_FAIL;
memcpy( pVertices, vertices, sizeof( vertices ) );
d3d9VertexBuffer-&gt;Unlock();
//-------------------
d3d9Device-&gt;SetStreamSource( 0, d3d9VertexBuffer, 0, sizeof( Vertex ) );
d3d9Device-&gt;SetFVF( D3DFVF_TLVERTEX );
//-------------------
if (FAILED( hr = d3d9Device-&gt;DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 ) ) )
{
const char* szError = DXGetErrorDescription9(hr);
MessageBox (MainForm-&gt;Handle, szError, "Error", MB_OK );
return E_FAIL;
}
//-------------------


[Edited by - nlraley on October 26, 2010 3:57:56 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement