Something wrong with getIndices?

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
Guest

Something wrong with getIndices?

Post by Guest »

I'm trying to make a funktion that can calculate lower LOD index buffers for a mesh. This funktion needs the vertex buffer and the index buffer from the given mesh. I did some experimenting and tried this code in the HelloWorld example:

Code: Select all

	IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
	IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );

	IMesh* im = mesh->getMesh(0);

	IMeshBuffer* mb = im->getMeshBuffer(0);

	for (int i = 0; i < mb->getIndexCount(); i++)
		cout << "getIndices[" << i << "]: " << mb->getIndices()[i] << endl;
The indices that is printed isn't what I expected. The first three is 0, 1, 2 which I'd expect. But the next three is 3, 4, 5. I'd expect something like 2, 1, 3. In fact, all index = i. Isn't there something wrong?

Thanks in advance,
Per Rasmussen.

Ps. I think it's great that there are many user tutorials, but some developer tutorials would be nice to.
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Re: Something wrong with getIndices?

Post by niko »

Anonymous wrote: The indices that is printed isn't what I expected. The first three is 0, 1, 2 which I'd expect. But the next three is 3, 4, 5. I'd expect something like 2, 1, 3. In fact, all index = i. Isn't there something wrong?


You are right, the mesh does not seem to be optimal. There aren't a lot shared vertices. I think I did not implement the .md2 loader in a effecient way. But you might try other meshes, maybe the have nicer indices.
Last edited by niko on Sat Dec 27, 2003 8:23 am, edited 1 time in total.
Guest

Post by Guest »

Indeed. It does have many duplicate vertices. So I figured that I would start by making a function that could optimize the index buffer.

I tried to downcast my IMeshBuffer to a SMeshBuffer and then access its indices through the member variable Indices. Apparently, Indices is an empty array. This code caused an access violation:

Code: Select all

	SMeshBuffer *smb = (SMeshBuffer *)mb;

	cout << "indices[" << 0 << "]: " << smb->Indices[0] << endl;
Here Indices.used is 0 according to my debugger. Why is this?

Ps. Btw, the faerie.md2 has the same problem, so you're probably right in your assumtion that the md2 loader is bad.
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Post by niko »

I think the problem is that the returned mesh is not a SMeshBuffer but a CAnimatedMeshMD2. The cast is simply wrong.
Guest

Post by Guest »

After switching my brain on (I forget that sometimes :) ) I realized that it wasn't nessesary to downcast at all, since the IMeshBuffer also can get me the pointers to the buffers.

Anyway, after examining the source, I don't think it will be hard to make the MD2 loader a bit "smarter" concerning the indices. I'll atempt to make the modifications. I can post the code when I'm done.

Best regards,
Per Rasmussen.
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Post by niko »

Cool :)
Guest

Post by Guest »

This should fix the problem. I do it a bit strange because the md2 format handles texcoords different then irrlicht. It uses indexed texcoord. Also, in the faerie.md2 some vertices apparently has the same pos and normal, but different texcoords. Anyway, due to this, the loader has to loop through all existing vertices, each time a new one is created, to see if it already exists (with the same texcoords). This, unfortunately increases the loading time. If anybody know a faster way, please let my know.

Here is the new loadfile:

Code: Select all

#define S3DVERTEX_CLOSE_ENOUGH(v1, v2, e)  ((v1.Pos.X <= v2.Pos.X + e && v1.Pos.X >= v2.Pos.X - e) && \
											(v1.Pos.Y <= v2.Pos.Y + e && v1.Pos.Y >= v2.Pos.Y - e) && \
											(v1.Pos.Z <= v2.Pos.Z + e && v1.Pos.Z >= v2.Pos.Z - e) && \
											(v1.TCoords.X <= v2.TCoords.X + e && v1.TCoords.X >= v2.TCoords.X - e) && \
											(v1.TCoords.Y <= v2.TCoords.Y + e && v1.TCoords.Y >= v2.TCoords.Y - e))

