Md2 模型顶点加载问题

Md2 model vertices loading issue

我正在尝试加载 MD2 模型,但似乎无法正确绘制顶点。我现在不加载 UV 或法线只是想看到模型在单个帧中正确显示然后从那里获取它。

这是我的 md2 结构(主要取自 here):

struct v3
{
    union
    {
        struct
        {
            union { float x; float r; };
            union { float y; float g; };
            union { float z; float b; };
        };
        float At[3];
    };
};

struct md2_header
{
    unsigned int Magic;
    unsigned int Version;

    unsigned int TextureWidth;
    unsigned int TextureHeight;

    unsigned int FrameSize;

    unsigned int NumTextures;
    unsigned int NumVertices;
    unsigned int NumUVs;
    unsigned int NumTrigs;
    unsigned int NumGLCommands;
    unsigned int NumFrames;

    unsigned int OffsetTextures;
    unsigned int OffsetUVs;
    unsigned int OffsetTrigs;
    unsigned int OffsetFrames;
    unsigned int OffsetGLCommands;
    unsigned int OffsetEnd;
};

struct md2_vertex
{
    unsigned char At[3];
    unsigned char NormalIndex;
};

struct md2_frame
{
    float       Scale[3];
    float       Translate[3];
    char        Name[16];
    md2_vertex  *Vertices;
};

struct md2_skin
{
    char Name[64];
};

struct md2_uv
{
    unsigned short u;
    unsigend short v;
}

struct md2_triangle
{
    unsigned short Vertices[3];
    unsigned short UVs[3];
};

struct md2_model
{
    md2_header Header;
    md2_uv *UVs;
    md2_triangle *Triangles;
    md2_frame *Frames;
    md2_skin *Skins;
    int *GLCommands;
    unsigned int Texture;
    unsigned int VAO, VBO;
};

这是我的简单加载函数:

void MD2LoadModel (char *FilePath, md2_model *Model)
{
    FILE *File = fopen (FilePath, "rb");
    if (!File)
    {
        fprintf (stderr, "Error: couldn't open \"%s\"!\n", FilePath);
        return;
    }

#define FREAD(Dest, Type, Count)\
    fread(Dest, sizeof(Type), Count, File)

#define FSEEK(Offset)\
    fseek(File, Offset, SEEK_SET)

#define ALLOC(Type, Count)\
    (Type *)malloc(sizeof(Type) * Count)

    /* Read Header */
    FREAD(&Model->Header, md2_header, 1);

    if ((Model->Header.Magic != 844121161) ||
        (Model->Header.Version != 8))
    {
        fprintf (stderr, "Error: bad md2 Version or identifier\n");
        fclose (File);
        return;
    }

    /* Memory allocations */
    Model->Skins = ALLOC(md2_skin, Model->Header.NumTextures);
    Model->UVs = ALLOC(md2_uv, Model->Header.NumUVs);
    Model->Triangles = ALLOC(md2_triangle, Model->Header.NumTrigs);
    Model->Frames = ALLOC(md2_frame, Model->Header.NumFrames);
    Model->GLCommands = ALLOC(int, Model->Header.NumGLCommands);

    /* Read model data */
    FSEEK(Model->Header.OffsetTextures);
    FREAD(Model->Skins, md2_skin, Model->Header.NumTextures);

    FSEEK(Model->Header.OffsetUVs);
    FREAD(Model->UVs, md2_uv, Model->Header.NumUVs);

    FSEEK(Model->Header.OffsetTrigs);
    FREAD(Model->Triangles, md2_triangle, Model->Header.NumTrigs);

    FSEEK(Model->Header.OffsetGLCommands);
    FREAD(Model->GLCommands, int, Model->Header.NumGLCommands);

    /* Read frames */
    FSEEK(Model->Header.OffsetFrames);
    for (int i = 0; i < Model->Header.NumFrames; i++)
    {
        /* Memory allocation for vertices of this frame */
        Model->Frames[i].Vertices = (md2_vertex *)
            malloc(sizeof(md2_vertex) * Model->Header.NumVertices);

        /* Read frame data */
        FREAD(&Model->Frames[i].Scale, v3, 1);
        FREAD(&Model->Frames[i].Translate, v3, 1);
        FREAD(Model->Frames[i].Name, char, 16);
        FREAD(Model->Frames[i].Vertices, md2_vertex, Model->Header.NumVertices);
    }

    v3 *Vertices = ALLOC(v3, Model->Header.NumVertices);

    md2_frame *Frame = &Model->Frames[0];
    For(u32, i, Model->Header.NumVertices)
    {
        Vertices[i] = V3(
            (Frame->Vertices[i].At[0] * Frame->Scale[0]) + Frame->Translate[0],
            (Frame->Vertices[i].At[1] * Frame->Scale[1]) + Frame->Translate[1],
            (Frame->Vertices[i].At[2] * Frame->Scale[2]) + Frame->Translate[2]);
    }

    glGenBuffers(1, &Model->VBO);
    glBindBuffer(GL_ARRAY_BUFFER, Model->VBO);
    glBufferData(GL_ARRAY_BUFFER, Model->Header.NumVertices * sizeof(v3), Vertices, GL_STATIC_DRAW);

    glGenVertexArrays(1, &Model->VAO);
    glBindVertexArray(Model->VAO);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
    glBindVertexArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    fclose (File);
    free(Vertices);

#undef FSEEK
#undef FREAD
#undef ALLOC
}

