Sign in to follow this  
Maverick_24

Creating a more dynamic vertex buffer struct

Recommended Posts

I have a mesh class with these structs right now:
struct VertexFormat_XYZ_NORM_UV
{
	float x, y, z;
	float nx, ny, nz;
	float u, v;
};
struct VertexFormat_XYZ_RGBA
{
	float x, y, z;
	char r, g, b, a;
};

then i fill one (not both) of these std::vectors with the mesh data
std::vector<VertexFormat_XYZ_NORM_UV> VertexBuffer1;
std::vector<VertexFormat_XYZ_RGBA> VertexBuffer2;

This seems kind of a cheesy and non-dynamic approach since i only have support for 2 vertex buffer types, and if i wanted to add more types i would have to hardcode a new struct for each one. I would like a better solution. What is a common approach, if there is one? Is there a common programming strategy to tackling this exact problem? Thanks in advance

Share this post


Link to post
Share on other sites
The method I use is to associate a small descriptor class with each vertex buffer that contains the number of fields in the vertex buffer (position, colour, uv, etc), the vertex buffer's stride (size of each vertex) and the format and component count for each field in the vertex buffer. I've only worked in OpenGL, but I presume that a similar method works for DirectX too.

The VertexField class describes 1 field in a vertex stream:

class VertexField
{
public:
enum Target
{
kPosition,
kNormal,
kColour,
kTexCoord0,
kTexCoord1,
kTexCoord2,
kTexCoord3,
kTexCoord4,
kTexCoord5,
kTexCoord6,
kTexCoord7,
};

enum Type
{
kFloat = GL_FLOAT,
kInt = GL_INT,
kShort = GL_SHORT,
kByte = GL_BYTE,
kUnsignedByte = GL_UNSIGNED_BYTE,
};

VertexField();
VertexField( Target target, Type type, u16 count, u16 offset );

Target m_target;
Type m_type;
u16 m_count;
u16 m_offset;
};




Here's how it's used by the client code to describe a vertex format and to initialise a vertex buffer instance:

struct Vertex
{
Point3 m_position;
Vector3 m_tangent;
Vector3 m_bitangent;
float m_u;
float m_v;
u8 m_colour[ 4 ];
};

VertexField fields[] =
{
VertexField( VertexField::kPosition, VertexField::kFloat, 3, offsetof( Vertex, m_position ) ),
VertexField( VertexField::kTexCoord0, VertexField::kFloat, 3, offsetof( Vertex, m_tangent ) ),
VertexField( VertexField::kTexCoord1, VertexField::kFloat, 3, offsetof( Vertex, m_bitangent ) ),
VertexField( VertexField::kTexCoord2, VertexField::kFloat, 2, offsetof( Vertex, m_u ) ),
VertexField( VertexField::kColour, VertexField::kUnsignedByte, 4, offsetof( Vertex, m_colour ) ),
};

u32 numFields = sizeof( fields ) / sizeof( VertexField );
m_pVertexBuffer = new VertexBuffer( fields, numFields, sizeof( Vertex ), vertexCount, VertexBuffer::kStatic );




And here's how it's used when a vertex buffer is bound (I'm assuming the use of vertex array buffers):

void VertexBuffer::Bind() const
{
for ( u16 i = 0; i < m_fieldCount; ++i )
{
const VertexField& rField = m_pFields[ i ];
void* pFieldData = ( void* )( u32 )rField.m_offset;

switch ( rField.m_target )
{
case VertexField::kPosition:
glVertexPointer( rField.m_count, rField.m_type, m_stride, pFieldData );
break;

case VertexField::kNormal:
SALT_ASSERT( rField.m_count == 3 );
glNormalPointer( rField.m_type, m_stride, pFieldData );
break;

case VertexField::kColour:
glColorPointer( rField.m_count, rField.m_type, m_stride, pFieldData );
break;

// case VertexField::kTexCoord0:
// case VertexField::kTexCoord1:
// case VertexField::kTexCoord2:
// case VertexField::kTexCoord3:
// case VertexField::kTexCoord4:
// case VertexField::kTexCoord5:
// case VertexField::kTexCoord6:
// case VertexField::kTexCoord7:
default:
glClientActiveTextureARB( GL_TEXTURE0_ARB + rField.m_target - VertexField::kTexCoord0 );
glTexCoordPointer( rField.m_count, rField.m_type, m_stride, pFieldData );
break;
}
}
}




This obviously isn't the whole story but hopefully it should be enough to point you in the right direction.

I'm not saying this is the best way, but it works very well for me :)

Share this post


Link to post
Share on other sites
I started coding up something more like this.....a dynamic array of floats....if any elements are not floats i use reinterpret_cast<> to get the whatever the bits are into a 32 bit "float"

Any comments/criticisms would be appreciated, thanks


void CreateVertexBuffer( eVertexFormat vertFormat )
{
int iNumFloatsPerStride = 0;
if ( vertFormat == XYZ_NORM_UV )
{
vbType = XYZ_NORM_UV;
iStride = sizeof(float) * 8;
iNumFloatsPerStride = 8;

}
else if ( vertFormat == XYZ_ARGB )
{
vbType = XYZ_ARGB;
iStride = sizeof(float) * 4;
iNumFloatsPerStride = 4;
}

iTotalVerts = vertList.size();

int iVBSize = iTotalVerts * iNumFloatsPerStride;

vertexBuffer = new float[iVBSize];

for ( int i = 0; i < iTotalVerts; ++i )
{
int iIndex = i * iNumFloatsPerStride;
//This Vertex Format Contains XYZ Positional Data
if ( vertFormat == XYZ_NORM_UV || vertFormat == XYZ_ARGB )
{
vertexBuffer[iIndex++] = vertList.at(i).x;
vertexBuffer[iIndex++] = vertList.at(i).y;
vertexBuffer[iIndex++] = vertList.at(i).z;
}
//This Vertex Format Contains XYZ Normal Data
if ( vertFormat == XYZ_NORM_UV )
{
vertexBuffer[iIndex++] = normalList.at(i).x;
vertexBuffer[iIndex++] = normalList.at(i).y;
vertexBuffer[iIndex++] = normalList.at(i).z;
}
//This Vertex Format Contains UV Coordinate Data
if ( vertFormat == XYZ_NORM_UV )
{
vertexBuffer[iIndex++] = uvcoordList.at(i).u;
vertexBuffer[iIndex++] = uvcoordList.at(i).v;
}
//This Vertex Format Contains Per-Vertex Color Data
if ( vertFormat == XYZ_ARGB )
{
char ch[4] = { colorList.at(i).a,
colorList.at(i).r,
colorList.at(i).g,
colorList.at(i).b, };

vertexBuffer[iIndex++] = *reinterpret_cast<float*>(&ch);

}

}

}



Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this