OpenGL 3D 模型纹理映射



我正在尝试渲染带有纹理的obj模型。这是我的工作:

  1. 从图像中获取 3D 模型model以及相应的视图矩阵view_mat和投影矩阵proj_mat
  2. 使用proj_mat * view_mat * model将3d模型投影到图像上,这样我可以在图像中获取3d模型中每个顶点的uv坐标。
  3. 使用 UV 坐标渲染 3D 模型。

这是我得到的(左边是渲染结果(,我认为我应该正确完成主要步骤,因为整体纹理看起来在正确的位置。但看起来三角形不在旋转模式下。

这是我认为与纹理映射相关的代码部分。

int main() {
    Tracker tracker;
    tracker.set_image("clooney.jpg");
    Viewer viewer(tracker.get_width(), tracker.get_height());
    while (tracker.track()) {
        Model* model = tracker.get_model();
        glm::mat4x4 proj_mat = tracker.get_proj_mat();
        proj_mat = glm::transpose(proj_mat);
        glm::mat4x4 view_mat = tracker.get_view_mat();
        view_mat = glm::transpose(view_mat);
        // render 3d shape
        viewer.set_model(model);
        viewer.draw(view_mat, proj_mat);
        waitKey(0);
    }
    return 0;
}
// initialization of the render part
Viewer::Viewer(int width, int height) {
    glfwInit();
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    m_window = glfwCreateWindow(width, height, "demo", NULL, NULL);
    if (!m_window)
    {
        fprintf(stderr, "Failed to open GLFW windown");
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    glfwMakeContextCurrent(m_window);
    glfwGetWindowSize(m_window, &m_width, &m_height);
    glfwSetFramebufferSizeCallback(m_window, reshape_callback);
    gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
    glfwSwapInterval(1);
    config();
}
void Viewer::config() {
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    glDisable(GL_CULL_FACE);
    glShadeModel(GL_FLAT);
}
// entry of the drawing function
void Viewer::draw(glm::mat4x4 view_mat, glm::mat4x4 proj_mat) {
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    proj_mat = glm::transpose(proj_mat);
    glLoadMatrixf(&proj_mat[0][0]);
    glMatrixMode(GL_MODELVIEW);
    view_mat = glm::transpose(view_mat);
    glLoadMatrixf(&view_mat[0][0]);
    // m_pmodel is an instance of Model Class
    // set texture
    m_pmodel->set_texture(m_image);
    // set model uvs
    m_pmodel->set_uvs(view_mat, proj_mat);
    m_pmodel->draw(); 
    glfwSwapBuffers(m_window);
    glfwPollEvents();
}
// set the texture for the model from the image
void Model::set_texture(cv::Mat img) {
    glGenTextures(1, &m_texture);
    glBindTexture(GL_TEXTURE_2D, m_texture);
    glTexImage2D(GL_TEXTURE_2D, 0, 3, img.cols, img.rows, 0, GL_BGR, GL_UNSIGNED_BYTE, img.data);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glGenerateMipmap(GL_TEXTURE_2D);
    glEnable(GL_TEXTURE_2D);
}
// specify correspondence between image and the model
void Model::set_uvs(glm::mat4x4 view_mat, glm::mat4x4 proj_mat) {
    for (int i = 0; i < m_uvs.size(); i++) {
        glm::vec4 clip_coord = proj_mat * view_mat * glm::vec4(m_vertices[i], 1);
        float w = clip_coord.w;
        glm::vec3 normal_coord = glm::vec3(clip_coord.x, clip_coord.y, clip_coord.z) / w;
        m_uvs[i] = glm::vec2(normal_coord.x * 0.5f + 0.5f, normal_coord.y * 0.5f + 0.5f);
    }
}
// render the 3d model
void Model::draw() const {
    glBindTexture(GL_TEXTURE_2D, m_texture);
    for (unsigned long i = 0; i < m_faces.size(); ++i) {
        glm::ivec3 face = this->m_faces[i];
        glBegin(GL_TRIANGLES);
        for (int j = 0; j < 3; j++) {
            glm::vec3 v = this->m_vertices[face[j]];
            glm::vec2 uv = this->m_uvs[face[j]];
            glVertex3f(v.x, v.y, v.z);
            glTexCoord2f(1 - uv.x,1 - uv.y);
        }
        glEnd();
    }
}

在指定顶点 ( glVertex ( 之前,必须设置当前纹理坐标 ( glTexCoord (,因为在调用 glVertex 时,当前颜色、法线、纹理坐标和雾坐标与顶点相关联。

这意味着您必须交换glVertex3fglTexCoord2f

glTexCoord2f(1 - uv.x,1 - uv.y);
glVertex3f(v.x, v.y, v.z);

否则,您将设置与下一个顶点位置关联的纹理坐标。


请参阅 OpenGL 2.0 API 规范,2.6 开始/结束范式,第 13 页:

每个顶点指定两个、三个或四个坐标。此外在处理每个顶点时,可以使用当前法线、多个当前纹理坐标集、多个当前通用顶点属性、当前颜色、当前辅助颜色和当前雾坐标

最新更新