I am trying to render an obj model with texture. Here is what I do:
- Get the 3d model
model
and the corresponding view matrixview_mat
and projection matrixproj_mat
from the image. - 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. - Use the uv coordinates to render the 3d model.
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();
}
}