简体   繁体   English

OpenGL 3D模型纹理贴图

[英]OpenGL 3D model texture mapping

I am trying to render an obj model with texture. 我正在尝试使用纹理渲染obj模型。 Here is what I do: 这是我的工作:

  1. Get the 3d model model and the corresponding view matrix view_mat and projection matrix proj_mat from the image. 从图像中获取3d模型model以及相应的视图矩阵view_mat和投影矩阵proj_mat
  2. Project the 3d model to the image using proj_mat * view_mat * model , in this way I can get uv coordinates in the image for every vertex in 3d model. 使用proj_mat * view_mat * model将3d模型proj_mat * view_mat * model到图像上,这样我就可以为3d模型中的每个顶点获取图像中的uv坐标。
  3. Use the uv coordinates to render the 3d model. 使用uv坐标渲染3d模型。

Here is what I get (on the left is the render result), I think I should get the main steps done right, as the overall texture looks in the right position. 就是我得到的结果(左边是渲染结果),我认为我应该正确完成主要步骤,因为整体纹理看起来在正确的位置。 But it looks like that triangles are not in the rotation mode. 但是看起来三角形不处于旋转模式。

Here is the part of the code I consider that is related to the texture mapping. 这是我认为与纹理映射有关的代码部分。

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 window\n");
        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();
    }
}

You have to set the current texture coordinate ( glTexCoord ) before you specify a vertex ( glVertex ), because the current color, normal, texture coordinates, and fog coordinate are associated with the vertex when glVertex is called. 指定顶点( glVertex之前,必须设置当前纹理坐标( glTexCoord ),因为调用glVertex时,当前颜色,法线,纹理坐标和雾化坐标都与该顶点相关联。

This means you have to swap glVertex3f and glTexCoord2f : 这意味着您必须交换glVertex3fglTexCoord2f

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

Otherwise you would set the texture coordinate which is associated to the next vertex position. 否则,您将设置与下一个顶点位置关联的纹理坐标。


See OpenGL 2.0 API Specification, 2.6 Begin/End Paradigm, page 13 : 请参阅OpenGL 2.0 API规范2.6 Begin / End范例(第13页)

Each vertex is specified with two, three, or four coordinates. 每个顶点都有两个,三个或四个坐标。 In addition, a current normal, multiple current texture coordinate sets, multiple current generic vertex attributes, current color, current secondary color, and current fog coordinate may be used in processing each vertex . 另外,当前法线,多个当前纹理坐标集,多个当前通用顶点属性,当前颜色,当前第二颜色和当前雾坐标可用于处理每个顶点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM