D3DX9 PRT Preprocessor

Started by
6 comments, last by DragonGeo2 13 years, 2 months ago
So I've been messing around a little bit with using the D3DX9 PRT precomputation engine (June 2010 version, not that they've changed the interface in a long time).

1) I can't get it to run outside of the SDK samples (all two of them). My code compiles, and then when in D3D debug mode with all of the preprocessor definitions for debugging and the OutputDebugString message verbosity cranked all the way up, I manage to spot some crazy error messages that (according to Google) I seem to be the first person to ever get (bonus points for breaking something awesomely!). So due to that, I'd like to know if anybody has seen any examples of using the D3DX9 PRT engine outside of the D3D SDK.

2) The errors I am getting are kind of discouraging, so does anybody know of any other non-D3DX PRT precomputation engines that are available (source code is a plus)? I think I had read somewhere that ATI had a proprietary internal PRT preprocessor, but that it was built outside of the D3DX one for their Sushi demo engine. However, I don't see ATI giving this tool out in the near future.
Advertisement

So I've been messing around a little bit with using the D3DX9 PRT precomputation engine (June 2010 version, not that they've changed the interface in a long time).

1) I can't get it to run outside of the SDK samples (all two of them). My code compiles, and then when in D3D debug mode with all of the preprocessor definitions for debugging and the OutputDebugString message verbosity cranked all the way up, I manage to spot some crazy error messages that (according to Google) I seem to be the first person to ever get (bonus points for breaking something awesomely!). So due to that, I'd like to know if anybody has seen any examples of using the D3DX9 PRT engine outside of the D3D SDK.

2) The errors I am getting are kind of discouraging, so does anybody know of any other non-D3DX PRT precomputation engines that are available (source code is a plus)? I think I had read somewhere that ATI had a proprietary internal PRT preprocessor, but that it was built outside of the D3DX one for their Sushi demo engine. However, I don't see ATI giving this tool out in the near future.


What are some of the error messages you're getting? I could try and help you decipher them, if you want.

Unfortunately I don't know of any other other PRT engines out there.
Thanks for taking the time to look at this for me.

Well as an aside, when trying to create a D3DXMesh with read/write buffer capabilities (that is, without specifying D3DXMESH_WRITEONLY), I get the warning:
Direct3D9: (INFO) :Failed to create driver indexbuffer[/quote]

The specific call I am using to generate this warning is:
HRESULT hr = D3DXCreateMeshFVF(nTris, nVerts, D3DXMESH_32BIT,
(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_DIFFUSE | D3DFVF_TEX1), dev, &PRTMeshIn);


Actually, any attempt to create an index buffer without the WRITEONLY flag set results in that warning, even if I'm not using D3DXCreateMesh to do it. But this isn't the mysterious error that I am getting involving PRT, it's just something that I see a lot when making read/write index buffers.

