Look for an example of index offseting

Here’s some pseudo code to give a rough idea of what I wanna do

typedef struct _POINT { uint color; uint place; uint texel; } POINT;
vec4 colors[3] = {{0}};
vec3 places[3] = {{0}};
vec2 texels[3] = {{0}};
POINT points[3] = {{0}};
// shader location, address, offset of member, stride to next index, size of array from address
attr( location, points, offsetof(POINT,color), sizeof(POINT), sizeof(points) );
buff( ..., colors, ... );
attr( location, points, offsetof(POINT,place), sizeof(POINT), sizeof(points) );
buff( ..., places, ... );
attr( location, points, offsetof(POINT,texel), sizeof(POINT), sizeof(points) );
buff( ..., texels, ... );

How would I go about doing that in OpenGL? For whatever example you give save future viewers of the thread some confusion by just using the exact same pseudo structure as above. Can also skip how to get the location though just in case there’s some deviation from what I’ve been using I’d like you to give a rough example of setting up the buffers before the render loop also.

How do you go about doing what in OpenGL? What does this code mean? What is it trying to accomplish?

I don’t know what a POINT is, but it looks suspiciously liked you’re trying to index each array separately. Which you can’t do.

Also, what is a “place?”

Well indexing each array separately was already done but I’m try to go the more efficient route of sending only one indices array and simply using offsets for each indexed attribute, here’s something I just finished abstracting out while attempting to do just that:

		StateFloats( FloatVBO, location, f );
		StateIndexOffset( GTraits->vbo, location, i, f );
	}

	RelayIndices( GTraits->vbo, Points, sizeof(POINT) / sizeof(uint), GL_DYNAMIC_DRAW );
	//glX( NULL, glInvalidateBriefData( CacheID ) );
	//glX( NULL, glVertexArrayElementBuffer( TraitVBO, IndexVBO ));
	glX( NULL, glDrawElements( Strip->DrawAs, Points->used, GL_UNSIGNED_INT, NULL ));

	return 0;
}

void StateFloats( uint vbo, uint loc, ENUM_CACHE f )
{
	glX( NULL, glBindBuffer( GL_ARRAY_BUFFER, vbo ) );
	glX( NULL, glVertexAttribPointer( loc, ++f, GL_FLOAT, GL_FALSE, 0, NULL ));
}

void StateIndexOffset( uint vbo, uint loc, ENUM_TRAIT i, ENUM_CACHE f )
{
	POINT P;
	glX( NULL, glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo ) );
	glX( NULL, glVertexAttribPointer
	(
		loc, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(POINT),
		(void*)((uchar*)(&(P.raw[i])) - (uchar*)&P)
	));
}

void RelayIndices( uint vbo, BLOCK *Indices, uint perStruct, uint DrawAs )
{
	glX( NULL, glBufferData
	(
		GL_ELEMENT_ARRAY_BUFFER,
		Indices->used * perStruct * sizeof(uint),
		Indices->addr,
		DrawAs
	));
}

Edit: Here’s the traits in my glsl code that the indices indicated by POINT’s members refer to:

#version 330

in vec2 Texel;
in vec4 Color;
in vec3 Place;
in vec3 Normal;
in vec3 Tangent;
in vec3 BiNormal;

I started by sending a separate index array for each trait but now I want to send an array of POINT objects as an index array and have each index be loaded from an offset of each stride (which is sizeof(POINT))

An index array, as the name suggests, contains an index. Singular. You get 32-bytes. That’s it; that’s an index.

If it were that easy to do multi-indexed rendering, I wouldn’t have written a big answer that says you can’t do multi-indexed rendering. If you want to have multi-indexed rendering, you must do all of the attribute fetching and manipulation manually.

There’s no trick around this. If you want X, you must do Y.

Well that sucks, that’s one thing they could’ve easily implemented when they 1st introduced indexing to the API, there’s no reason they couldn’t. A struct full of indices can still be reinterpreted as part of an index array, for GPU side all it would be is this:

indices = (uchar*)addr;
vertex = vertices[*((uint*)(indices + ((i * stride) + offset)))];

Oh well, back to the slower method then… can shaders access the float vbo directly at all? if so I could still get round that annoyance by just passing the POINT struct as set of attributes and pass it as a normal array

They can do random access on buffers bound as UBOs, SSBOs or buffer textures. VBOs (i.e. buffers bound as attribute arrays) have their data “pushed” to the vertex shader; the vertex shader can’t “pull” from it (that’s a large part of why attributes are more efficient than dependent fetches).

UBO I guess means Uniform Buffer Object but what is SSBO? Well either way it sounds like what is clearly the most efficient method of using indices with common vertex attributes is just plain unsupported which is annoying and weird to boot.

I linked to something that explains why they didn’t. And also explains what you can do instead.

But it’s not “the most efficient.” Multi-indexed rendering, for most meshes, is terribly inefficient. It bloats your index data to remove a few redundant vertex attributes. It messes with your cache efficiency since you’ll have to be fetching non-interleaved arrays of data.

It’s only a good idea if your meshes are made of cubes or some other geometric primitive. That may be the case for yourself, but it’s not generally true.

Well triangles are a geometric primitive but I’m assuming that’s not what you mean, anyways if a VBO has to have new indices sent per mesh then it only makes sense to store all related indices in a single array and provide offsets instead of maintaining multiple arrays (which increases complexity of code and introduces more potential for error), it’s faster to send a single array then to hop back and forth between the GPU and CPU’s sending/received singles for multiple smaller arrays which store the same type of information, that’s the same reason I’m using vector caches, so I only have to send the vectors once in a while and instead send the currently focused index array before sending the command to draw the mesh.

Or perhaps 32 bits as multiple interleaved indices, on some hardware.

We’re not talking about indices per mesh; we’re talking about indices per attribute within a mesh. Different attributes using different indices within a single draw call. That’s what the code you wrote was (maybe?) trying to do.

… I have no idea what you’re even talking about here. Unless you’re streaming vertex data, you shouldn’t be sending anything. You upload your data once, then render with it as needed.

Each mesh has points, each point has attributes, meshes never need to store anything but the point data, that makes it either a plain vertex object list or an index list, even if those indices happen to be aligned into objects, the GPU only needs to know the stride to the next set of indices to use (assuming it is not just 1 index where the stride would be 1 uint), where the mesh as a whole gets moved to is something that gets stored outside that array since it is irrelevant to the array, so yes we’re talking about indices per attribute but also indices per mesh because they’re stored in the same buffer.

There’s no guarantee the GPU has enough memory for storing all the meshes used in a sub stage and it’s local sub stages on top of the main stage - just in case you’re confused here, think of the sub stages as a small chunk of the active scene which is the main stage, for example FFXV would never have loaded every sub stage in the starting continent, instead it woulda use a low poly version of the continent as the main stage and the area the player is in would be a sub stage that’s loaded on the fly, which in turn can change the list of models on the fly with it which means the meshes for said models could not be just “sent once”.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.