//Buffer creation functions.
LPDIRECT3DVERTEXDECLARATION9 D3DEngine::CreateDeclaration(Vertex* vertices)
{
int x = BitSet(vertices->m_type);
x+=1;
////////////////////////////////////////////////////
/*----------DECLARATIONS----------*/
D3DVERTEXELEMENT9* elements = new D3DVERTEXELEMENT9[x];
int i = 0;
if(vertices->m_type & VERT_POSITION)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT3;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_POSITION;
elements.UsageIndex = 0;
i++;
}
if(vertices->m_type & VERT_NORMAL)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT3;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_NORMAL;
elements.UsageIndex = 0;
i++;
}
if(vertices->m_type & VERT_COLOR)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_D3DCOLOR;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_COLOR;
elements.UsageIndex = 0;
i++;
}
if(vertices->m_type & VERT_TEX0)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT2;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_TEXCOORD;
elements.UsageIndex = 0;
i++;
}
if(vertices->m_type & VERT_TEX1)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT2;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_TEXCOORD;
elements.UsageIndex = 1;
i++;
}
if(vertices->m_type & VERT_TEX2)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT2;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_TEXCOORD;
elements.UsageIndex = 2;
i++;
}
if(vertices->m_type & VERT_BONE)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT4;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_TEXCOORD;
elements.UsageIndex = 3;
i++;
}
if(vertices->m_type & VERT_WEIGHT)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT4;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_TEXCOORD;
elements.UsageIndex = 4;
i++;
}
if(vertices->m_type & VERT_TANGENT)
{
elements.Stream = i;
elements.Offset = 0;
elements.Type = D3DDECLTYPE_FLOAT4;
elements.Method = D3DDECLMETHOD_DEFAULT;
elements.Usage = D3DDECLUSAGE_TANGENT;
elements.UsageIndex = 0;
i++;
}
D3DVERTEXELEMENT9 endelement = D3DDECL_END();
elements = endelement;
LPDIRECT3DVERTEXDECLARATION9 declaration;
m_device->CreateVertexDeclaration(elements, &declaration);
//m_device->SetVertexDeclaration(declaration);
return declaration;
}
int D3DEngine::CreateVertexBuffer(Vertex* &vertices, int numVertices, int mode)
{
//Create new vertex buffer id.
int vertexBufferId = 0;
vertexBufferId = (int)m_vertexBuffers.size();
//Create new Direct3D vertex buffer struct.
D3DVertexBuffer newBuffer;
if(vertices->v0)
{
for(int i=0; i<numVertices; i++)
{
vertices->v0 = -vertices->v0;
}
}
newBuffer.declaration = CreateDeclaration(vertices);
LPDIRECT3DVERTEXBUFFER9 pvb;
if( FAILED( m_device->CreateVertexBuffer(numVertices*vertices->Size(), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &pvb, NULL) ))
MessageBox(NULL, "Failed to create vertex buffer.", "Failed to create vertex buffer.", 0);
else
{
void* pVertices;
//Lock the vertex buffer.
pvb->Lock( 0, numVertices*vertices->Size(), (void**)&pVertices, 0 );
//Get the data from my vertex format.
float* data;
vertices->Data(data);
//Copy the data over.
memcpy(pVertices, data, numVertices*vertices->Size());
delete [] data;
//Unlock the buffer.
pvb->Unlock();
}
//Populate the struct.
newBuffer.vb = pvb;
newBuffer.type = vertices->m_type;
newBuffer.stride = vertices->Size();
newBuffer.numVertices = numVertices;
newBuffer.data = vertices;
//Set the mode of the buffer and calc the number of triangles.
switch(mode)
{
case TRI_STRIP:
{
newBuffer.numTriangles = numVertices - 2;
newBuffer.mode = D3DPT_TRIANGLESTRIP;
}break;
case TRI_LIST:
{
newBuffer.numTriangles = numVertices/3;
newBuffer.mode = D3DPT_TRIANGLELIST;
}break;
case TRI_FAN:
{
newBuffer.numTriangles = numVertices - 2;
newBuffer.mode = D3DPT_TRIANGLEFAN;
}break;
case LINE_LIST:
{
newBuffer.numTriangles = numVertices/2;
newBuffer.mode = D3DPT_LINELIST;
}
}
//Add the vertex buffer to the vector.
m_vertexBuffers.push_back(newBuffer);
//Return the ID.
return vertexBufferId;
}
//Buffer render functions.
void D3DEngine::BindVertexBuffer(int vertexBufferId)
{
//Make sure the IDs are valid.
if(vertexBufferId < 0 || vertexBufferId > (int)m_vertexBuffers.size())
return;
//Get the vertex struct.
D3DVertexBuffer vbuffer = m_vertexBuffers[vertexBufferId];
m_device->SetVertexDeclaration(vbuffer.declaration);
int d = 0;
/*----------DECLARATIONS----------*/
if(vbuffer.type & VERT_POSITION)
{
//OutputDebugString("Position\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_position, vbuffer.stride);
}
if(vbuffer.type & VERT_NORMAL)
{
//OutputDebugString("Normal\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_normal, vbuffer.stride);
}
if(vbuffer.type & VERT_COLOR)
{
//OutputDebugString("Color\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_color, vbuffer.stride);
}
if(vbuffer.type & VERT_TEX0)
{
//OutputDebugString("Tex0\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_tex0, vbuffer.stride);
}
if(vbuffer.type & VERT_TEX1)
{
//OutputDebugString("Tex1\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_tex1, vbuffer.stride);
}
if(vbuffer.type & VERT_TEX2)
{
//OutputDebugString("Tex2\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_tex2, vbuffer.stride);
}
if(vbuffer.type & VERT_BONE)
{
//OutputDebugString("Bone\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_bone, vbuffer.stride);
}
if(vbuffer.type & VERT_WEIGHT)
{
//OutputDebugString("Weight\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_weight, vbuffer.stride);
}
if(vbuffer.type & VERT_TANGENT)
{
//OutputDebugString("Tangent\n");
m_device->SetStreamSource(d++, vbuffer.vb, vbuffer.data->offset_tangent, vbuffer.stride);
}
}
void D3DEngine::RenderVertexBuffer(int vertexBufferId)
{
//Make sure the ID is valid.
if(vertexBufferId < 0 || vertexBufferId > (int)m_vertexBuffers.size())
return;
//Get the struct from the vector.
D3DVertexBuffer vbuffer = m_vertexBuffers[vertexBufferId];
//Bind the vertex buffer.
BindVertexBuffer(vertexBufferId);
//Draw the buffer.
m_device->DrawPrimitive(vbuffer.mode, 0, vbuffer.numTriangles);
//Increment the number of triangles drawn.
if(vbuffer.mode == D3DPT_TRIANGLEFAN || vbuffer.mode == D3DPT_TRIANGLESTRIP || vbuffer.mode == D3DPT_TRIANGLELIST)
{
numRenderedTriangles += vbuffer.numTriangles;
}
}
🔒 Locked
Vertex Declarations and SetStreamSource
Advertisement
Original Post
Hello all, I am working on getting my Direct3D engine into a more flexible state and am looking at doing so with vertex declarations. My goal is to be able to render multiple types of vertex buffers. One vertex buffer might have just positions and colors. The next vertex buffer will have positions, normals, colors, textures, bones, weights, etc. I have animation and a few basic lighting techniques implemented on the shader that work, but now I need to render other objects that are not as complex as the animated model. Their objects do not need all the extra information in the larger vertex buffer. -------------------------------- Here are some fundamental questions: Do I need a unique vertex declaration for each unique vertex buffer? On top of this, I need to call device->SetVertexDeclaration() on each declaration before I bind and render the buffer. For each component of my vertex buffer, do I need a matching call to SetStreamSource with an offset into the buffer. --------------------------------- Now here are my CreateVertexBuffer and RenderVertexBuffer functions, i know its kinda big, and not as clean as it could be, but i am trying to just get it up and working and then I can do some code clean up. Also, you can see the assumptions i made to the questions above. [Edited by - esunder on August 21, 2008 11:51:11 PM]
Quote:Each of your vertex declarations should be unique, there's no point having two identical declarations. So you want one declaration for each vertex buffer "type".
Original post by esunder
Do I need a unique vertex declaration for each unique vertex buffer?
Quote:Whenever the declaration changes, yes.
Original post by esunder
On top of this, I need to call device->SetVertexDeclaration() on each declaration before I bind and render the buffer.
Quote:No, the vertex declaration has that information in it. The elements.Offset member is supposed to be the offset from the start of a vertex to this component type.
Original post by esunder
For each component of my vertex buffer, do I need a matching call to SetStreamSource with an offset into the buffer.
EDIT: Your UsageIndex looks a little funky to me. If your vertex has VERT_TEX0, then your declaration has 1 set of texture coordinates (index 0). If your vertex has VERT_TEX2, then your declaration is invalid - it has 1 set of texture coordinates (index 2), but indices 0 and 1 are missing.
Here's the relevant function from my vertex declaration class:
IDirect3DVertexDeclaration9* PVertexDecl::GetDecl(){ // If declaration is already valid, no need to regenerate it if(m_pDecl) return m_pDecl; DWORD dwOffset = 0; // Offset into vertex DWORD dwIndex[16]; // Index of this type (E.g. 1 for 2nd set of tex coords) for(int i=0; i<16; ++i) dwIndex = 0; for(size_t i=0; i<m_vDecl.size(); ++i) { Assert(m_vDecl.Usage < 16, "Unexpected usage"); m_vDecl.Offset = (WORD)dwOffset; m_vDecl.UsageIndex = (BYTE)dwIndex[m_vDecl.Usage]; switch(m_vDecl.Type) { case D3DDECLTYPE_FLOAT1: dwOffset += sizeof(float); break; case D3DDECLTYPE_FLOAT2: dwOffset += sizeof(float)*2; break; case D3DDECLTYPE_FLOAT3: dwOffset += sizeof(float)*3; break; case D3DDECLTYPE_FLOAT4: dwOffset += sizeof(float)*4; break; case D3DDECLTYPE_D3DCOLOR: dwOffset += sizeof(DWORD); break; case D3DDECLTYPE_UBYTE4: dwOffset += sizeof(BYTE)*4; break; case D3DDECLTYPE_SHORT2: dwOffset += sizeof(SHORT)*2; break; case D3DDECLTYPE_SHORT4: dwOffset += sizeof(SHORT)*4; break; default: Assert(false, "Unhandled size"); } ++dwIndex[m_vDecl.Usage]; } // Add the terminator m_vDecl.push_back(s_streamEnd); // Now create the declaration HRESULT hResult = PGraphics::Get().GetDevice()->CreateVertexDeclaration(&m_vDecl[0], &m_pDecl); if(FAILED(hResult)) { #ifndef DRUINK_NO_GRAPHICS // Don't link to DXGetErrorStringA std::stringstream str; str << "Failed to create vertex declaration. Error: "; str << DXGetErrorStringA(hResult); PApp::Get().SetError(str.str()); ELog::Get().ErrorFormat("RENDER : %s\n", PApp::Get().GetError().c_str()); #endif return NULL; } // Done return m_pDecl;}
Ok I see that the usage may be off for the texture coordinates.
The current problem I am having is that I am trying to render an animated model that uses all of the vertex components, and then I am trying to also render a flat grid of lines that are just position and color.
The model animates and renders fine, however the grid does not. However, in debug mode, the grid renders fine, only the release version is incorrect. Also, If I remove the model and just try to render the lines, they do not show up.
I currently only have 2 declarations, one has all of the vertex components and works fine, the other only has pos and color and does not work.
The current problem I am having is that I am trying to render an animated model that uses all of the vertex components, and then I am trying to also render a flat grid of lines that are just position and color.
The model animates and renders fine, however the grid does not. However, in debug mode, the grid renders fine, only the release version is incorrect. Also, If I remove the model and just try to render the lines, they do not show up.
I currently only have 2 declarations, one has all of the vertex components and works fine, the other only has pos and color and does not work.
Quote:That's the correct way to do it, the vertices are different formats so you should have different declarations.
Original post by esunder
Ok I see that the usage may be off for the texture coordinates.
The current problem I am having is that I am trying to render an animated model that uses all of the vertex components, and then I am trying to also render a flat grid of lines that are just position and color.
The model animates and renders fine, however the grid does not. However, in debug mode, the grid renders fine, only the release version is incorrect. Also, If I remove the model and just try to render the lines, they do not show up.
I currently only have 2 declarations, one has all of the vertex components and works fine, the other only has pos and color and does not work.
Anything from the Debug runtimes?
Quote:
Original post by esunder
Is it correct to SetStreamSource for each component of the vertex? Or if i set the offset in the vertex declaration, do i only need to do it once?
A stream source can contain one or more components of a vertex. So just because your vertex has 3 components doesn't necessarily imply you'll have 3 streams. You can have 1, 2, or 3 streams for 3 components.
I discuss this more in Chapter 5. Modeling of my book "The Direct3D Graphics Pipeline". Perhaps taking a look at that chapter will help clear things up for you.
All of the vertex declarations that I am seeing online are created differently than mine. Is this not a valid way to do it?
Also, nothing from the Debug runtimes :\. That was the first thing i checked.
BTW, how do you get your code into a box to use less room?
[Edited by - esunder on August 21, 2008 11:43:41 PM]
Also, nothing from the Debug runtimes :\. That was the first thing i checked.
BTW, how do you get your code into a box to use less room?
//Buffer creation functions.LPDIRECT3DVERTEXDECLARATION9 D3DEngine::CreateDeclaration(Vertex* vertices){ int x = BitSet(vertices->m_type); x+=1; //////////////////////////////////////////////////// /*----------DECLARATIONS----------*/ D3DVERTEXELEMENT9* elements = new D3DVERTEXELEMENT9[x]; int i = 0; if(vertices->m_type & VERT_POSITION) { elements.Stream = 0; elements.Offset = vertices->offset_position; elements.Type = D3DDECLTYPE_FLOAT3; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_POSITION; elements.UsageIndex = 0; i++; } if(vertices->m_type & VERT_NORMAL) { elements.Stream = 0; elements.Offset = vertices->offset_normal; elements.Type = D3DDECLTYPE_FLOAT3; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_NORMAL; elements.UsageIndex = 0; i++; } if(vertices->m_type & VERT_COLOR) { elements.Stream = 0; elements.Offset = vertices->offset_color; elements.Type = D3DDECLTYPE_D3DCOLOR; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_COLOR; elements.UsageIndex = 0; i++; } if(vertices->m_type & VERT_TEX0) { elements.Stream = 0; elements.Offset = vertices->offset_tex0; elements.Type = D3DDECLTYPE_FLOAT2; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_TEXCOORD; elements.UsageIndex = 0; i++; } if(vertices->m_type & VERT_TEX1) { elements.Stream = 0; elements.Offset = vertices->offset_tex1; elements.Type = D3DDECLTYPE_FLOAT2; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_TEXCOORD; elements.UsageIndex = 1; i++; } if(vertices->m_type & VERT_TEX2) { elements.Stream = 0; elements.Offset = vertices->offset_tex2; elements.Type = D3DDECLTYPE_FLOAT2; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_TEXCOORD; elements.UsageIndex = 2; i++; } if(vertices->m_type & VERT_BONE) { elements.Stream = 0; elements.Offset = vertices->offset_bone; elements.Type = D3DDECLTYPE_FLOAT4; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_TEXCOORD; elements.UsageIndex = 3; i++; } if(vertices->m_type & VERT_WEIGHT) { elements.Stream = 0; elements.Offset = vertices->offset_weight; elements.Type = D3DDECLTYPE_FLOAT4; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_TEXCOORD; elements.UsageIndex = 4; i++; } if(vertices->m_type & VERT_TANGENT) { elements.Stream = 0; elements.Offset = vertices->offset_tangent; elements.Type = D3DDECLTYPE_FLOAT4; elements.Method = D3DDECLMETHOD_DEFAULT; elements.Usage = D3DDECLUSAGE_TANGENT; elements.UsageIndex = 0; i++; } D3DVERTEXELEMENT9 endelement = D3DDECL_END(); elements = endelement; LPDIRECT3DVERTEXDECLARATION9 declaration; m_device->CreateVertexDeclaration(elements, &declaration); //m_device->SetVertexDeclaration(declaration); return declaration;}[Edited by - esunder on August 21, 2008 11:43:41 PM]
It looks like you're trying to make one "uber vertex class" that can handle any possible layout of vertices.
In practice, unless you are doing a very general purpose modeling or mesh transformation tool, you rarely need this level of generality.
Since a vertex declaration is intimately tied to its layout, most people make that association in their code. For instance, something like:
BTW, use the source bbcode markup to mark a block of text as source code.
In practice, unless you are doing a very general purpose modeling or mesh transformation tool, you rarely need this level of generality.
Since a vertex declaration is intimately tied to its layout, most people make that association in their code. For instance, something like:
struct Vertex1{ D3DXVECTOR3 _position; D3DXVECTOR3 _normal; static IDirect3DVertexDeclaration9 *GetDeclaration(IDirect3DDevice9 *device) { D3DVERTEXELEMENT9 elements[] = { { 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }, { 0, 3*sizeof(float), D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }, D3DDECL_END }; IDirect3DVertexDeclaration9 *declaration = 0; THR(device->CreateVertexDeclaration(&elements[0], &declaration)); return declaration; }};BTW, use the source bbcode markup to mark a block of text as source code.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement