Problem drawing a quad

Started by
7 comments, last by Roxypinky 14 years, 1 month ago
Hello everyone, I'm writing a tile engine for a map editor and I now I want to draw a quad on top of my textures tiles to mark which ones are selected. The others tiles (the textured ones) work just fine but when trying to draw my translucent "selection" quad it becomes gigantic and takes the whole window (and beyond). Now, if I use the same vertex buffer that I used to draw my texture tiles, it works just fine which lead me to believe there is a problem in the way I create my other quads and/or vertex buffer but I can't find anything wrong with it... the code is actually pretty much the same for my textured tiles and that work fine.

// Creating the vertex buffer
if (FAILED(m_d3dDevice->CreateVertexBuffer(sizeof(aHighlightVertex) * m_tileCount * 4, 0, HIGHLIGHTVERTEX_FORMAT, D3DPOOL_MANAGED, &m_highlightsVertexBuffer, 0)))
[...]


// Initialization code
void aMapRender::_UpdateHighlights(aHighlightTile *highlights, unsigned int highlightCount)
{
	m_highlightTriangleCount = highlightCount * 2;
	aHighlightVertex *highlightVertices = new aHighlightVertex[highlightCount * 4];

	// Create the highlight tile vertices
	for (unsigned int i = 0; i < highlightCount; ++i)
	{
		aHighlightVertex vertices[] = 
		{
			{32.0f, 0.0f,/*highlights.x * m_tileSize +  m_tileSize,	highlights.y * m_tileSize,			*/	0.5f,	1.0f,	highlights.color}, // Top Right
			{32.0f, 32.0f,/*highlights.x * m_tileSize +  m_tileSize,	highlights.y * m_tileSize + m_tileSize,*/	0.5f,	1.0f,	highlights.color}, // Bottom Right
			{0.0f, 32.0f,/*highlights.x * m_tileSize,					highlights.y * m_tileSize + m_tileSize,*/	0.5f,	1.0f,	highlights.color}, // Bottom Left		
			{0.0f, 0.0f,/*highlights.x * m_tileSize,					highlights.y * m_tileSize,	*/			0.5f,	1.0f,	highlights.color}, // Top Left
		};

		memcpy(&highlightVertices, test, <span class="cpp-keyword">sizeof</span>(aHighlightVertex) * <span class="cpp-number">4</span>);
	}

	<span class="cpp-comment">// Copy this to our vertex buffer</span>
	<span class="cpp-keyword">void</span> *ptr;
	m_highlightsVertexBuffer-&amp;gt;Lock(<span class="cpp-number">0</span>, <span class="cpp-number">0</span>, &amp;ptr, <span class="cpp-number">0</span>);
	memcpy(ptr, highlightVertices, <span class="cpp-keyword">sizeof</span>(aHighlightVertex) * highlightCount * <span class="cpp-number">4</span>);
	m_highlightsVertexBuffer-&amp;gt;Unlock();

	<span class="cpp-keyword">delete</span>[] highlightVertices;
}




<span class="cpp-comment">// And the drawing code</span>
[…]
<span class="cpp-keyword">if</span> (m_highlightTriangleCount)
{
	m_d3dDevice-&amp;gt;SetFVF(HIGHLIGHTVERTEX_FORMAT);
	m_d3dDevice-&amp;gt;SetStreamSource(<span class="cpp-number">0</span>, m_highlightsVertexBuffer, <span class="cpp-number">0</span>, <span class="cpp-keyword">sizeof</span>(aHighlightTile));
	m_d3dDevice-&amp;gt;DrawPrimitive(D3DPT_TRIANGLEFAN, <span class="cpp-number">0</span>, m_highlightTriangleCount);
}
[…]


</pre></div><!–ENDSCRIPT–>

Does anyone know what I'm doing wrong?

Thanks,
-Roxanne
Advertisement
Quote:memcpy(&highlightVertices, test, sizeof(aHighlightVertex) * 4);<!–QUOTE–></td></tr></table></BLOCKQUOTE><!–/QUOTE–><!–ENDQUOTE–> What's 'test'? Never mind, why are you allocating an array &#111;n the heap, writing to it, then copying the array to the vertex buffer? Why not write directly to the vertex buffer? Why is the vertex buffer created without the D3DUSAGE_WRITEONLY flag? You don't seem to be reading back from it.<br><br><!–QUOTE–><BLOCKQUOTE><span class="smallfont">Quote:</span><table border=0 cellpadding=4 cellspacing=0 width="95%"><tr><td class=quote><!–/QUOTE–><!–STARTQUOTE–>m_d3dDevice-&gt;DrawPrimitive(D3DPT_TRIANGLEFAN, 0, m_highlightTriangleCount);<!–QUOTE–></td></tr></table></BLOCKQUOTE><!–/QUOTE–><!–ENDQUOTE–><br>D3DPT_TRIANGLEFAN? To draw a bunch of quads? Use triangle lists instead to draw all the quads in &#111;ne call. Also, it seems to me all quads have the same color, so why are you storing per-vertex color information unnecessarily?
Oups, nevermind that 'test' it should be 'vertices'... I was trying something and forgot to change it back before copying my code here. You are also right about the D3DUSAGE_WRITEONLY flag, I'm not reading from it, I'll add it.