Back to the main problem: The mesh I am passing to the PRT engine has 99359 vertices and 81144 triangles (it is a concatenation of 504 meshes that form a small scene). I call D3DXCreateMeshFVF on it (using the aforementioned call) and then I lock the AB, the IB, and the VB and fill those in (I'm using LockAttributeBuffer, am I supposed to be using SetAttributeTable instead?). Then I unlock the VB, IB, and AB. Then I call:PRTMeshIn->CloneMesh(D3DXMESH_32BIT, PRT_elements, dev, &PRTMeshOut);

This is the same or very similar to the call in the SDK samples that are used to add the many bytes of per-vertex PRT data to the mesh so as to allow PRT computation to take place. After that, I call GenerateAdjacency on the new (cloned) mesh, and then finally I call D3DXCreatePRT engine. Firstly, it gave me the errors:
D3DX: Texture coordinates were outside the [0, 1] range on the u-axis.
D3DX: Texture coordinates were outside the [0, 1] range on the v-axis.[/quote]

So then I hacked my vertex buffer copying code to clamp texture coordinates in the PRT mesh. Then it gave me these bizarre errors (and returned D3DERR_INVALIDCALL ) :
D3DX: Non manifold edges in mesh - not a good idea...
D3DX: Winding order is incosistant inside mesh
D3DX: Must have non-zero number of attributes[/quote]So it looks like, spelling mistake in the warning message aside, I don't really know where to begin here. For one, I am fairly certain that my winding order IS consistent within my mesh as I batch and render ALL of the meshes in this scene using the same winding order: D3DCULL_CW. Also, I'm fairly certain that the number of attributes is non-zero as I just got done filling the attribute buffer with indices from 0 to 503 (using one attribute ID per mesh).

So do you have any idea what could be wrong here?

The full sourcecode for what I am doing is shown below:const CellCoords thisCC(0, 0);
std::map<CellCoords, CELL* const>::const_iterator it = ExtCellLookup.find(thisCC);
const std::vector<Object*>& objs = *(it->second->gameObjsList);
const unsigned nObjs = (const unsigned)(objs.size() );
unsigned nVerts = 0;
unsigned nTris = 0;
for (unsigned x = 0; x < nObjs; ++x)
{
const Object* const thisObj = objs[x];
if (thisObj->type == Object::ot_static)
{
const unsigned nMeshes = (const unsigned)(thisObj->mesh.meshes.size() );
for (unsigned y = 0; y < nMeshes; ++y)
{
nVerts += thisObj->mesh.meshes[y].nVerts;
nTris += thisObj->mesh.meshes[y].nTris;
}
}
}

LPD3DXMESH PRTMeshIn = NULL;
ERRHRPTR(D3DXCreateMeshFVF(nTris, nVerts, D3DXMESH_32BIT, TERRAIN_FVF, dev, &PRTMeshIn), PRTMeshIn, "Failed on D3DXCreateMeshFVF for PRTMeshIn");
bprintf("Allocated PRT Mesh Space with %u verts and %u tris\n", nVerts, nTris);

// Load the vertex/index data:
terrainVertex* vb = NULL;
ERRHRPTR(PRTMeshIn->LockVertexBuffer(0, (LPVOID* const)&vb), vb, "Error locking VB");

unsigned* ib = NULL;
ERRHRPTR(PRTMeshIn->LockIndexBuffer(0, (LPVOID* const)&ib), ib, "Error locking IB");

DWORD* ab = NULL;
ERRHRPTR(PRTMeshIn->LockAttributeBuffer(NULL, (LPDWORD* const)&ab), ab, "Error locking AB");

unsigned nAttrs = 0;
unsigned nVertsSoFar = 0; // Used for offsetting the indices in the IB
for (unsigned x = 0; x < nObjs; ++x)
{
const Object* const thisObj = objs[x];
if (thisObj->type == Object::ot_static)
{
const unsigned nMeshes = (const unsigned)(thisObj->mesh.meshes.size() );
for (unsigned y = 0; y < nMeshes; ++y)
{
const unsigned thisNTris = thisObj->mesh.meshes[y].nTris;
const unsigned thisNVerts = thisObj->mesh.meshes[y].nVerts;

// Mark the AB:
for (unsigned z = 0; z < thisNTris; ++z)
ab[z] = nAttrs;
ab += thisNTris;
++nAttrs;

// Mark the IB:
unsigned short* readib = NULL;
ERRHRPTR(thisObj->mesh.ib->Lock(0, 0, (LPVOID* const)&readib, D3DLOCK_READONLY), readib, "Err reading from IB");
for (unsigned z = 0; z < thisNTris * 3; ++z)
ib[z] = (const unsigned)readib[z] + nVertsSoFar;
ERRHR(thisObj->mesh.ib->Unlock(), "Error unlocking read IB");
readib = NULL;
ib += (thisNTris * 3);

// Mark the VB:
terrainVertex* readvb = NULL;
ERRHRPTR(thisObj->mesh.vb->Lock(0, 0, (LPVOID* const)&readvb, D3DLOCK_READONLY), readvb, "Error reading from VB");
for (unsigned z = 0; z < thisNVerts; ++z)
{
terrainVertex& thisVert = vb[z];
thisVert = readvb[z];

if (thisVert.texCoords.xPos < 0.0f)
thisVert.texCoords.xPos = 0.0f;
else if (thisVert.texCoords.xPos > 1.0f)
thisVert.texCoords.xPos = 1.0f;

if (thisVert.texCoords.yPos < 0.0f)
thisVert.texCoords.yPos = 0.0f;
else if (thisVert.texCoords.yPos > 1.0f)
thisVert.texCoords.yPos = 1.0f;
}
ERRHR(thisObj->mesh.vb->Unlock(), "Error unlocking read VB");
nVertsSoFar += thisNVerts;
readvb = NULL;
vb += thisNVerts;
}
}
}

ERRHR(PRTMeshIn->UnlockAttributeBuffer(), "Error unlocking AB");
ab = NULL;

ERRHR(PRTMeshIn->UnlockIndexBuffer(), "Error unlocking IB");
ib = NULL;

ERRHR(PRTMeshIn->UnlockVertexBuffer(), "Error unlocking VB");
vb = NULL;

LPD3DXMESH PRTMeshOut = NULL;
ERRHRPTR(PRTMeshIn->CloneMesh(D3DXMESH_32BIT, PRT_elements, dev, &PRTMeshOut), PRTMeshOut, "Error in CloneMesh for PRTMeshOut");
PRTMeshIn->Release();
PRTMeshIn = NULL;

// Make an adjacency buffer:
DWORD* const adj = new DWORD[nTris * 3];
ERRHRPTR(PRTMeshOut->GenerateAdjacency(1e-6f, adj), adj, "Error in GenerateAdjacency");

LPD3DXPRTENGINE prtengine = NULL;
ERRHRPTR(D3DXCreatePRTEngine(PRTMeshOut, adj, TRUE, NULL, &prtengine), prtengine, "Failed to create PRT engine");
Okay, I tried using D3DXValidMesh to see what it said and it cites:
D3DX: D3DXValidIndices: A neighbor triangle index(78902) was found more than once on triangle 78901
D3DX: D3DXValidIndices: (Likely problem is that two triangles share same points with opposite orientations)
D3DX: D3DXValidIndices: A neighbor triangle index(78901) was found more than once on triangle 78902
D3DX: D3DXValidIndices: (Likely problem is that two triangles share same points with opposite orientations)[/quote]But so what? Why is it an error to have a triangle face in two directions at once? Isn't this common practice amongst artists to force two-sided triangles when D3DCULL_CW or CCW is enabled?
I looked at triangles #78901 and #78902 and they have indices:
tri78901: 833, 853, 854
tri78902: 833, 854, 835

Furthermore, the float3 position component of vertices #835 and #853 are:
vert835: position {xPos=2.8177976e-005 yPos=727.30304 zPos=-331.13400 }
vert853: position {xPos=2.8177976e-005 yPos=727.30304 zPos=-331.13400 }

But these two vertices are not the same! The texcoords are different (which explains why D3DXMesh::Optimize correctly did not fold these two vertices into one vertex) :
vert835: texCoords {xPos=0.75000095 yPos=6.4504614 }
vert853: texCoords {xPos=0.74999917 yPos=-5.4504614 }

Anyhow, if I *further* hack my code apart (all this hacking just to get PRT working is part of the reason I was interested in alternative PRT engines) such that the new indices for these triangles are:
tri78901: 0, 1, 2
tri78902: 3, 4, 5

Then D3DXValidMesh spits out this:
D3DX: D3DXValidMesh: A bowtie was found. Bowties can be fixed by call D3DXCleanMesh
D3DX: D3DXValidMesh: A bowtie is the usage of a single vertex by two separate fans of triangles.
D3DX: D3DXValidMesh: The fix is to duplicate the vertex so that each fan has its own vertex.
D3DX: D3DXValidMesh: Bowtie found around vertex 0 shared by faces 1930 and 1745
D3DX: D3DXValidMesh: Bowtie found around vertex 2439 shared by faces 4845 and 4859[/quote]This list goes on and on for many many entries and it looks like most if not all of my triangles have bowties (though I am not using triangle fans at all, I am using triangle LISTS).

Anyhow, let's take D3DX's advice here and use D3DXCleanMesh to try to fix this issue...

Calling D3DXCleanMesh with the D3DXCLEAN_BOWTIES parameter works (as verified by D3DXValidMesh) to remove the many bowties from the input mesh. However, D3DXCleanMesh also seems to remove the attribute tables that D3DXMesh::Optimize had generated, so let's throw in another optimize pass with D3DXMESHOPT_ATTRSORT passed into it.

Oh hey now D3DXCreatePRTEngine isn't crashing anymore or returning D3DERR_INVALIDMESH. But it is still spitting out the warnings:
D3DX: Non manifold edges in mesh - not a good idea...
D3DX: Winding order is incosistant inside mesh[/quote]

Oh well, that's all I really wanted to accomplish. Now to play around with PRT and see if I can't break some more things! Thanks GameDev for being an awesome rubber ducky once again...
Hmmm, today I'm getting a new error.

It's returning D3DERR_INVALIDCALL from ID3DXCompBuffer::ExtractToMesh() when I pass in the parameters:

const HRESULT hr = compBuffer->ExtractToMesh(
numPCA, // = 108
D3DDECLUSAGE_BLENDWEIGHT,
1,
PRTMeshOpt);

The debug window says:
D3DX: Decl must include fields that are being stored[/quote]
But then when I check the decl, it looks like this:

{0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0},
{0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},

{0, 32, D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0},
{0, 36, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 1},
{0, 52, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 2},
{0, 68, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 3},
{0, 84, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 4},
{0, 100, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 5},
{0, 116, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 6},
D3DDECL_END()

Just like in the PRT sample. Anyone have any ideas what I could be doing wrong this time?

As an aside (really unimportant), I am getting a *bunch* of warnings from the ID3DXCompBuffer::NormalizeData() call. Here is my CPCA data (from D3DXCreatePRTCompBuffer):

0:24.159,1:23.4702,2:18.2266,3:13.2868,4:9.22632,5:9.01283,6:7.83637,7:7.74012,8:4.7412,9:4.07041,10:3.30417,11:2.99374,12:2.75513,13:2.61905,14:2.53517,15:2.35827,16:2.28648,17:2.22668,18:2.19849,19:2.06878,20:2.01303,21:1.94696,22:1.89736,23:1.8886,24:1.75462,25:1.6786,26:1.61502,27:1.55268,28:1.28009,29:1.22815,30:1.16904,31:1.11033,32:1.09248,33:1.05889,34:1.04792,35:0.970803,36:0.960798,37:0.92903,38:0.915257,39:0.897479,40:0.825967,41:0.819196,42:0.770105,43:0.632364,44:0.550767,45:0.33493,46:0.302352,47:0.280272,48:0.268512,49:0.256499,50:0.222959,51:0.214292,52:0.205298,53:0.189197,54:0.185428,55:0.182692,56:0.152369,57:0.134242,58:0.123444,59:0.113712,60:0.106282,61:0.105848,62:0.0922538,63:0.0829579,64:0.078667,65:0.0772636,66:0.0639746,67:0.0630302,68:0.0607521,69:0.057155,70:0.0455355,71:0.0351868,72:6.71577e-006,73:5.65773e-006,74:4.5162e-006,75:4.26041e-006,76:2.27857e-006,77:2.03437e-006,78:1.6654e-006,79:1.62659e-006,80:1.59743e-006,81:8.60336e-007,82:7.82631e-007,83:7.26784e-007,84:6.67613e-007,85:5.61827e-007,86:5.53026e-007,87:4.99717e-007,88:4.64925e-007,89:4.39114e-007,90:4.09796e-007,91:3.64396e-007,92:3.56146e-007,93:3.44603e-007,94:3.14188e-007,95:2.92631e-007,96:2.8632e-007,97:2.79102e-007,98:2.65384e-007,99:2.50505e-007,100:2.42782e-007,101:2.38272e-007,102:2.33528e-007,103:2.06712e-007,104:1.86666e-007,105:1.3328e-007,106:0,107:0,
[/quote]
And here is the debug output that I get from NormalizeData():

D3DX: Channel 72 seems to have no energy
D3DX: Channel 74 seems to have no energy
D3DX: Channel 75 seems to have no energy
D3DX: Channel 76 seems to have no energy
D3DX: Channel 77 seems to have no energy
D3DX: Channel 78 seems to have no energy
D3DX: Channel 79 seems to have no energy
D3DX: Channel 80 seems to have no energy
D3DX: Channel 81 seems to have no energy
D3DX: Channel 82 seems to have no energy
D3DX: Channel 83 seems to have no energy
D3DX: Channel 84 seems to have no energy
D3DX: Channel 85 seems to have no energy
D3DX: Channel 86 seems to have no energy
D3DX: Channel 87 seems to have no energy
D3DX: Channel 88 seems to have no energy
D3DX: Channel 89 seems to have no energy
D3DX: Channel 90 seems to have no energy
D3DX: Channel 91 seems to have no energy
D3DX: Channel 92 seems to have no energy
D3DX: Channel 93 seems to have no energy
D3DX: Channel 94 seems to have no energy
D3DX: Channel 95 seems to have no energy
D3DX: Channel 96 seems to have no energy
D3DX: Channel 97 seems to have no energy
D3DX: Channel 98 seems to have no energy
D3DX: Channel 99 seems to have no energy
D3DX: Channel 100 seems to have no energy
D3DX: Channel 101 seems to have no energy
D3DX: Channel 102 seems to have no energy
D3DX: Channel 103 seems to have no energy
D3DX: Channel 104 seems to have no energy
D3DX: Channel 105 seems to have no energy
D3DX: Channel 106 seems to have no energy
D3DX: Channel 107 seems to have no energy
[/quote]
I understand that it's not possible to normalize a PCA weight that is less than the epsilon (1.0e-6 in this case), but wouldn't CPCA normally generate these effects? (Why does it have to warn me about expected behavior?)
If numPCA = 108, then isn't that too many coefficients to store in your vertex buffer? You only have enough room for 24 per vertex.

If numPCA = 108, then isn't that too many coefficients to store in your vertex buffer? You only have enough room for 24 per vertex.

Hmmmm yeah you might be right there! Lemme check that out, and thanks for the tip!

Edit: Yeah that was it, thanks again! :D

This topic is closed to new replies.

Advertisement