# md2 texturing

## Recommended Posts

I have an md2 model that won't be textured. Whenever I try the model just appears black. I thought previously this was because I was setting the color of the vertices to black, but I changed them to white, and I found that the model appears completely black when textured (the texture is a mostly black color). I thought this was strange, so I tried texturing with another texture, something which wouldn't properly fit on the model, but something that I would at least be able to see. The texture had a lot of blue, so the model ended up turning blue (a single color, not several shades). This is fairly confusing for me because using the same bitmap loading code I can load and display another bitmap on another model fine, so that leads me to believe that it is not the bitmap loading code. So the only thing left is the texture coords. Is it possible to verify that these are correct? This is how they are being calculated:
m_numST = modelHeader->m_numST;

float height;
float width;
// if we don't have a texture
if( m_texture == NULL ){
width = 1.0f;		// no texture coords
height = 1.0f;
}
else{
// set the proper texture height and width
width = m_texture->getSize().width;
height = m_texture->getSize().height;
}
// read in the texture coords
for (i = 0; i < m_numST; i++){
m_vertexList[i].u = (float)stPtr[i].s / (float)width;
m_vertexList[i].v = (float)stPtr[i].t / (float)height;
}


Any ideas what could be causing this apart from stuffed tex coords?

##### Share on other sites
Quote:
 Any ideas what could be causing this apart from stuffed tex coords?

##### Share on other sites
This is the texture that I'm trying to use: linky

This is straight from the irrlicht engine v0.1

##### Share on other sites
Well, I posted this almost 12 hours ago and have been checking it through the day with only 1 reply.

I think it deserves a bump.

##### Share on other sites
Try using a standard q2 model with a 256x256 map.
I had a problem like this long ago that was because my texture was at a different size than the models map.
I don't know if your problem is the same but you should give it a try.
Also be sure texturing is enabled...