However, aMapRender::_UpdateHighlights is called on every frame update and I read that if you need to lock a vertex buffer during a frame update it was best to leave it lock for the least amount of time as this could degrade performance. Do you think this is unnecessary? I'll try both ways and see what work best. Also, my quads may not have all the same color and are not contiguous so I can't draw them in one call.

Thanks
You should draw them in one call. If each tile is 32 pixels in size, and the screen resolution is, say, no more than 1600x1600, then the maximum number of quads you'll have to draw each frame is (1600/32) ^ 2, which is 2500 quads. You certainly don't want to draw each quad in its own draw call, or you'll suffer poor performance for sure. That's why you should use one draw call and a triangle list instead of fan. Them being contiguous has nothing to do with the number of draw calls, but it forces you to use a triangle list instead of strips or fans.

As for reducing the locking time, the advice you spoke of encourages against locking a vertex buffer and then going off performing lengthy computations, but in this case, you aren't doing that. The stuff you are doing here (computing vertex locations) is relatively trivial, so write directly to the VB. Hope this helps.
Alright, thanks for the advice I changed the way i create my vertices. However, I don't understand how I can draw non-contiguous quads with only one call using a triangles list. The way I understand it is that all the triangles will be drawn connected to each other. Am I correct? I'll mess up a bit with that and try to understand more how it works. But I still don't understand why it was drawing giant triangles on screen (now there is simply nothing appearing). There must be something wrong with how I initialize my quads (other than the fact that it is not the best possible way to do it) because if i use the same vertex buffer I use to draw my tiles it works fine. But I don't see what wrong... :( Here's a screenshot of my the faulty vertex buffer right before I unlock it:

http://i924.photobucket.com/albums/ad85/roxypinky/quads.png

Any idea?

Thanks a lot for the help :)
Use D3DPT_TRIANGLELIST, not FAN. You are then specifying sets of three vertices defining non-connected triangles. If this is producing too many duplicate indices, solve with an index buffer.

The problems you describe with the wildly wrong triangles sounds like the vertex data being misinterpreted to me:

m_d3dDevice->SetStreamSource(0, m_highlightsVertexBuffer, 0, sizeof(aHighlightTile));


Should that not be sizeof(aHighlightVertex)?

Quote:
I read that if you need to lock a vertex buffer during a frame update it was best to leave it lock for the least amount of time as this could degrade performance.


It is more the time taken to lock and unlock the buffer that can degrade performance than the time it is locked. You should avoid too many lock and unlocks per frame, not try to minimise the time it is locked.

Vertex memory may reside on the graphics card. When you unlock a locked buffer, it can be as bad as having to copy all the buffer data from normal memory to graphics memory.

Since the most probable bottleneck is transfer of data from main board to graphics card, you should batch as much as possible over to the card. This also allows you to continue processing on the CPU while the GPU is rendering the provided vertex data.
omg lol, you're totally right. Thanks a lot. And I'll switch to D3DPT_TRIANGLELIST... dunno why when Amr0 first suggested this I had D3DPT_TRIANGLESTRIP in mind hence why I was confused as to how I was gonna draw unconnected triangles with that. Anyway thanks a lot you 2, you have been of great help :)
The way I do quads to reduce traffic across to the card is to create a big index buffer that is set up like this:

QuadIndices.Acquire(*Gr,1800*2,D3DUSAGE_WRITEONLY,D3DPOOL_DEFAULT);WORD *W=QuadIndices.Lock(D3DLOCK_DISCARD);WORD O=0;for(WORD N=0;N<300*2;++N)    {    *W++=O; *W++=O+1; *W++=O+3; *W++=O+1; *W++=O+2; *W++=O+3;    O+=4;    }QuadIndices.Unlock();


I'm using my own class wrapper for an index buffer but it is pretty thin so should translate. The important bit is more the values I'm putting in.

If you haven't used index buffers before, there is loads of info in the docs. Just remember to set the index buffer onto the stream and call DrawIndexedPrimitive instead of DrawPrimitive.

I can then just put four vertices into the vertex buffer for each quad, in clockwise order starting from top left.

Since the index buffer does not need to be unlocked, it can sit in memory accessible to the GPU without being moved about and it reduces the vertices required to move over to the card from six to four per quad - a big saving if you are batching a large number of quads per frame.

Obviously you need to keep in mind that you can't put more quads into the vertex buffer than the index buffer can accomodate. I size the index buffer based on the size of the vertex buffer I use for sprite rendering and have the vertex buffer flush to screen when it runs out of space.
Awesome :)

Thanks again for all the help this was pretty useful

This topic is closed to new replies.

Advertisement