Vertex Array problem

Started by
33 comments, last by azjerei 19 years, 2 months ago
yes, OpenGL Culls what isnt on screen. The reason it used to be faster todo it by hand was because the CPU was doing all the work anyways, these days the hardware handles issues such as this. However, that doesnt mean you should just throw all your objects at the scene and let OGL cull them, as its still faster to cull out the objects which dont cross into the scene than to pass them in anyways.

As for your lighting system you'll have to rethink how you approch it all, you'll probably want to pre-process all the data and batch various sections together somehow or use shaders of some sort (depending on how complex your lighting model is, however the first option should probably do you as I doubt you are doing per-pixel lighting without having touched shaders yet).

Per-object collision is only the start, you have to work out if the object even hits anything else (simple sphere check) and then work down to the per-poly level as required. This isnt such as problem as you make it out to be, look at stuff like UT2K4, they use the D3D version of Vertex arrays and yet can still do proper collision detection.

Octrees arent some 'magic bullet' that'll speed things up, you'll probably get some speed up, sure as you wont have to check all the vertices to see if you can see them however you will still be hand feeding the GPU and using up all the CPU time doing it, so you'll still be wasting a lot of time and anything above a low amount of polys will crash your frame rate into the ground.

Simple put if you want the extra speed which will come from using VA/VBO instead of glvertex3f et al commands you are going to have to rethink how you do things. What you want doto isnt impossible, it just going to require some thought/redesign from your current method.

However, that said if you dont want to put the effort in and are happy wasting all your CPU and GPU time hand feeding the gfx card your data then go ahead, but dont moan because changing from one system to another doesnt work how you want it to any more.
Advertisement
I cannot really agree that OGL culls what is not on the screen.. oh well.. if ppl say it does, then is maybe does so without really doing so.

The problem is that I cannot rewrite anything at this moment. VA's and VBO's looked small enough in terms of how much to change, but then I would have to rewrite lots of things, as we have now come to see, and I cannot do that.

*sigh*

I think I'll frankly need a good structured and easy to follow engine/tutorial that explains it all to be able to understand how to do it. I cannot experiment, it takes too long.
Okey, stage one in implementing Vertex Arrays has been initialized. We agreed on giving it a shot, slightly halting development a little, in favour of getting a faster game.

But... I ran into trouble almost immediately. Take a look at these images...





Strange looking landscape huh? Well, that is what I get when I render the level landscape with the Vertex Array system.

Here is the code I have written for the Vertex Arrays:

Reading level file:
// Read vertice number for this object and allocate memory.} else if (!strcmp(strWord, MIS_NUM_VERTS)) {	fscanf(m_FilePointer, " %d", &pObject->numOfVerts);	pObject->pVerts = new CVector3 [pObject->numOfVerts];	pObject->pNormals = new CVector3 [pObject->numOfVerts];	// Create Vertex Arrays for vertices and vertex normals.	pObject->vertexArray = new float [pObject->numOfVerts * 3];	pObject->normalArray = new float [pObject->numOfVerts * 3];// Read texture coordinate number and allocate memory.} else if (!strcmp(strWord, MIS_NUM_TEXVERTS)) {	fscanf(m_FilePointer, " %d", &pObject->numTexVertex);	pObject->pTexVerts = new CVector2 [pObject->numTexVertex];	// Create Vertex Array for texture coordinates.	pObject->texCoordArray = new float [pObject->numTexVertex * 2];// Read object vertices.} else if (!strcmp(strWord, MIS_VERT)) {	fscanf(m_FilePointer, " %d", &indx);	fscanf(m_FilePointer, " %f %f %f",		&(pObject->pVerts[indx].x), 		&(pObject->pVerts[indx].y), 		&(pObject->pVerts[indx].z));	// Set Vertex Array data for vertices.	pObject->vertexArray[v++] = pObject->pVerts[indx].x;	pObject->vertexArray[v++] = pObject->pVerts[indx].y;	pObject->vertexArray[v++] = pObject->pVerts[indx].z;// Read object texture vertices.} else if (!strcmp(strWord, MIS_TEXVERT)) {	fscanf(m_FilePointer, " %d", &indx);	fscanf(m_FilePointer, " %f %f", 		&(pObject->pTexVerts[indx].x), &(pObject->pTexVerts[indx].y));	// Set Vertex Array data for texture coordinates.	pObject->texCoordArray[t++] = pObject->pTexVerts[indx].x;	pObject->texCoordArray[t++] = pObject->pTexVerts[indx].y;// Read object vertex normals.} else if (!strcmp(strWord, MIS_NORMAL)) {	fscanf(m_FilePointer, " %d", &indx);	fscanf(m_FilePointer, " %f %f %f",		&(pObject->pNormals[indx].x),		&(pObject->pNormals[indx].y),		&(pObject->pNormals[indx].z));	// Set Vertex Array data for vertices.	pObject->normalArray[n++] = pObject->pNormals[indx].x;	pObject->normalArray[n++] = pObject->pNormals[indx].y;	pObject->normalArray[n++] = pObject->pNormals[indx].z;


