# Drawing multiple lines with one draw call

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

## Recommended Posts

I'm trying to fill the indices to draw multiple lines with a single draw call:

DWORD linesCount = 4; // Draw 4 lines with one draw call
TVertex* vrts = new TVertex[linesCount]();

for(DWORD i = 0; i < linesCount; i++)
{
vrts[i+0].pos = v0; vrts[0].otherPos = v1;
vrts[i+1].pos = v1; vrts[1].otherPos = v0;
vrts[i+2].pos = v0; vrts[2].otherPos = v1;
vrts[i+3].pos = v1; vrts[3].otherPos = v0;

g_fThickness = 0.5f;
vrts[i+0].thickness = D3DXVECTOR3( -g_fThickness, 0.f, g_fThickness * 0.5f );
vrts[i+1].thickness = D3DXVECTOR3(  g_fThickness, 0.f, g_fThickness * 0.5f );
vrts[i+2].thickness = D3DXVECTOR3(  g_fThickness, 0.f, g_fThickness * 0.5f );
vrts[i+3].thickness = D3DXVECTOR3( -g_fThickness, 0.f, g_fThickness * 0.5f );

vrts[i+0].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.f, 0.f );
vrts[i+1].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.25f, 0.f );
vrts[i+2].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.f, 0.25f );
vrts[i+3].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.25f, 0.25f );
}

device->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, 0, linesCount*4, linesCount*2, indexBuffer, D3DFMT_INDEX32, vrts, sizeof( TVertex ) );


Now, I'm not sure how to fill indexBuffer, what values I should give to the index buffer?

Edited by Medo3337

##### Share on other sites

First off, use D3DPT_LINELIST or D3DPT_LINESTRIP. Then the index buffer values correspond to vertex buffer positions.

So if the lines are not connected there are 8 vertices. The indices are 0-7.

If the lines are connected then there are 5 vertices and you don't need an index buffer and you can use DrawPrimitiveUP.

##### Share on other sites

@menohack: I'm not drawing normal lines, instead, I'm drawing volumetric lines (which is actually billboards)

Up.

##### Share on other sites

1.

I would advice you to use DrawIndexedPrimitive instead DrawIndexedPrimitiveUP which is slow.

2.

Create VB, IB and vertex declaration instead FVF.

struct TInputVertex
{
float4 pos : POSITION; // Position of this vertex
float4 otherPos : NORMAL; // Position of the other vertex at the other end of the line.
float4 texOffset : TEXCOORD0; // Tex coord offset.
float3 thickness : TEXCOORD1; // Thickness info.
};


Vetex declaration becomes

    D3DVERTEXELEMENT9 vertexElements[] =
{
{0,  0,  D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,  0},
{0, 16,  D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,  0},
{0, 32,  D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD,  0},
{0, 48,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD,  1},
D3DDECL_END()
};

HRESULT hr = d3d9device->CreateVertexDeclaration(vertexElements, &vDeclaration);
if(FAILED(hr))
...// act on error


vertex

struct Vertex
{
D3DXVECTOR4 pos;
D3DXVECTOR4 normal;
D3DXVECTOR4 texCoordOff;
D3DXVECTOR3 thickness;
};


VB and IB


const std::size_t maxLinesCnt = 1000;
const std::size_t vertsPerLine  = 4;
const std::size_t triPerLine      = 2;
const std::size_t numVerts      = maxLinesCnt * vertsPerLine;

D3DPOOL pool = D3DPOOL_DEFAULT;
DWORD usage  = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
UINT len     = sizeof(Vertex) * numVerts;
hr = d3d9device->CreateVertexBuffer(len, usage, 0, pool, &vBuffer, nullptr);
if(FAILED(hr))
...// act on error

D3DFORMAT indFormat  = (std::numeric_limits<WORD>::max() < numVerts) ? D3DFMT_INDEX32 : D3DFMT_INDEX16;
std::size_t indBytes = (std::numeric_limits<WORD>::max() < numVerts) ? sizeof(DWORD) : sizeof(WORD);
len = indBytes * maxLinesCnt * triPerLine * 3;
hr = d3d9device->CreateIndexBuffer(len, usage, indFormat, pool, &iBuffer, nullptr);
if(FAILED(hr))
...// act on error


Fill your VB and IB and set these before drawing:

d3d9device->SetVertexDeclaration(vDeclaration);
d3d9device->SetIndices(iBuffer);
d3d9device->SetStreamSource(0, vBuffer, 0, sizeof(Vertex));