##### Share on other sites
A few things pop into my mind: are you using lighting, and if not, have you tried setting the colour to white (since GL_MODULATE'd make the entire model black if you were using black for your colour, regardless of the texture).

##### Share on other sites
Well, I've got lighting disabled, and the color of each vertex is white. And since I don't know what GL_MODULATE is, its probably fair to say that I'm not using it.

This is the part of my code where I init OGL things:
glShadeModel(GL_SMOOTH);	// enable smooth shadingglDisable(GL_LIGHTING);		// lighting disabledglFrontFace(GL_CW);		glEnable(GL_CULL_FACE);glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// really nice perspective calculationsglClearDepth(1.0f);		// set gl clear depthglEnable(GL_DEPTH_TEST);glDepthFunc(GL_LEQUAL);glEnable(GL_TEXTURE_2D);	// enable 2D texturing

And, plus, I can load a simple cube from my own model file (just the vertices and everything written straight to the file, no compression or anything fancy), and I can texture it, and it works perfectly.

##### Share on other sites
Quote:
 Original post by EndarI thought this was strange, so I tried texturing with another texture, something which wouldn't properly fit on the model, but something that I would at least be able to see. The texture had a lot of blue, so the model ended up turning blue (a single color, not several shades).

This makes me think that there is something wrong with the texture coords on the model...

If you are able to render other md2s just fine, then when you performed the test stated above you would have expected the model to look like a mess of colors from the not-matching texture... even if the texture was not the standard size, you'd think that you would see more than one color.

is there a way to make sure that the model has texture coordinates that look right?

##### Share on other sites
Unless someone can give me an idea, I don't think there is an easy way.

I've been looking at them, and they haven't been anything stupid, the ones that I've seen have all been between 0-1, and, as far as I can tell with my beginner's experience, they look okay.

##### Share on other sites
You might check my previous post. I had similar problems myself.

clicky

The part after previous post - is with error. Above it is the solved.

##### Share on other sites
When you scale an image, say 308x193, does it have to be to the closest power of 2, or do you scale both of them up to the next power of 2?

Edit:: So should the scaled size be 256x256 or 512x256?

Edit2:: Or does it not matter as long as you scale them both the same way?

[Edited by - Endar on November 7, 2005 12:36:42 AM]

##### Share on other sites
Quote:
 Original post by EndarWhen you scale an image, say 308x193, does it have to be to the closest power of 2, or do you scale both of them up to the next power of 2?Edit:: So should the scaled size be 256x256 or 512x256?Edit2:: Or does it not matter as long as you scale them both the same way?

I think it doesn't matter.

Btw try to flip your texture horizontally or vertically and both. I had this problem also, untill I figured to set the UV coordinates correctly.

##### Share on other sites
Okay, so, currently, I'm scaling them both up.

How do I flip the texture? Do I actually use a gl call, or is this something like just doing:
m_vertexList[i].u = 1 - ((float)stPtr[i].s / (float)width);m_vertexList[i].v = 1 - ((float)stPtr[i].t / (float)height);

Does this flip it both horizontally and vertically?

##### Share on other sites
Quote:
 Original post by EndarOkay, so, currently, I'm scaling them both up.How do I flip the texture? Do I actually use a gl call, or is this something like just doing:m_vertexList[i].u = 1 - ((float)stPtr[i].s / (float)width);m_vertexList[i].v = 1 - ((float)stPtr[i].t / (float)height);Does this flip it both horizontally and vertically?

I think that works, yes. You can also try to flip it in an image-editing application.

##### Share on other sites
I have this for my md2 loader

the ReadShort are s and t accordingly.

//un compress them to temp array    kbo[i].u = (float)ReadShort(&file) / header.skinwidth;    kbo[i].v = (float)ReadShort(&file) / header.skinheight - 1;//and now I put them into ready to use form	for(i = 0; i < header.num_face; i++)	{		// A side		tbo[cnt].u = kbo[fbo[i].auv].u;		tbo[cnt++].v = kbo[fbo[i].auv].v;		// B side		tbo[cnt].u = kbo[fbo[i].buv].u;		tbo[cnt++].v = kbo[fbo[i].buv].v;		// C side		tbo[cnt].u = kbo[fbo[i].cuv].u;		tbo[cnt++].v = kbo[fbo[i].cuv].v;	}

##### Share on other sites
Quote:
 Original post by DMINATORheader.skinwidth and header.skinheight are dimention of the texture in pixels

The size after the texture has been scaled, or the size before the texture has been scaled?

##### Share on other sites
it is size in pixels the texture has. If you scale texture proportionally then it doesn't matter.

-DMINATOR

##### Share on other sites

The MD2 file has the texture coords in range 0-1 or 0 - texturesize ?

The texture coordinates don't have too much to do with the actual texture size in OpenGl (or DX). That is, I can use high detail textures or low resolution textures without touching the texture coordinates.

I can imagine that scaling the coords screw up the texturing.

##### Share on other sites
Okay, well, I'm no longer scaling the actual coords that I'm using to calculate the coords from the shorts.

Here is what it currently looks like, and I've tried flipping the texture using the "1 - " at the beginning of the u and v calculations, tried both individually, at the same time, and none, and I'm always getting similar variations on what is in the picture.

##### Share on other sites
Please post how are you filling vertex array and how are you rendering it.

-DMINATOR

##### Share on other sites
This is how I update the interpolation and fill the array I'm using to render the model with the vertices:
/** * Updates the animation of the model. * Constructs the vertices between the two keyframes and * stores them in m_displayVertexList[i]. * \param percent The percent to interpolate by (the percentage to advance through each frame, each * interpolation call). The percentage is a decimal point: 0.25 for 25% */void updateInterpolation(float percent = 0.01f){	util::CVector3d v1;	// current frame point values	util::CVector3d v2;	// next frame point values	scene::CVertex3d vertex;// temporarily holds an interpolated vertex	// If the start and end frames are the same, then that means that	// we don't want any animation.	if( m_startFrame == m_endFrame ){		// if we don't want animation, we have to assign the right vertices for the frame		if( m_displayVertexList.getSize() != m_numVertices ){			m_displayVertexList.clear();			m_displayVertexList.resize(m_numVertices);	// size array		}					// Maybe we're already on the frame we want, so we don't have to reassign		// all the vertices in the model.		if( m_currentFrame != m_startFrame ){			// reassign all the vertices in the model			m_currentFrame = m_startFrame;			for(int i=0; i < m_numVertices; i++)				m_displayVertexList[i] = m_vertexList[(m_currentFrame*m_numVertices) + i];		}		return;	}	// copy the required vertices into the array	m_displayVertexList.clear();	m_displayVertexList.reserve( m_numVertices );	// If interpolation of a whole frame was done, increment the current frame and next frame.	// Note:: this wraps around again to the beginning of the whole animation.	if (m_interpol >= 1.0f){		m_interpol = 0.0f;				// set interpolation to 0		m_currentFrame++;					// start at next frame		if (m_currentFrame >= m_endFrame)			m_currentFrame = m_startFrame;	// wrap around to the start		m_nextFrame = m_currentFrame + 1;	// assign the next frame to interpolate to		if (m_nextFrame >= m_endFrame || m_nextFrame >= m_numFrames)			m_nextFrame = m_startFrame;		// wrap around to the start	}	// update the interpolation for each vertex	for(int i = 0; i < m_numVertices; i++){		// get the points of each frame to interpolate between		v1 = m_vertexList[(m_currentFrame*m_numVertices) + i].point;		v2 = m_vertexList[(m_nextFrame*m_numVertices) + i].point;		// Store first interpolated vertex of triangle.		// we want the color and tex coords		vertex = m_vertexList[(m_currentFrame*m_numVertices) + i];		vertex.point.x = v1.x + m_interpol * (v2.x - v1.x);		vertex.point.y = v1.y + m_interpol * (v2.y - v1.y);		vertex.point.z = v1.z + m_interpol * (v2.z - v1.z);		// render properly textured triangle		m_displayVertexList.push_back(vertex);	}	m_interpol += percent;  // increase percentage of interpolation done for this frame	// update the normals for all the vertices (the average of the faces that vertex	// is used in).	util::CVector3d temp;	util::array<util::CVector3d> normal_list;	util::array<unsigned int> normal_index_list;	normal_list.resize(m_numVertices);	normal_index_list.resize(m_numVertices);	int i1, i2, i3;	for(i=0; i < m_numTriangles; i+=3){		// get vertex indices of a triangle		i1 = m_displayIndexList[i];		i2 = m_displayIndexList[i+1];		i3 = m_displayIndexList[i+2];		// calculate the normal for the triangle		temp = calculateNormal(m_displayVertexList[i1].normal, 					m_displayVertexList[i2].normal, m_displayVertexList[i3].normal);		// add the current normal to get a normal total for each of the vertices		// and increase the number of normals used for each total		normal_list[i1] += temp;		normal_index_list[i1]++;		normal_list[i2] += temp;		normal_index_list[i2]++;		normal_list[i3] += temp;		normal_index_list[i3]++;	}	// calculate the average of each normal and assign to its vertex	for(i=0; i < m_numVertices; i++)		m_displayVertexList[i].normal = normal_list[i] / (float)normal_index_list[i];}

This is the load function, which includes filling the array with contains all the vertices for each keyframe in the model (into dynamic array 'm_vertexList').
/** * Load an MD2 model from file. * \param file A reference to a CReadFile object open to the model file. * \return True if the file was loaded properly, else false */bool CAnimatedMeshMD2::load(io::CReadFile& file){	char *buffer;			// file buffer	modelHeader_t *modelHeader;	// model header	stIndex_t *stPtr;		// texture data	frame_t *frame;			// frame data	mesh_t *bufIndexPtr;		// index variables	util::array<mesh_t> indexList;	int i,j;	// file is not open	if( !file.isOpen() ){		util::Message::print("CAnimatedMeshMD2::load: file not opened.");		return false;	}	// read entire file into buffer	buffer = new char [file.getSize()+1];	file.read(buffer, sizeof(char)*file.getSize() );	// extract model file header from buffer	modelHeader = (modelHeader_t*)buffer;	// allocate memory for the vertex list	m_vertexList.reserve( modelHeader->numXYZ * modelHeader->m_numFrames );	m_numVertices = modelHeader->numXYZ;	m_numFrames = modelHeader->m_numFrames;	for (j = 0; j < m_numFrames; j++)	{		frame = (frame_t*)&buffer[modelHeader->offsetFrames + modelHeader->framesize * j];		// just adding more vertices, frame by frame, right after one another		//vertexListPtr = (vector_t*)&m_vertexList[m_numVertices * j];		for (i = 0; i < m_numVertices; i++)		{			scene::CVertex3d v;			v.point.x = frame->scale[0] * frame->fp[i].v[0] + frame->translate[0];			v.point.z = frame->scale[1] * frame->fp[i].v[1] + frame->translate[1];			v.point.y = frame->scale[2] * frame->fp[i].v[2] + frame->translate[2];			v.color = video::CColor(1.0f, 1.0f, 1.0f);	// make the color white so we can see the														// texture			m_vertexList.push_back(v);	// add the next vertex to the list		}	}	m_numST = modelHeader->m_numST;	stPtr = (stIndex_t*)&buffer[modelHeader->offsetST];	float height;	float width;	// if we don't have a texture	if( m_texture == NULL ){		width = 1.0f;		// no texture coords		height = 1.0f;	}	else{		// set the proper texture height and width		width = m_texture->getSize().width;		height = m_texture->getSize().height;	}	///////////////////////////	//FILE* filep = fopen("tex_coords.txt", "w");	//fprintf(filep, "num tex coords: %d\n", m_numST);	// read in the texture coords	for (i = 0; i < m_numST; i++){		m_vertexList[i].u = (float)stPtr[i].s / width;		m_vertexList[i].v = 1 - (float)stPtr[i].t / height;	//	fprintf(filep, "%f %f\n", m_vertexList[i].u, m_vertexList[i].v);	}	//fclose(filep);	//////////////////////////	m_numTriangles = modelHeader->numTris;	// point to triangle indexes in buffer	bufIndexPtr = (mesh_t*)&buffer[modelHeader->offsetTris];	indexList.resize( m_numFrames * m_numTriangles );	// create a mesh (triangle) list	for(j = 0; j < m_numFrames; j++)         	{		// for all triangles in each frame		for(i = 0; i < m_numTriangles; i++)		{			indexList[i].meshIndex[0] = bufIndexPtr[i].meshIndex[0];			indexList[i].meshIndex[1] = bufIndexPtr[i].meshIndex[1];			indexList[i].meshIndex[2] = bufIndexPtr[i].meshIndex[2];			indexList[i].stIndex[0] = bufIndexPtr[i].stIndex[0];			indexList[i].stIndex[1] = bufIndexPtr[i].stIndex[1];			indexList[i].stIndex[2] = bufIndexPtr[i].stIndex[2];		}	}	/* Build the display index list (shouldn't change, only the position of vertices should	/* change during animation/interpolation) */	m_displayIndexList.clear();	m_displayIndexList.reserve( m_numTriangles * 3 );	// insert the indices into the display index list (to pass as a complete array to drawIndexedTriangleList)	for(i=0; i < m_numTriangles; i++){		m_displayIndexList.push_back( indexList[i].meshIndex[0] );		m_displayIndexList.push_back( indexList[i].meshIndex[1] );		m_displayIndexList.push_back( indexList[i].meshIndex[2] );	}	// add the texture coords to the vertices	for(i=0; i < m_numFrames; i++){		for(int j=0; j < m_numVertices; j++){			// Copy the texture coords from the vertices of the first keyframe			// to the other vertices of all the other frames.			m_vertexList[(i*m_numVertices) + j].u = m_vertexList[(0*m_numVertices) + j].u;			m_vertexList[(i*m_numVertices) + j].v = m_vertexList[(0*m_numVertices) + j].v;			// NOTE:: this will probably kill the memory paging system on the computer, with			// the 67,000 vertices total for all the keyframes, because we're always refering			// back to the first keyframe.		}	}	// close file and free memory	free(buffer);	m_currentFrame = 0;	m_nextFrame = 1;	m_interpol = 0.0f;     	return true;}

This is the render function:
/** * Render the model using indexed triangle lists. */void render(){	if(m_texture)		m_texture->apply();	// apply the texture	// if the animation state is NOT correct for the currentFrame	if( !(m_currentFrame >= MD2AnimationList[m_animState].begin &&		m_currentFrame < MD2AnimationList[m_animState].end) ){		// set the animation state correctly for the currentFrame of animation		for(int i=0; i < NUM_OF_ANIM; i++)			if( m_currentFrame >= MD2AnimationList[i].begin && m_currentFrame < MD2AnimationList[i].end ){				m_animState = (MD2AnimationState) i;				break;			}	}	// calculate the percentage for advance through the frames depending	// on the animation data and the frames-per-second for each anim	float p = (float)( MD2AnimationList[m_animState].fps / 		  (float)( MD2AnimationList[m_animState].end - MD2AnimationList[m_animState].begin) );	// update the animation	updateInterpolation(p);	// draw the indexed triangle list	m_sceneManager->getVideoDriver()->drawIndexedTriangleList(				m_displayVertexList.getPtr(), m_displayVertexList.getSize(),				m_displayIndexList.getPtr(), m_displayIndexList.getSize() );	ISceneGraphNode::render();	// render all the children}

/** * Draws an indexed triangle list. * \param v A const pointer to an array of CVertex3d objects, that are the vertices in the object * \param vertex_count The number of vertices in the array * \param index_list A pointer to the array of indices (unsigned int) * \param index_count The size of the index array */void COpenGLDriver::drawIndexedTriangleList(const scene::CVertex3d* v, unsigned int vertex_count,					const unsigned int* index_list, unsigned int index_count){	util::array<unsigned char> color_buffer;	// temporarily holds the colors in float format, which OGL understands	// Enable the use of vertex arrays	glEnableClientState(GL_COLOR_ARRAY);	glEnableClientState(GL_VERTEX_ARRAY);	glEnableClientState(GL_TEXTURE_COORD_ARRAY );	glEnableClientState(GL_NORMAL_ARRAY );	// convert colors into a format OGL understands (from a single int, to a series of chars)	color_buffer.resize(vertex_count*4);	// because there are 4 components for each color for each vertex	for(int i=0; i < vertex_count*4; i+=4){	// again, vertex_count*4 becuase it is 4 component color		color_buffer[i] = v[i/4].color.getRed();		color_buffer[i+1] = v[i/4].color.getGreen();		color_buffer[i+2] = v[i/4].color.getBlue();		color_buffer[i+3] = v[i/4].color.getAlpha();	}	// define arrays to use	/* http://www.gamedev.net/community/forums/viewreply.asp?ID=2242450	 * The stride is the number of bytes between the start of one entry in the 	 * vertex array to the start of the next entry. That is, how many bytes you 	 * must move in memory to get the next following entry. So the stride in your 	 * case should be sizeof(CVertex3d).	 */	glColorPointer(4, GL_UNSIGNED_BYTE, 0, color_buffer.getPtr() );	glNormalPointer(GL_FLOAT, sizeof(scene::CVertex3d), &v[0].normal );	glTexCoordPointer(2, GL_FLOAT, sizeof(scene::CVertex3d), &v[0].u );	glVertexPointer(3, GL_FLOAT, sizeof(scene::CVertex3d), &v[0].point );	glDrawElements(GL_TRIANGLES, index_count, GL_UNSIGNED_INT, index_list);	// draw all four arrays	// increase the number of primitives drawn	IVideoDriver::drawIndexedTriangleList(v, vertex_count, index_list, index_count);}

##### Share on other sites
Actually I used glDrawElements first but encountered the same problem, so I decided to glDrawArray, which solved most of the problems.

anyway I understand what you trying to do here,
but why not make a separate array for vertices and texture coordinates.

and this looks also strange:

glTexCoordPointer(2, GL_FLOAT, sizeof(scene::CVertex3d), &v[0].u );

you are pointing only to one coordinate, so the v is ignored completelly. And using sizeof(scene::CVertex3d) - 3 floats ?.

// add the texture coords to the verticesfor(i=0; i < m_numFrames; i++){for(int j=0; j < m_numVertices; j++){// Copy the texture coords from the vertices of the first keyframe// to the other vertices of all the other frames.m_vertexList[(i*m_numVertices) + j].u = m_vertexList[(0*m_numVertices) + j].u;m_vertexList[(i*m_numVertices) + j].v = m_vertexList[(0*m_numVertices) + j].v;// NOTE:: this will probably kill the memory paging system on the computer, with// the 67,000 vertices total for all the keyframes, because we're always refering// back to the first keyframe.}}

##### Share on other sites
Quote:
 Original post by DMINATORglTexCoordPointer(2, GL_FLOAT, sizeof(scene::CVertex3d), &v[0].u );you are pointing only to one coordinate, so the v is ignored completelly. And using sizeof(scene::CVertex3d) - 3 floats ?.

'&v[0].u' takes the address of the 'u' texture coordinate of the first vertex in the array, and I didn't post the CVertex3d class, but the v coordinate comes right after 'u' as the class is set out in memory.

The 'sizeof(scene::CVertex3d)' indicates the stride, which is the amount of bytes from the beginning of the first coord to the beginning of the next set of coords.

class CVertex3d{public:	util::CVector3d point;	///< The position of this vertex in 3d space	util::CVector3d normal;	///< The normal vector of the vertex.	float 	u,		///< Component of the texture coordinates		v;		///< Component of the texture coordinates	video::CColor color;	///< Color for the vertexpublic:	// functions};

##### Share on other sites
Quote:
Original post by Endar
Quote:
 Original post by DMINATORglTexCoordPointer(2, GL_FLOAT, sizeof(scene::CVertex3d), &v[0].u );you are pointing only to one coordinate, so the v is ignored completelly. And using sizeof(scene::CVertex3d) - 3 floats ?.

'&v[0].u' takes the address of the 'u' texture coordinate of the first vertex in the array, and I didn't post the CVertex3d class, but the v coordinate comes right after 'u' as the class is set out in memory.

The 'sizeof(scene::CVertex3d)' indicates the stride, which is the amount of bytes from the beginning of the first coord to the beginning of the next set of coords.

*** Source Snippet Removed ***

Oh yes you are right , I haven't used stride before. And to tell you honestly it does look pretty complicated to me.

##### Share on other sites
A little, but I've rendered a couple of cubes with textures, so I'm giving that particular code the benefit of the doubt. [smile]

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628305
• Total Posts
2981962

• 9
• 12
• 11
• 12
• 11