程序员爱装B

写装A程序 做装C的事情

[搬家文] 第九课 动画-part 3

    //Load the texture coordinates
    input.seekg(texCoordOffset, ios_base::beg);
    model->texCoords = new MD2TexCoord[numTexCoords];
    for(int i = 0; i < numTexCoords; i++) {
        MD2TexCoord* texCoord = model->texCoords + i;
        texCoord->texCoordX = (float)readShort(input) / textureWidth;
        texCoord->texCoordY = 1 - (float)readShort(input) / textureHeight;
    }

    接下来,我们载入纹理坐标。每个纹理坐标用两个short表示。为了能从每个short获得合适的float,我们需要除以在文件开头找到的纹理的 长和宽。对于y轴坐标,需要在纹理前面加一个负号,因为md2文件的y轴是从纹理的顶部向下计算的,而OpenGL是从纹理的底部开始向上计算的。

    //Load the triangles
    input.seekg(triangleOffset, ios_base::beg);
    model->triangles = new MD2Triangle[numTriangles];
    model->numTriangles = numTriangles;
    for(int i = 0; i < numTriangles; i++) {
        MD2Triangle* triangle = model->triangles + i;
        for(int j = 0; j < 3; j++) {
            triangle->vertices[j] = readUShort(input);
        }
        for(int j = 0; j < 3; j++) {
            triangle->texCoords[j] = readUShort(input);
        }
    }

    现在,我们载入三角形,这些其实只是一堆顶点和纹理坐标的索引号。

    //Load the frames
    input.seekg(frameOffset, ios_base::beg);
    model->frames = new MD2Frame[numFrames];
    model->numFrames = numFrames;
    for(int i = 0; i < numFrames; i++) {
        MD2Frame* frame = model->frames + i;
        frame->vertices = new MD2Vertex[numVertices];
        Vec3f scale = readVec3f(input);
        Vec3f translation = readVec3f(input);
        input.read(frame->name, 16);
        
        for(int j = 0; j < numVertices; j++) {
            MD2Vertex* vertex = frame->vertices + j;
            input.read(buffer, 3);
            Vec3f v((unsigned char)buffer[0],
                    (unsigned char)buffer[1],
                    (unsigned char)buffer[2]);
            vertex->pos = translation + Vec3f(scale[0] * v[0],
                                              scale[1] * v[1],
                                              scale[2] * v[2]);
            input.read(buffer, 1);
            int normalIndex = (int)((unsigned char)buffer[0]);
            vertex->normal = Vec3f(NORMALS[3 * normalIndex],
                                   NORMALS[3 * normalIndex + 1],
                                   NORMALS[3 * normalIndex + 2]);
        }
    }

    现在我们载入帧。每个帧以6个浮点数开始,表明了变换和伸缩顶点的数组。然后的16个字节表示帧的名字。接下来是顶点,对于每个顶点,有两个无符号 型char表示位置,我们可以通过伸缩和变换将其变为浮点数。然后有一个无符号char表示法向量,这是我们先前看到的NORMALS数组的索引。

    model->startFrame = 0;
    model->endFrame = numFrames - 1;
    return model;
}

    最后,设置开始和结束帧,并返回模型。

void MD2Model::setAnimation(const char* name) {
    /* The names of frames normally begin with the name of the animation in
     * which they are, e.g. "run", and are followed by a non-alphabetical
     * character.  Normally, they indicate their frame number in the animation,
     * e.g. "run_1", "run_2", etc.
     */
    bool found = false;
    for(int i = 0; i < numFrames; i++) {
        MD2Frame* frame = frames + i;
        if (strlen(frame->name) > strlen(name) &&
            strncmp(frame->name, name, strlen(name)) == 0 &&
            !isalpha(frame->name[strlen(name)])) {
            if (!found) {
                found = true;
                startFrame = i;
            }
            else {
                endFrame = i;
            }
        }
        else if (found) {
            break;
        }
    }
}

    这个函数找到开始和结束帧,以使用不同帧的名字来指示动画,这注释里有说明。

void MD2Model::advance(float dt) {
    if (dt < 0) {
        return;
    }
    
    time += dt;
    if (time < 1000000000) {
        time -= (int)time;
    }
    else {
        time = 0;
    }
}

    现在,我们有一个播放动画的方法,就是增大我们的time值。为了保证这个值介于0到1,我们使用-=(int)time(除非time真的非常大,这样将time转换为int就会出现问题。)

void MD2Model::draw() {
    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, textureId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    这里是我们绘制3D模型的代码。从告诉OpenGL纹理和想使用的纹理映射开始。

    //Figure out the two frames between which we are interpolating
    int frameIndex1 = (int)(time * (endFrame - startFrame + 1)) + startFrame;
    if (frameIndex1 > endFrame) {
        frameIndex1 = startFrame;
    }
    
    int frameIndex2;
    if (frameIndex1 < endFrame) {
        frameIndex2 = frameIndex1 + 1;
    }
    else {
        frameIndex2 = startFrame;
    }
    
    MD2Frame* frame1 = frames + frameIndex1;
    MD2Frame* frame2 = frames + frameIndex2;

    现在使用time值,计算出那两个帧中间需要插值。

    //Figure out the two frames between which we are interpolating
    int frameIndex1 = (int)(time * (endFrame - startFrame + 1)) + startFrame;
    if (frameIndex1 > endFrame) {
        frameIndex1 = startFrame;
    }
    
    int frameIndex2;
    if (frameIndex1 < endFrame) {
        frameIndex2 = frameIndex1 + 1;
    }
    else {
        frameIndex2 = startFrame;
    }
    
    MD2Frame* frame1 = frames + frameIndex1;
    MD2Frame* frame2 = frames + frameIndex2;

    现在计算出我们在两个帧中的那个部分。0表示我们在第一个帧,1表示在第二个帧,0.5表示在中间。

//Draw the model as an interpolation between the two frames
glBegin(GL_TRIANGLES);
for(int i = 0; i < numTriangles; i++) {
   MD2Triangle* triangle = triangles + i;
   for(int j = 0; j < 3; j++) {
      MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
      MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
      Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;

    现在我们遍历每个三角形,每个顶点,他们的位置取这两个帧的插值。

      Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
      if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) {
          normal = Vec3f(001);
      }
      glNormal3f(normal[0], normal[1], normal[2]);

    对于每个法向量做相同事情。如果平均下来为0向量,我们将之改为一个任意的向量,因为0向量不表示任何方向,因此不能作为一个法向量。实际上有一个更好的办法去两个方向的军制,但是我们采用线性平均,因为这比较简单。

      MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
      glTexCoord2f(texCoord->texCoordX, texCoord->texCoordY);
      glVertex3f(pos[0], pos[1], pos[2]);
      }
    }
    glEnd();

    现在只需要找到合适的纹理坐标,并调用glTexCoord2f和glVertex3f函数。

posted on 2010-07-19 20:30 camel 阅读(101) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2024年9月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

统计

常用链接

留言簿

随笔档案

文章档案

搜索

最新评论

阅读排行榜

评论排行榜