Flexible Vertex Format on the fly?

Started by
7 comments, last by mrbastard 18 years, 3 months ago
Greetings! I was wondering, does anyone have a dynamic solution for flexible vertex formats? For example, what if you have vertex position and uv, or vertex position and vertex normal or perhaps only vertex position or maybe vertex postioion with normal and uv? The thing is, how to load souch a file? for each fvf combination define own struct and read from file?! Is there a better way to do it? Thank you in advance!
Advertisement
Do you need to actually process the data yourself? Typically, you'll just store a vertex array using a format, a count of vertices, a size in bytes, and a byte chunk. To load, create a vertex buffer with the appropriate format, lock it, and read the byte chunk into the vertex buffer.

If you need to process vertices with FVF formats, you can write accessor functions that, given the base of an array and a FVF, returns a pointer to the component in question, as well as the stride of that array.

Although most people probably have moved on to vertex declaration structs instead these days.
enum Bool { True, False, FileNotFound };
I have defined my vertex formats like this:

enum eVertexFormat {
VF_POSITION = 1<<0, // vertex position 3 floats x,y,z
VF_NORMAL = 1<<1, // normal 3 floats x,y,z
VF_TEXCOORD2D_1 = 1<<2, // texcoord 1 2 floats u,v
VF_TEXCOORD2D_2 = 1<<3, // texcoord 2 2 floats u,v
VF_TEXCOORD2D_3 = 1<<4, // texcoord 3 2 floats u,v
// and so on
};

then a VertexBuffer class

class CVertexBuffer { uint m_iVertexFormat; uint m_iVertexCount; uint m_iVertexStride; // size in bytes for one vertex uint m_iDataSize; void *pData;public: CVertexBuffer( eVertexFormat f, uint count ); void Push( void *data, uint size);};CVertexBuffer::CVertexBuffer( eVertexFormat f, uint count ){ m_iVertexFormat = f; m_iVertexCount = count; m_iVertexStride = 0; if( m_iVertexFormat & VF_POSITION )  m_iVertexStride += 3 * sizeof(float); // vertex has position data, 3 floats if( m_iVertexFormat & VF_NORMAL )  m_iVertexStride += 3 * sizeof(float); // vertex has normal data, 3 floats if( m_iVertexFormat & VF_TEXCOORD2D_1 )  m_iVertexStride += 2 * sizeof(float); // vertex has texcoord data, 2 floats ... m_iDataSize = m_iVertexStride * m_iVertexCount; pData = (void*)new char[m_iDataSize];}void CVertexBuffer::Push( void *data, uint size ){ // just copy 'size' bytes from 'data' to 'pData' memcpy(pData, data, size);}


so then I can create a VB with the vertexformat I like the order of the vertexdata is as the enum types is in the list: Position,Normal,TexCoord1,TexCoord2,... if the vertexformat of the VB doesn't have one of them then the next is there.

example:
This will create a vb with room for 3 vertex positions and their normals
CVertexBuffer *vb = new CVertexBuffer(VF_POSITION | VF_NORMAL, 3);

the data for that buffer will be x1,y1,z1,nx1,ny1,nz1,x2,y2,z2,nx2,ny2,nz2,...

This will create a vb with room for 3 vertex positions and their first uv coords
CVertexBuffer *vb = new CVertexBuffer(VF_POSITION | VF_TEXCOORD2D_1, 3);

the data for that buffer will be x1,y1,z1,u1,v1,x2,y2,z2,u2,v2,...

and if you want vertex position, normal and uv.
CVertexBuffer *vb = new CVertexBuffer(VF_POSITION | VF_NORMAL | VF_TEXCOORD2D_1, 3);

the data for that buffer will be x1,y1,z1,nx1,ny1,nz1,u1,v1,x2,y2,z2,nx2,ny2,nz2,u2,v2,...

And so on.
If you used vertex declarations, of course, this process would be somewhat simplified...
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
You could read through Yann L's famous Material/Shader posts. Lots of good info in there on ways to handle different shaders (and their data streams). You'd want to make a new thread if you have questions about that stuff, since you don't want to necro the old thread.
Take a look at this: Vertex Buffer Proxy. This class allows you to access a vertex buffer as an array of vertices, where the layout of each vertex is determined by an FVF value that you provide.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Recently i started to write a vertex-, a vertexbuffer- and an indexbufferclass,that work with any fvf..you can simply create a vertex with vertex.create(DWORD fvf),fill in values with vertex.setPosition(vector3 v),vertex.setNormal(vector3 n),etc and put it into a vertexbuffer. The vertexclass will automatically allocate the memory needed for the vertex with the given fvf and will copy the values you give to it in the right position in this memory. The vertex has a function call getD3DVertex() which returns a void pointer to the allocated memory. This pointer can then be used to put the vertex in a D3Dvertexbuffer.

Sadly it still doesn't work properly and i don't know where the error could be...but the vertexclass seems to work fine the error seems to be within the vertexbuffer class.

That is my aproach to not limiting my engine to certain fvf combinations and it's the best way i came up with.

regards,
m4gnus
"There are 10 types of people in the world... those who understand binary and those who don't."
I use a system just like m4gnus for dynamic content. I VertexBufferWriter is instantiated with a specific vertex declaration ( dx9 style ) and then I iterate over the num vertices I need, and for each one fill in the data. The VertexBufferWriter knows where to put each member since it was passed the declaration (which knows the offset & stride of each component).

For static content that I might need to access I have a VertexBufferReader class which is templated so that I can do this:

struct StaticGeomVert{  Vertex3  vPosition;  Vertex3  vNormal;  Vertex2  vTexcoord0;};VertexBufferReader <StaticGeomVert*>vbReader( pModelObject, vertDecl );StaticGeomVert* pVertices = vbReader.LockVertices();for ( int i = 0 ; i < vbReader.GetNumVerts(); i++ ){  pVertices.vPosition.x += 1.0f;<br>}<br><br>vbReader.UnlockVertices();<br><br></pre><br><br>All of my models know their vertex format through a dictionary. I create, in the build pipeline, a dictionary of all used vertex declarations and then store a unique ID of that in the model. &#79;nce loaded I bind that ID to a pointer in the dictionary. This lowers our memory footprint and also makes the model header format fixed size. &#79;nly the dictionary needs to worry about the variable length nature of the vertex delcarations.<br><br>Hope that helps.<br><br>
Quote:Original post by hplus0603just store a vertex array using a format, a count of vertices, a size in bytes, and a byte chunk.


To my mind that's the simplest and most flexible way. In opengl terms, store the params to the gl*Pointer functions and you have all the information you need to make a custom iterator. You can use such a custom iterator to process vertex data using stl algorithms.

edit: the OP asked about files. Store the size of the whole vertex in bytes, and the number of bytes offset to the start of the first element for each attribute. Read in the whole file and use the offsets to set up your iteraors / vert arrays.

[Edited by - mrbastard on January 17, 2006 12:03:03 AM]
[size="1"]

This topic is closed to new replies.

Advertisement