只传递顶点数据。其中,根据我的理解 Header->NumVertices 是每帧中的顶点数。所以我采用任意帧(在本例中为第 0 帧)并将其未压缩的顶点数据读入 Vertices

现在我在一本书上读到 Quake 的 y 轴和 z 轴翻转了,但仍然没有太大变化。

这是我绘制模型的方式:

GLuint Shader = Data->Shaders.Md2Test;
ShaderUse(Shader);
ShaderSetM4(Shader, "view", &WorldToView);
ShaderSetM4(Shader, "projection", &ViewToProjection);

glBindVertexArray(DrFreak.VAO);
{
    ModelToWorld = m4_Identity;
    ShaderSetM4(Shader, "model", &ModelToWorld);
    glDrawArrays(GL_TRIANGLES, 0, DrFreak.Header.NumVertices);
}
glBindVertexArray(0);

矩阵是在 CameraUpdate 函数中计算的,我可以验证该函数是否正常工作,因为除了 MD2 模型外,场景中的其他所有内容都可以正确渲染。参见:

黄色的应该是MD2模型。

这是我的着色器(板条箱和平面的着色器几乎相同,除了只有一个 'in' 变量,位置和没有 UV):

#version 330 core
layout (location = 0) in vec3 position;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f);
}

#version 330 core
out vec4 color;
void main()
{             
    color = vec4(1, 1, 0, 1);
}

我被困在这里几天了。我进入了加载代码,我似乎得到了有效的值。我不确定是什么问题。我在做什么 wrong/missing?

感谢任何帮助。

我通过复制 vertices/uvs 从 tirangles 数据中获取它们来解决问题。我不必像许多教程那样翻转 't' UV 坐标。我切换了 y 和 z 坐标,因为它们被翻转了。

u32 NumVerts = Model->Header.NumTrigs * 3;
u32 NumUVs = NumVerts;

v3 *Vertices = ALLOC(v3, NumVerts);
v2 *UVs = ALLOC(v2, NumUVs);

md2_frame *Frame = &Model->Frames[0]; // render first frame for testing

For(u32, i, Model->Header.NumTrigs)
{
    For(u32, j, 3)
    {
        u32 VertIndex = Model->Triangles[i].Vertices[j];
        Vertices[i * 3 + j] = V3(
            (Frame->Vertices[VertIndex].At[0] * Frame->Scale[0]) + Frame->Translate[0],
            (Frame->Vertices[VertIndex].At[2] * Frame->Scale[2]) + Frame->Translate[2],
            (Frame->Vertices[VertIndex].At[1] * Frame->Scale[1]) + Frame->Translate[1]);

        u32 UVIndex = Model->Triangles[i].UVs[j];
        UVs[i * 3 + j] = V2(
            Model->UVs[UVIndex].u / (r32)Model->Header.TextureWidth,
            Model->UVs[UVIndex].v / (r32)Model->Header.TextureHeight);
    }
}

glGenVertexArrays(1, &Model->VAO);
glBindVertexArray(Model->VAO);

glGenBuffers(1, &Model->VBO);
glBindBuffer(GL_ARRAY_BUFFER, Model->VBO);
glBufferData(GL_ARRAY_BUFFER, NumVerts * sizeof(v3), Vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

u32 UVBuffer;
glGenBuffers(1, &UVBuffer);
glBindBuffer(GL_ARRAY_BUFFER, UVBuffer);
glBufferData(GL_ARRAY_BUFFER, NumUVs * sizeof(v2), UVs, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);

我可能会使用索引数组和 glDrawElements。但出于我的测试目的 glDrawArrays 就足够了。如果有人知道做这一切的更好方法,请随时发表评论。

还有 Dr Freak chillin'