Jump to content
  • Advertisement
Sign in to follow this  
Samurai Jack

Flexible Vertex Format on the fly?

This topic is 4601 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

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!

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
If you used vertex declarations, of course, this process would be somewhat simplified...

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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[ i ].vPosition.x += 1.0f;
}

vbReader.UnlockVertices();



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. Once 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. Only the dictionary needs to worry about the variable length nature of the vertex delcarations.

Hope that helps.

Share this post


Link to post
Share on other sites
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]

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!