d3d9device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, ...);

Edited by belfegor

##### Share on other sites

Ok, i looked a bit at volume lines demo from CodeSampler, but today i am to lazy to make project and test it out with above modifications.

I guess you could do something like this:

struct Line
{
D3DXVECTOR4 pt0;
D3DXVECTOR4 pt1;
};

std::vector<Line> vLines;
...
// fill lines
...
Vertex* vrts;
vBuffer->Lock(... &vrts);
std::size_t numTriDraw = 0u;
for(std::size_t i = 0; i < vLines.size(); ++i)
{
if( i > maxNumLines)
{
vBuffer->Unlock();
d3d9device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, ..., numTriDraw);
vBuffer->Lock( ... &vrts);
numTriDraw = 0u;
}
numTriDraw += triPerLine;

const D3DXVECTOR4& v0 = vLines.pt0;
const D3DXVECTOR4& v1 = vLines.pt1;

vrts[i*4 + 0].pos = v0;        vrts[i*4 + 0].otherPos = v1;
vrts[i*4 + 1].pos = v1;        vrts[i*4 + 1].otherPos = v0;
vrts[i*4 + 2].pos = v0;        vrts[i*4 + 2].otherPos = v1;
vrts[i*4 + 3].pos = v1;        vrts[i*4 + 3].otherPos = v0;

vrts[i*4 + 0].thickness = D3DXVECTOR3( -g_fThickness, 0.f, g_fThickness * 0.5f );
vrts[i*4 + 1].thickness = D3DXVECTOR3(  g_fThickness, 0.f, g_fThickness * 0.5f );
vrts[i*4 + 2].thickness = D3DXVECTOR3(  g_fThickness, 0.f, g_fThickness * 0.5f );
vrts[i*4 + 3].thickness = D3DXVECTOR3( -g_fThickness, 0.f, g_fThickness * 0.5f );

vrts[i*4 + 0].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.f, 0.f );
vrts[i*4 + 1].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.25f, 0.f );
vrts[i*4 + 2].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.f, 0.25f );
vrts[i*4 + 3].texOffset = D3DXVECTOR4( g_fThickness, g_fThickness, 0.25f, 0.25f );
}
vBuffer->Unlock()

if(numTriDraw > 0u)
{
d3d9device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, ..., numTriDraw);
}

Edited by belfegor

##### Share on other sites

Here is the modified CodeSampler demo: http://pastebin.com/VRCNdUw6

##### Share on other sites

Good job! Well done :-)

Can you give me idea how should I generally determine the index buffer? How did you know that it's 0, 2, 1, 2, 3, 1?

pIndices[0+i] = 0+j;
pIndices[1+i] = 2+j;
pIndices[2+i] = 1+j;
pIndices[3+i] = 2+j;
pIndices[4+i] = 3+j;
pIndices[5+i] = 1+j;


##### Share on other sites

Triangle strip MSDN

I don't know to create the right algorithm for triangle strips (since it has a bit weird order), but in this case it was easy since there is 2 triangle strip per line, so i just follow rule for first two triangles:

The system uses vertices v1, v2, and v3 to draw the first triangle; v2, v4, and v3 to draw the second triangle...

0 1 2

1 3 2

Since that was original way to create each line vertices (with triangle strip in mind), and also It depends in what order vertices are fed to vertex buffer, so i changed indices to CCW order:

0 2 1

2 3 1

I just saw something in original code, to get default cull mode comment this in shader:

technique VolumeLine
{
pass p0
{
//CullMode = none; // THIS
AlphaBlendEnable = true;
SrcBlend = one;
DestBlend = one;
alpharef = 0.9;
alphafunc = GreaterEqual;
ZEnable = false;
}
}


and also (redundant) in cpp:

// Set up some device states.
D3DXMatrixPerspectiveFovLH( &g_mProjection, 45.f,
(float)d3dpp.BackBufferWidth / (float)d3dpp.BackBufferHeight,
0.1f, 100.f );

g_pD3DDevice->SetTransform( D3DTS_PROJECTION, &g_mProjection );
g_pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
//g_pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE ); // THIS


1. 1
2. 2
Rutin
18
3. 3
khawk
15
4. 4
A4L
14
5. 5

• 10
• 13
• 26
• 10
• 11
• ### Forum Statistics

• Total Topics
633745
• Total Posts
3013667
×