//! loads an md3 file
bool CAnimatedMeshMD2::loadFile(io::IReadFile* file)
{
	if (!file)
		return false;

	SMD2Header header;
	s8* frames = 0;

	file->read(&header, sizeof(SMD2Header));

	if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION)
	{
		os::Printer::log("MD2 Loader: Wrong file header", file->getFileName(), ELL_WARNING);
		return false;
	}

	// create Memory for indices and frames

	Indices.reallocate(header.numTriangles);
	FrameList = new core::array<video::S3DVertex>[header.numFrames];
	FrameCount = header.numFrames;

	s32 i;
	
	for (i=0; i<header.numFrames; ++i)
		FrameList[i].reallocate(header.numVertices);

	// read TextureCoords

	file->seek(header.offsetTexcoords, false);
	SMD2TextureCoordinate* textureCoords = new SMD2TextureCoordinate[header.numTexcoords];

	if (!file->read(textureCoords, sizeof(SMD2TextureCoordinate)*header.numTexcoords))
	{
		os::Printer::log("MD2 Loader: Error reading TextureCoords.", file->getFileName(), ELL_ERROR);
		return false;
	}

	// read Triangles

	file->seek(header.offsetTriangles, false);

	SMD2Triangle *triangles = new SMD2Triangle[header.numTriangles];
	if (!file->read(triangles, header.numTriangles *sizeof(SMD2Triangle)))
	{
		os::Printer::log("MD2 Loader: Error reading triangles.", file->getFileName(), ELL_ERROR);
		return false;
	}

	// read Vertices

	s8 buffer[MD2_MAX_VERTS*4+128];
	SMD2Frame* frame = (SMD2Frame*)buffer;

	core::array< core::vector3df >* vertices = new core::array< core::vector3df >[header.numFrames];
	core::array< core::vector3df >* normals = new core::array< core::vector3df >[header.numFrames];

	file->seek(header.offsetFrames, false);

	for (i = 0; i<header.numFrames; ++i)
	{
		// read vertices

		vertices[i].reallocate(header.numVertices);
		file->read(frame, header.frameSize);

		// store frame data

		SFrameData fdata;
		fdata.begin = i;
		fdata.end = i;
		fdata.fps = 7;

		if (frame->name[0])
		{
			for (s32 s = 0; frame->name[s]!=0 && (frame->name[s] < '0' ||
				frame->name[s] > '9'); ++s)
				fdata.name += frame->name[s];

			if (!FrameData.empty() && FrameData[FrameData.size()-1].name == fdata.name)
				++FrameData[FrameData.size()-1].end;
			else
				FrameData.push_back(fdata);
		}

		// add vertices

		for (s32 j=0; j<header.numVertices; ++j)
		{
			core::vector3df v;
			v.X = (f32)frame->vertices[j].vertex[0] * frame->scale[0] + frame->translate[0];
			v.Z = (f32)frame->vertices[j].vertex[1] * frame->scale[1] + frame->translate[1];	// µ! z?
			v.Y = (f32)frame->vertices[j].vertex[2] * frame->scale[2] + frame->translate[2];

			vertices[i].push_back(v);

			s32 normalidx = frame->vertices[j].lightNormalIndex;
			if (normalidx > 0 && normalidx < Q2_VERTEX_NORMAL_TABLE_SIZE)
			{
				v.X = Q2_VERTEX_NORMAL_TABLE[normalidx][0];
				v.Y = Q2_VERTEX_NORMAL_TABLE[normalidx][1];
				v.Z = Q2_VERTEX_NORMAL_TABLE[normalidx][2];
			}	

			normals[i].push_back(v);
		}

		// calculate bounding boxes
		if (header.numVertices)
		{
			core::aabbox3d<f32> box;
			box.reset(vertices[i][0]);

			for (s32 j=1; j<header.numVertices; ++j)
				box.addInternalPoint(vertices[i][j]);

			BoxList.push_back(box);
		}
			
	}

	// put triangles into frame list
	
	f32 dmaxs = 1.0f/(header.skinWidth);
	f32 dmaxt = 1.0f/(header.skinHeight);

	video::S3DVertex vtx;
	vtx.Color = video::SColor(255,255,255,255);
	
	for (s32 f = 0; f<header.numFrames; ++f)
	{
		core::array< core::vector3df >& vert = vertices[f];
		int currentIndex = 0;

		for (s32 t=0; t<header.numTriangles; ++t)
		{
			for (s32 n=0; n<3; ++n)
			{
				vtx.Pos = vert[triangles[t].vertexIndices[n]];
				vtx.TCoords.X = (textureCoords[triangles[t].textureIndices[n]].s + 0.5f) * dmaxs;
				vtx.TCoords.Y = (textureCoords[triangles[t].textureIndices[n]].t + 0.5f) * dmaxt;
				vtx.Normal = normals[f].pointer()[triangles[t].vertexIndices[n]];

				int prev = -1;
				for (u32 j = 0; j < FrameList[f].size(); j++)	// See if this vertex already has been used.
				{
					if (S3DVERTEX_CLOSE_ENOUGH(vtx, FrameList[f][j], 0.00001f))
					{
						prev = j;
						break;
					}
				}

				if (prev < 0)  FrameList[f].push_back(vtx);

				if (f == 0)
				{
					if (prev < 0)  Indices.push_back(currentIndex++);
					else
						Indices.push_back(prev);
				}
			}
		}
	}

	//calculateNormals();

	// reallocate interpolate buffer
	if (header.numFrames)
	{
		InterpolateBuffer.set_used(FrameList[0].size());

		s32 count = FrameList[0].size();
		for (i=0; i<count; ++i)
		{
			InterpolateBuffer[i].TCoords = FrameList[0].pointer()[i].TCoords;
			InterpolateBuffer[i].Color = vtx.Color;
		}
	}

	// clean up

	delete [] normals;
	delete [] vertices;
	delete [] triangles;
	delete [] textureCoords;
	TriangleCount = Indices.size() / 3;

	// return

	calculateBoundingBox();

	return true;
}

BTW, shouldn't z and y be swapped in the line I've commented with a µ?

Best Regards,
Per Rasmussen.
niko
Site Admin
Posts: 1759
Joined: Fri Aug 22, 2003 4:44 am
Location: Vienna, Austria
Contact:

Post by niko »

Hm, maybe you are right, but there seems to have occured any problem with the swapped coordinates. For increasing speed: I just wrote a loader for .x files, and had the same problem. Instead of looping through all existing vertices, searching if the same vertex already exists in the buffer before adding a new one, I looped through the vertices in reversed order. This nearly increased creation seed by the factor 3. It works, because often, similar vertices occur next to each other in the buffer. Don't know if it is a solution for the md2 loader too.
madinitaly
Posts: 92
Joined: Sat Nov 29, 2003 8:30 pm
Contact:

Post by madinitaly »

This looks nice, I was doing something similar for the md3 loader, and now I think I'll try to use Per's code (if you don't mind, Per... :D - credit will be given, of course!).
Post Reply