Sign in to follow this  
Endar

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;

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;
}
// 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 this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Any ideas what could be causing this apart from stuffed tex coords?


How about a black texture?

Share this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 shading

glDisable(GL_LIGHTING); // lighting disabled
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// really nice perspective calculations

glClearDepth(1.0f); // set gl clear depth
glEnable(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 this post


Link to post
Share on other sites
Quote:
Original post by Endar
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 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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by Endar
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?


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 this post


Link to post
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 this post


Link to post
Share on other sites
Quote:
Original post by Endar
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?


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

Share this post


Link to post
Share on other sites
I have this for my md2 loader

the ReadShort are s and t accordingly.

header.skinwidth and header.skinheight are dimention of the texture in pixels



//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 this post


Link to post
Share on other sites
Quote:
Original post by DMINATOR
header.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 this post


Link to post
Share on other sites
Guest Anonymous Poster
it is size in pixels the texture has. If you scale texture proportionally then it doesn't matter.

-DMINATOR

Share this post


Link to post
Share on other sites
Guest Anonymous Poster

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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 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.
}
}


Share this post


Link to post
Share on other sites
Quote:
Original post by DMINATOR
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 ?.


'&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 vertex

public:
// functions
};




Share this post


Link to post
Share on other sites
Quote:
Original post by Endar
Quote:
Original post by DMINATOR
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 ?.


'&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 this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this