• Advertisement
Sign in to follow this  

DrawIndexedPrimitive help

This topic is 4177 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 trying to render 4 patches with one VB and IB, with culling. I am not having any luck figuring out the DrawIndexedPrimitive() and its parameters. Whats funny is the two books I have don't agree on the function of the parameters. One says they are for the VB the other IB... Here is my code.
dxApp.d3dDevice->DrawIndexedPrimitive(type, 0, 0, NUM_VERTICES, indicesSum, NUM_POLYGONS);
indicesSum += NUM_INDICES;

The issue is my terrain is rendering about 3/4 of it and the last 1/4 is all fragmented? Thanks

Share this post


Link to post
Share on other sites
Advertisement
The way I see it, if I understand the situation, you'd want to the same index buffer for all the patches, and all the patches are in the same vertex buffer. In that case, BaseVertexIndex is the parameter you'd use to offset inside the vertex buffer, and you won't offset the index buffer, so StartIndex will be 0.

In the current call, NUM_VERTICES has to be the total number of vertices in your buffer. I suspect it isn't and that's why you fail. In what I described above it need only be the size of one patch (which I suspect it is now).

(If I've misunderstood, feel free to provide more information.)

Share this post


Link to post
Share on other sites
The DIP() params have always been confusing. I've been using it for years and I still muddle them up occasionally [headshake]

Best advice I can give is to draw out your parameters as a diagram on a piece of paper.

Take a simple case where each of your patches only has, say, 4 vertices and 6 indices (or whatever) and draw the buffers out and then some arrows corresponding to the various parameters. As was suggested in your journal entry, Jonathan Steed's and Tom Forsyth's explanations are great - even if they don't immediately seem it [smile]

hth
Jack

Share this post


Link to post
Share on other sites
Quote:
Original post by ET3D
The way I see it, if I understand the situation, you'd want to the same index buffer for all the patches, and all the patches are in the same vertex buffer. In that case, BaseVertexIndex is the parameter you'd use to offset inside the vertex buffer, and you won't offset the index buffer, so StartIndex will be 0.

In the current call, NUM_VERTICES has to be the total number of vertices in your buffer. I suspect it isn't and that's why you fail. In what I described above it need only be the size of one patch (which I suspect it is now).

(If I've misunderstood, feel free to provide more information.)



I have one VB that holds all the vertices for the mesh and then I have one IB that holds all the indices for the VB. e.g. 513x513 mesh with 33x33 patches I have 16x16=256 WORD pointers that I send my indices to and then I send those to my IB. Then I want to render each patch in one call if its in view. Here is my setup code and rendering code.


for(unsigned long z = 0; z < (mapData.map_Z - 1) / (PATCH_SIZE - 1); ++z)
{
for(unsigned long x = 0; x < (mapData.map_X - 1) / (PATCH_SIZE - 1); ++x)
{
maxX = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxX;
maxY = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxY;
maxZ = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxZ;
minX = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minX;
minY = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minY;
minZ = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minZ;

// Check to see if the corners of the patches are within the frustum.
if (!gCamera.pointInFrustum(maxX, maxY, maxZ) &&
!gCamera.pointInFrustum(minX, maxY, minZ) &&
!gCamera.pointInFrustum(minX, maxY, maxZ) &&
!gCamera.pointInFrustum(maxX, maxY, minZ) &&
!gCamera.pointInFrustum(maxX, minY, maxZ) &&
!gCamera.pointInFrustum(minX, minY, minZ) &&
!gCamera.pointInFrustum(minX, minY, maxZ) &&
!gCamera.pointInFrustum(maxX, minY, minZ))
{
indicesSum += NUM_INDICES;
continue;
}
dxApp.d3dDevice->DrawIndexedPrimitive(type, 0, 0, NUM_VERTICES, indicesSum, NUM_POLYGONS);
indicesSum += NUM_INDICES;
}
}

//setup
unsigned long currentIndex = 0;
unsigned long index = 0;
unsigned long index1 = 0;
unsigned long index2 = 0;
unsigned long index3 = 0;
unsigned long startx = 0;
unsigned long startz = 0;
unsigned long endx = 0;
unsigned long endz = 0;
unsigned long rows = ((mapData.map_Z - 1) / (PATCH_SIZE - 1));
unsigned long columns = ((mapData.map_X - 1) / (PATCH_SIZE - 1));
float maxX = 0.0f, maxY = 0.0f, maxZ = 0.0f;
float minX = 0.0f, minY = 0.0f, minZ = 0.0f;

CreatePatches();

// Calculate the triangle index lists for each patch
for(unsigned long z = 0; z < rows; ++z)
{
for(unsigned long x = 0; x < columns; ++x)
{
index = z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x;

// Calculate the extents of the chunk.
startx = x * PATCH_SIZE;
startz = z * PATCH_SIZE;
endx = startx + PATCH_SIZE;
endz = startz + PATCH_SIZE;

index1 = (startz * mapData.map_X + startx);
maxX = float(startx);
minX = float(startx);
maxY = vertices[index1].pos.y;
minY = vertices[index1].pos.y;
maxZ = float(startz);
minZ = float(startz);

// Loop through the chunk extents and create the list.
indexBuffer->Lock(0, 0, (void**)&patch[index].index_buffer, 0);
for(unsigned long zz = startz; zz < endz - 1; ++zz)
{
for(unsigned long xx = startx; xx < endx - 1; ++xx)
{
index3 = (zz * mapData.map_X + xx);
// Update the min and max values.
maxX = maxX > xx ? maxX : xx;
minX = minX < xx ? minX : xx;
maxY = maxY > vertices[index3].pos.y ? maxY : vertices[index3].pos.y;
minY = minY < vertices[index3].pos.y ? minY : vertices[index3].pos.y;
maxZ = maxZ > zz ? maxZ : zz;
minZ = minZ < zz ? minZ : zz;
maxZ = maxZ > (zz + 1) ? maxZ : (zz + 1);
minZ = minZ < (zz + 1) ? minZ : (zz + 1);

patch[index].index_buffer[index2] = zz * mapData.map_X + xx + 1;
patch[index].index_buffer[index2 + 1] = zz * mapData.map_X + xx;
patch[index].index_buffer[index2 + 2] = (zz + 1) * mapData.map_X + xx + 1;

patch[index].index_buffer[index2 + 3] = (zz + 1) * mapData.map_X + xx + 1;
patch[index].index_buffer[index2 + 4] = zz * mapData.map_X + xx;
patch[index].index_buffer[index2 + 5] = (zz + 1) * mapData.map_X + xx;
index2+=6;
}
}
indexBuffer->Unlock();

// Assign the min and max values found
//scale the max min values to terrain scale
maxX *= mapData.terrainScaleFactor;
maxZ *= mapData.terrainScaleFactor;
minX *= mapData.terrainScaleFactor;
minZ *= mapData.terrainScaleFactor;

patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxX = maxX;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxY = maxY;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxZ = maxZ;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minX = minX;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minY = minY;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minZ = minZ;
}
}




Share this post


Link to post
Share on other sites
*BUMP anyone? I have looked at http://tomsdxfaq.blogspot.com/2002_05_01_tomsdxfaq_archive.html

and if that is the correct way I am totally lost on how one is supposed to keep track of all that info just to render some polygons. It is IMO ridiculous vs. OpenGL. What I want to do should be simple as calling 8 vertices and 12 polygons but 4 times and need to offset the IB to call those indices to render those polygons in the VB...

Share this post


Link to post
Share on other sites
Quote:
Original post by MARS_999
and if that is the correct way I am totally lost on how one is supposed to keep track of all that info just to render some polygons. It is IMO ridiculous vs. OpenGL. What I want to do should be simple as calling 8 vertices and 12 polygons but 4 times and need to offset the IB to call those indices to render those polygons in the VB...

You are making no sense. This isn't OpenGL.

DrawIndexedPrimitive is simple. It really is.
HRESULT DrawIndexedPrimitive(    D3DPRIMITIVETYPE Type,    INT BaseVertexIndex,    UINT MinIndex,
UINT NumVertices, UINT StartIndex, UINT PrimitiveCount);


Let's assume for now, that BaseVertexIndex is 0, as that makes things simpler. I'll get to using that parameter in a second.

I'll start with the MinIndex and NumVertices parameters. These are old, and are there for software renderers. Under the assumption you're using a HAL device, you can safely set these two parameters to MinIndex = 0 and NumVertices = NumberOfVertsInVB. They need to be correct because they are checked by the GPU, but they are not used for anything, so as long as they are valid, everything is fine.

Once you've set the first 3 parameters to these values, DrawIndexedPrimitive behaves almost exactly like DrawPrimitive does. You're left with 2 parameters, StartIndex, which tells it from where in the Index Buffer to start, and PrimitiveCount -- how many primitives to draw.

Using these parameter values is enough to allow you to use DrawIndexedPrimitive for almost any use. In fact, I find I rarely use a BaseVertexIndex value other than 0. Using BaseVertexIndex is essentially the same as going through the entire Index Buffer, and adding the value to every index in the buffer. Uses for this very, very special case are not that common, and in most cases, simply duplicating the data in the Index Buffer would be more benefitial, as it allows you to draw both cases in one draw call. Unless you've got a specific use for this feature, just keep BaseVertexIndex at 0. Also, if you use it, I'm quite sure you'd need to decrease NumVertices appropriately.

Hope this helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by sirob
Quote:
Original post by MARS_999
and if that is the correct way I am totally lost on how one is supposed to keep track of all that info just to render some polygons. It is IMO ridiculous vs. OpenGL. What I want to do should be simple as calling 8 vertices and 12 polygons but 4 times and need to offset the IB to call those indices to render those polygons in the VB...

You are making no sense. This isn't OpenGL.

DrawIndexedPrimitive is simple. It really is.
HRESULT DrawIndexedPrimitive(    D3DPRIMITIVETYPE Type,    INT BaseVertexIndex,    UINT MinIndex,
UINT NumVertices, UINT StartIndex, UINT PrimitiveCount);


Let's assume for now, that BaseVertexIndex is 0, as that makes things simpler. I'll get to using that parameter in a second.

I'll start with the MinIndex and NumVertices parameters. These are old, and are there for software renderers. Under the assumption you're using a HAL device, you can safely set these two parameters to MinIndex = 0 and NumVertices = NumberOfVertsInVB. They need to be correct because they are checked by the GPU, but they are not used for anything, so as long as they are valid, everything is fine.

Once you've set the first 3 parameters to these values, DrawIndexedPrimitive behaves almost exactly like DrawPrimitive does. You're left with 2 parameters, StartIndex, which tells it from where in the Index Buffer to start, and PrimitiveCount -- how many primitives to draw.

Using these parameter values is enough to allow you to use DrawIndexedPrimitive for almost any use. In fact, I find I rarely use a BaseVertexIndex value other than 0. Using BaseVertexIndex is essentially the same as going through the entire Index Buffer, and adding the value to every index in the buffer. Uses for this very, very special case are not that common, and in most cases, simply duplicating the data in the Index Buffer would be more benefitial, as it allows you to draw both cases in one draw call. Unless you've got a specific use for this feature, just keep BaseVertexIndex at 0. Also, if you use it, I'm quite sure you'd need to decrease NumVertices appropriately.

Hope this helps.


Thanks for the reply, I know this isn't OpenGL, but I have worked with GL for years and am trying to get my head around DX. Now what you posted will this only work for a single call? Where you want to render only a single mesh in one call? I have a single mesh but its broken up into 4 parts for now and each parts indices and vertices are all in one VB and one IB. I called this and


//looped 4x due to 65x65 terrain size patches are 33x33 so 4 grids will be rendered and this block below will be called 4x...
dxApp.d3dDevice->DrawIndexedPrimitive(type, 0, 0, mapData.map_X*mapData.map_Z, indicesSum, NUM_POLYGONS);
indicesSum += NUM_INDICES;




this is the screen I get

http://members.gamedev.net/Mars_999/Pics/error1.jpg

http://members.gamedev.net/Mars_999/Pics/error2.jpg

Share this post


Link to post
Share on other sites
MARS_999, since in your latest post it's still impossible to tell what, for example, mapData.map_X*mapData.map_Z is, it's really hard to tell you "this is wrong". Seeing the pictures, I suspect that NUM_INDICES may be wrong, but since you're the only one who knows what these values are, your options are either to make sure yourself that all the values are correct, or provide us with the info. IMO the best way would be to simply replace the constants in your code with the actual values you think are required, and if that doesn't work, post the code with the numbers so we can look at them.

BTW, as I said before, it still seems to me that you can use an index buffer that's for 33x33 vertices and reuse that. It's likely to make your code simpler, in addition to saving some memory.

Share this post


Link to post
Share on other sites
Quote:
Original post by ET3D
MARS_999, since in your latest post it's still impossible to tell what, for example, mapData.map_X*mapData.map_Z is, it's really hard to tell you "this is wrong". Seeing the pictures, I suspect that NUM_INDICES may be wrong, but since you're the only one who knows what these values are, your options are either to make sure yourself that all the values are correct, or provide us with the info. IMO the best way would be to simply replace the constants in your code with the actual values you think are required, and if that doesn't work, post the code with the numbers so we can look at them.

BTW, as I said before, it still seems to me that you can use an index buffer that's for 33x33 vertices and reuse that. It's likely to make your code simpler, in addition to saving some memory.



const unsigned long PATCH_SIZE = 33;
const unsigned long NUM_POLYGONS = (PATCH_SIZE - 1) * (PATCH_SIZE - 1) * 2;
const unsigned long NUM_VERTICES = PATCH_SIZE * PATCH_SIZE;
const unsigned long NUM_INDICES = NUM_POLYGONS * 3;



mapdata.mapX and mapZ are the texture width and height from the texture and that is currently 65x65.

So with a IB of only 33x33 I am confused would I need more than one VB then? Cause isn't the IB values represent the elements in the VB? So if you have 65x65 vertices (4225) and with a list you have 3 indices per triangle... Thanks again for the help...

Share this post


Link to post
Share on other sites
Like jollyjeffers said, start out with a smaller case...

Say you have a small terrain with only 16 quads and a patch is 4 quad (two triangles per quad).
You'd have 9 vertices per patch, and to draw one patch via triangle_list, you'd need 24 indices.

Assume that for a patch your vertices are arranged like this:

0,1,2,
3,4,5,
6,7,8

The patch's indices would be (2 tri's per line for each quad):

0,1,3, 3,1,4,
1,2,4, 4,2,5,
3,4,6, 6,4,7,
4,5,7, 7,5,8

The DIP would be:

DrawIndexedPrimitive(triangle_list, 0, 0, 9, 0, 8);

BaseVertexIndex is 0 (our first vertex is addressed by index 0)
MinIndex is 0 (the first vertex)
NumVertices is 9
StartIndex is 0 (start at the beginning of our index buffer)
PrimitiveCount is 8 (4 quads, 8 tris)

Say the next patch's vertices are this:

9,10,11,
12,13,14,
15,16,17

Using the same Index buffer we used for the first patch the DIP would be:

DrawIndexedPrimitive(triangle_list, 9, 0, 9, 0, 8);

Only the BaseVertexIndex changed here. This allows us to draw this new patch using the same index buffer, and assumes the vertices for your patches are arranged the same.

The other parameters stay the same because we are drawing the same number of vertices (just offset into the VB by BaseVertexIndex), and the same index buffer.

BaseIndexVertex is added to each index as it's used to access the vertex buffer. It's also added to MinIndex, which is why that parameter stayed at zero in the second call.

Share this post


Link to post
Share on other sites
Btw, my guess is that your indices are going over 65535 and you are using 16bit indices.

Each patch in your terrain is 1089 vertices, how many patches are there? If there are more than 60 then you have more than you can index in a single IB that covers the whole terrain.

If you use the approach I outline above, then you can have as many vertices as you want (up to memory limits) and still draw them with one small 16bit index buffer.

Share this post


Link to post
Share on other sites
Your values seem okay. Another thing to check is whether the buffer sizes (VB and IB) are correct.

As for using a 33x33 IB with a 65x65 VB, the idea is simply to use the BaseVertexIndex parameter to offset into the vertex buffer. After all, all 4 subtiles should have the same structure as far as triangles are concerned.

Share this post


Link to post
Share on other sites
Still no dice. Here is my revised code and no I wasn't going over the 65k limit I used a new WORD pointer for each patch...


const unsigned long PATCH_SIZE = 5;

//Create VBO
if(!terrain.CreateVertexBuffer(sizeof(Vertex) * mapData.map_X * mapData.map_Z, D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED))
MessageBox(ghWnd, "Error on Creating Vertexbuffer", "Error", MB_OK);

//Create IBO
//if(!terrain.CreateIndexBuffer(sizeof(WORD) * (mapData.map_X - 1) * (mapData.map_Z - 1) * 6, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED))
if(!terrain.CreateIndexBuffer(sizeof(WORD) * (PATCH_SIZE - 1)*(PATCH_SIZE - 1) * 6, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED))
MessageBox(ghWnd, "Error on Creating Indexbuffer", "Error", MB_OK);

//setup
bool Terrain::CreateIndexBufferData(void)
{
unsigned long currentIndex = 0;
unsigned long index = 0;
unsigned long index1 = 0;
unsigned long startx = 0;
unsigned long startz = 0;
unsigned long endx = 0;
unsigned long endz = 0;
unsigned long rows = ((mapData.map_Z - 1) / (PATCH_SIZE - 1));
unsigned long columns = ((mapData.map_X - 1) / (PATCH_SIZE - 1));
unsigned long x = 0;
unsigned long z = 0;
float maxX = 0.0f, maxY = 0.0f, maxZ = 0.0f;
float minX = 0.0f, minY = 0.0f, minZ = 0.0f;
WORD *index_Buffer = NULL;

CreatePatches();

//Calculate the triangle index lists for each patch
indexBuffer->Lock(0, 0, (void**)&index_Buffer, 0);
for(z = 0; z < PATCH_SIZE - 1; ++z)
{
for(x = 0; x < PATCH_SIZE - 1; ++x)
{
index_Buffer[index] = z * PATCH_SIZE + x + 1;
index_Buffer[index + 1] = z * PATCH_SIZE + x;
index_Buffer[index + 2] = (z + 1) * PATCH_SIZE + x + 1;

index_Buffer[index + 3] = (z + 1) * PATCH_SIZE + x + 1;
index_Buffer[index + 4] = z * PATCH_SIZE + x;
index_Buffer[index + 5] = (z + 1) * PATCH_SIZE + x;
index+=6;
}
}
indexBuffer->Unlock();

for(z = 0; z < rows; ++z)
{
for(x = 0; x < columns; ++x)
{
// Calculate the extents of the chunk.
startx = x * PATCH_SIZE;
startz = z * PATCH_SIZE;
endx = startx + PATCH_SIZE;
endz = startz + PATCH_SIZE;

index = (startz * mapData.map_X + startx);
maxX = float(startx);
minX = float(startx);
maxY = vertices[index].pos.y;
minY = vertices[index].pos.y;
maxZ = float(startz);
minZ = float(startz);

// Loop through the chunk extents and create the list.
for(unsigned long zz = startz; zz < endz - 1; ++zz)
{
for(unsigned long xx = startx; xx < endx - 1; ++xx)
{
index1 = (zz * mapData.map_X + xx);
// Update the min and max values.
maxX = maxX > xx ? maxX : xx;
minX = minX < xx ? minX : xx;
maxY = maxY > vertices[index1].pos.y ? maxY : vertices[index1].pos.y;
minY = minY < vertices[index1].pos.y ? minY : vertices[index1].pos.y;
maxZ = maxZ > zz ? maxZ : zz;
minZ = minZ < zz ? minZ : zz;
maxZ = maxZ > (zz + 1) ? maxZ : (zz + 1);
minZ = minZ < (zz + 1) ? minZ : (zz + 1);
}
}
// Assign the min and max values found
//scale the max min values to terrain scale
maxX *= mapData.terrainScaleFactor;
maxZ *= mapData.terrainScaleFactor;
minX *= mapData.terrainScaleFactor;
minZ *= mapData.terrainScaleFactor;

patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxX = maxX;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxY = maxY;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxZ = maxZ;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minX = minX;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minY = minY;
patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minZ = minZ;
}
}
return true;
}

//render
for(unsigned long z = 0; z < (mapData.map_Z - 1) / (PATCH_SIZE - 1); ++z)
{
for(unsigned long x = 0; x < (mapData.map_X - 1) / (PATCH_SIZE - 1); ++x)
{
maxX = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxX;
maxY = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxY;
maxZ = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].maxZ;
minX = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minX;
minY = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minY;
minZ = patch[z * ((mapData.map_X - 1) / (PATCH_SIZE - 1)) + x].minZ;

// Check to see if the corners of the patches are within the frustum.
if (!gCamera.pointInFrustum(maxX, maxY, maxZ) &&
!gCamera.pointInFrustum(minX, maxY, minZ) &&
!gCamera.pointInFrustum(minX, maxY, maxZ) &&
!gCamera.pointInFrustum(maxX, maxY, minZ) &&
!gCamera.pointInFrustum(maxX, minY, maxZ) &&
!gCamera.pointInFrustum(minX, minY, minZ) &&
!gCamera.pointInFrustum(minX, minY, maxZ) &&
!gCamera.pointInFrustum(maxX, minY, minZ))
continue;

dxApp.d3dDevice->DrawIndexedPrimitive(type, sum, 0, 9, 0, 8);
sum += (PATCH_SIZE+PATCH_SIZE) - 1;
}
}







I think I am close but still rendering all messed up... I made the IB small 96 indices and just use that to render the terrain over and over again? And with the vertex order its setup like this


for(unsigned long z = 0; z < mapData.map_Z; ++z)
{
for(unsigned long x = 0; x < mapData.map_X; ++x)
{




row by row

[Edited by - MARS_999 on August 13, 2006 6:10:05 PM]

Share this post


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

  • Advertisement