OpenGL 3D模型纹理映射

时间:2018-02-03 14:16:34

标签: opengl texture-mapping

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

  1. 从图片中获取三维模型model和相应的视图矩阵view_mat以及投影矩阵proj_mat
  2. 使用proj_mat * view_mat * model将3d模型投影到图像,这样我就可以在图像中为3d模型中的每个顶点获取uv坐标。
  3. 使用uv坐标渲染3d模型。
  4. Here是我得到的(左边是渲染结果),我认为我应该正确完成主要步骤,因为整体纹理看起来正确。但看起来三角形不处于旋转模式。

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

    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();
        }
    }
    

1 个答案:

答案 0 :(得分:1)

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

这意味着您必须交换glVertex3fglTexCoord2f

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

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


OpenGL 2.0 API Specification, 2.6 Begin/End Paradigm, page 13

  

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