As you can see, I use a separate vertex, normal and texcoord array list for each object. I assign them a dynamic size depending on the number of vertices/texture coordinates of the objects, and then I set the values based on the read values from the file. I have checked that I assign the correct values... well.. it does it because without Vertex Arrays, the landscape draws just fine (though slower).

I store the arrays in a fashion of

vert0.x, vert0.y, vert0.z, vert1.x, vert1.y, vert1.z ...

and so on.. as you can see in the code. Maybe I should store them in another order??

Here is the rendering code:

void RenderLandscape(){	bool useDetailTexture = false;	// Activate the necessary Vertex Array properties.	glEnable(GL_VERTEX_ARRAY);	glEnable(GL_TEXTURE_COORD_ARRAY);	glEnable(GL_NORMAL_ARRAY);	for (int i = 0; i < g_3DModel.numOfObjects; i++)	{		// Draw only ground objects.		if (bItemList != false)			continue;		// Make sure we have valid objects just in case. (size() is in the vector class).		if(g_3DModel.pObject.size() <= 0) break;		// Get the current object that we are displaying.		t3DObject *pObject = &g_3DModel.pObject;		// Check visibility based on distance from object to player.		if (!ObjectDistanceCalc(player.vCharMove, pObject))			continue;		ActivateDetailTexturing();					// Does the material applied to this object have a detail texture?		if (g_TextureDetail[pObject->materialID] < 666) {			useDetailTexture = true;		} else {			useDetailTexture = false;		}		// Set up the detail texturing parameters.		if (useDetailTexture) {			SetupDetailTexturing(g_Texture[pObject->materialID],								 g_TextureDetail[pObject->materialID]);		} else {			SetupDetailTexturing(g_Texture[pObject->materialID], -1);		}		// Turn on backface culling.		glEnable(GL_CULL_FACE);		// Check if the object is to be rendered without culling.		if (!pObject->doCulling)			glDisable(GL_CULL_FACE);		// Set translucency and color.		if (pObject->transPercent < 1.0f) {			glColor4f(1.0f, 1.0f, 1.0f, pObject->transPercent);			glBlendFunc(GL_SRC_ALPHA, GL_ONE);			glEnable(GL_BLEND);		} else {			glColor4f(1.0f, 1.0f, 1.0f, 1.0f);			glDisable(GL_BLEND);		}		// Shiny objects should have specular coloring applied.		if (pObject->ShinyObj) {			glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, SunAmbience);			glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &specularShine);		} else {			GLfloat noSpecular[] = {0, 0, 0, 1.0f};			float noShininess = 0.0f;			glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, noSpecular);			glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &noShininess);		}		// Set up the Vertex Array lists.		glVertexPointer(3, GL_FLOAT, 0, pObject->vertexArray);		glTexCoordPointer(2, GL_FLOAT, 0, pObject->texCoordArray);		glNormalPointer(GL_FLOAT, 0, pObject->normalArray);		// Draw the Vertex Array lists.		glDrawArrays(g_ViewMode, 0, pObject->numOfFaces);		// Disable detail texturing.		DisableDetailTexturing();		// Disable possible set blending.		if (pObject->transPercent < 1.0f)			glDisable(GL_BLEND);	}	glDisable(GL_NORMAL_ARRAY);	glDisable(GL_TEXTURE_COORD_ARRAY);	glDisable(GL_VERTEX_ARRAY);}


Does your hawk-eyes see any screwup I've made? I cannot find anything... :(
Could be the order I am storing the arrays in.. I dunno.. never done this before. Thanks for convincing me into going with Vertex Arrays :)
the 'count' value in glDrawArrays refers to the number of vertices not the number of faces, so for triangles you'd multiple it by 3
Oh, then I misunderstood the explanation at opengl.net. So I should type something like pObject->numOfFaces*3 ?
Quote:Original post by azjerei
I cannot really agree that OGL culls what is not on the screen.. oh well.. if ppl say it does, then is maybe does so without really doing so.
I think that maybe what's causing some confusion here is that OpenGL *does* do some processing of triangles that are outside of the view frustum, but the amount of work involved is so minimal on modern hardware that there is no point in doing per-polygon frustum culling on your own. Per-object culling using bounding volumes (rendering all fully and partially visible objects) will yield better performance than doing per-polygon frustum culling. For the terrain, just group together blocks of polygons and test them as a whole.

Anyway, you should definitely invest the time and effort to incorporate vertex arrays (and really, VBOs) into your engine. Since you're unfamiliar with them, it'll take some time to get them working correctly, but the performance gains will be worth it, and there is absolutely nothing that you're doing right now that can't be done with vertex arrays/VBOs. If you think otherwise, then you don't understand them fully.
As you can probably see in the post above yours, I have begun work with Vertex Arrays, but the outcome was not what I expected.

I tried changing the glDrawArrays(..) call to

glDrawArrays(GL_TRIANGLES, 0, pObject->numOfVerts * 3);

but that yielded nothing except an FPS of 1!!
This probably isn't the problem because I don't see any index loading code when you load the level, but it could help.

Are you sure that the order you store the vertices is the order of the triangles (ie: tri0=(vert0,vert1,vert2), tri1=(vert3,vert4,vert5), etc). If not then you will need an array of faces storing the indices into the vertex array for each triangle, and then use glDrawElements() or glDrawRangeElements().

Like I said, from the loading code you posted this probably isn't the problem, but it does look like it is creating triangles from the wrong vertices.
I do it like this, roughly:

1. Level is read from file.
--1.2. When the number of vertices is read for an object, that object's
own vertex array is created with a size equal to the number of verts.
The vertex normal array is also created in this step since it is of the
same size.
--1.3. When the number of texcoords are read, a texcoord array is created with
the size of the number of texture coordinates for the object. This array
also belongs to the object.
--1.4. When a vertice is read from the file, it assigns the coordinates of that
vertex into the vertex array. The vertices are stored like this in the
file:

# X.xx Y.yy Z.zz (ex. 0 99.00000 -89.07700 100.00000) where # is the
number of the vertex and X, Y and Z are the coordinates (floats).

The same procedure is done when reading a normal or a texture coordinate.
They are stored in the same manner.

So.. what the above thing does (well, I hope it does according to how I have written) is that for each object, it stores the vertices, normals and texcoords in arrays like so:

el0.x, el0.y, el0.z, el1.x, el1.y, el1.z, el2.x, el2.y, el2.z, el3.x, el3.y, el3.z ... and so on and so forth (el stands for element, meaning either vertex, normal or texcoord, though not in the same array!).

Is this the correct way to store them?
Kalidor, I think that you are correct. Just checked up on the Vertex Array tutorial that I used (not a good tutorial at all, it does not explain anything). It seems that I need to store the indices.. whatever that is.. never heard that term before now :)

Could anybody explain?

This topic is closed to new replies.

Advertisement