Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

homework2, draw opencv 3d logo in motion with opengl compat, support shade flat/smooth and smoothing group #38

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions assets/opencvpart.obj
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ vt 0.000000 0.000000
vt 0.000000 0.000000
vt 0.000000 0.000000
s 0
#group 0
f 47/47/1 46/46/1 100/100/1 101/101/1
f 21/21/1 20/20/1 74/74/1 75/75/1
f 48/48/1 47/47/1 101/101/1 102/102/1
Expand Down Expand Up @@ -555,6 +556,7 @@ f 45/45/1 44/44/1 98/98/1 99/99/1
f 19/19/1 18/18/1 72/72/1 73/73/1
f 46/46/1 45/45/1 99/99/1 100/100/1
f 20/20/1 19/19/1 73/73/1 74/74/1
#group 1
f 155/155/2 209/209/2 208/208/2 154/154/2
f 129/129/2 183/183/2 182/182/2 128/128/2
f 156/156/2 210/210/2 209/209/2 155/155/2
Expand Down Expand Up @@ -608,6 +610,7 @@ f 153/153/2 207/207/2 206/206/2 152/152/2
f 127/127/2 181/181/2 180/180/2 126/126/2
f 154/154/2 208/208/2 207/207/2 153/153/2
f 128/128/2 182/182/2 181/181/2 127/127/2
#group 2
f 2/2/3 3/3/3 111/111/3 110/110/3
f 3/3/4 4/4/4 112/112/4 111/111/4
f 4/4/5 5/5/5 113/113/5 112/112/5
Expand Down Expand Up @@ -661,6 +664,7 @@ f 51/51/52 52/52/52 160/160/52 159/159/52
f 52/52/53 53/53/53 161/161/53 160/160/53
f 53/53/54 54/54/54 162/162/54 161/161/54
f 54/54/55 1/1/55 109/109/55 162/162/55
#group 3
f 57/57/35 56/56/35 164/164/35 165/165/35
f 58/58/36 57/57/36 165/165/36 166/166/36
f 59/59/37 58/58/37 166/166/37 167/167/37
Expand Down Expand Up @@ -714,5 +718,7 @@ f 106/106/20 105/105/20 213/213/20 214/214/20
f 107/107/21 106/106/21 214/214/21 215/215/21
f 108/108/22 107/107/22 215/215/22 216/216/22
f 55/55/23 108/108/23 216/216/23 163/163/23
#group 4
f 1/1/67 55/55/67 163/163/67 109/109/67
#group 5
f 56/56/68 2/2/68 110/110/68 164/164/68
5 changes: 4 additions & 1 deletion include/OBJ.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
#include <glm/ext.hpp>
#include <vector>
#include <string>
#include <unordered_map>

struct OBJ {
std::vector<glm::vec3> vertices;
std::vector<glm::uvec3> faces;
std::unordered_map<unsigned int, std::vector<unsigned int>> smoothing_groups;

void load_obj(std::string path);
void load_obj(std::string path, bool grouped = false);
void draw_obj();
void draw_obj_smooth();
};
84 changes: 69 additions & 15 deletions src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
#include <glm/ext.hpp>
#include "OBJ.hpp"

#include <vector>

struct Game::Private { // P-IMPL pattern
glm::mat4x4 viewMat;
glm::mat4x4 projMat;

OBJ monkey;
std::vector<OBJ> ocvLogo;
};

Game::Game() : m_private(std::make_unique<Private>()) {}
Game::Game() : m_private(std::make_unique<Private>()), m_window(nullptr) {}

Game::~Game() = default;

Expand All @@ -31,11 +33,49 @@ void Game::set_window(GLFWwindow *window) {
#endif

void Game::initialize() {
/* m_private->monkey.load_obj(OPENGLTUTOR_HOME "assets/opencvpart.obj"); */
m_private->monkey.load_obj(OPENGLTUTOR_HOME "assets/monkey.obj");
/* m_private->monkey.load_obj(OPENGLTUTOR_HOME "assets/cube.obj"); */
OBJ ocvpart;
ocvpart.load_obj(OPENGLTUTOR_HOME "assets/opencvpart.obj", true);

for (size_t i = 0; i < 3; ++i) {
m_private->ocvLogo.push_back(ocvpart);
}
constexpr float short_side = 0.65f;
glm::vec3 tri_sides = {short_side, 2 * short_side, short_side * sqrtf(3)};

auto C0 = glm::vec3(0.0f, tri_sides.y, 0.0f);
auto C1 = glm::vec3(-tri_sides.z, -tri_sides.x, 0.0f);
auto C2 = glm::vec3(tri_sides.z, -tri_sides.x, 0.0f);

std::vector<glm::mat4x4> cvLogoModel;

auto model = glm::mat4x4(1.0f);
model = glm::translate(model, C0);
model = glm::rotate(model, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(150.0f), glm::vec3(0.0f, 1.0f, 0.0f));
cvLogoModel.push_back(model);

model = glm::mat4x4(1.0f);
model = glm::translate(model, C1);
model = glm::rotate(model, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f));
cvLogoModel.push_back(model);

model = glm::mat4x4(1.0f);
model = glm::translate(model, C2);
model = glm::rotate(model, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
model = glm::rotate(model, glm::radians(-30.0f), glm::vec3(0.0f, 1.0f, 0.0f));
cvLogoModel.push_back(model);

for (size_t i = 0; i < m_private->ocvLogo.size(); ++i) {
auto& ocvPart = m_private->ocvLogo.at(i);
auto& ocvPartModel = cvLogoModel.at(i);
for (auto& vert : ocvPart.vertices) {
vert = ocvPartModel * glm::vec4(vert, 1.0f);
}
}

CHECK_GL(glEnable(GL_DEPTH_TEST));
CHECK_GL(glDisable(GL_MULTISAMPLE));
CHECK_GL(glEnable(GL_MULTISAMPLE));
CHECK_GL(glEnable(GL_BLEND));
CHECK_GL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
CHECK_GL(glEnable(GL_LIGHTING));
Expand All @@ -44,6 +84,7 @@ void Game::initialize() {
CHECK_GL(glEnable(GL_CULL_FACE));
CHECK_GL(glCullFace(GL_BACK));
CHECK_GL(glFrontFace(GL_CCW));
CHECK_GL(glShadeModel(GL_SMOOTH));
}

void Game::render() {
Expand All @@ -52,24 +93,37 @@ void Game::render() {
CHECK_GL(glViewport(0, 0, width, height));

CHECK_GL(glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

auto projection = m_inputCtl.get_projection_matrix();

CHECK_GL(glMatrixMode(GL_PROJECTION));
CHECK_GL(glLoadMatrixf(glm::value_ptr(projection)));

auto view = m_inputCtl.get_view_matrix();

glm::mat4x4 model(1.0f);

static float motionAngle = 0.0f;
static constexpr glm::vec3 motionAxis = { 0.0f, 1.0f, 0.0f };
static constexpr float motionDelta = 1.2f;

static float angle = 0.0f;
model = glm::rotate(model, glm::radians(angle), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::translate(model, glm::vec3(0.0f, 0.12f * glm::sin(glm::radians(angle) * 2.718f), 0.0f));
angle += 0.5f;

CHECK_GL(glMatrixMode(GL_MODELVIEW));

model = glm::rotate(glm::mat4(1.0f), glm::radians(motionAngle), motionAxis);
CHECK_GL(glLoadMatrixf(glm::value_ptr(view * model)));
glColor3f(1.0f, 0.0f, 0.0f);
m_private->ocvLogo.at(0).draw_obj_smooth();

model = glm::rotate(glm::mat4(1.0f), glm::radians(motionAngle), motionAxis);
CHECK_GL(glLoadMatrixf(glm::value_ptr(view * model)));
glColor3f(0.0f, 1.0f, 0.0f);
m_private->ocvLogo.at(1).draw_obj_smooth();

model = glm::rotate(glm::mat4(1.0f), glm::radians(motionAngle), motionAxis);
CHECK_GL(glLoadMatrixf(glm::value_ptr(view * model)));
glColor3f(0.0f, 0.0f, 1.0f);
m_private->ocvLogo.at(2).draw_obj_smooth();

glColor3f(0.9f, 0.6f, 0.1f);
m_private->monkey.draw_obj();
motionAngle += motionDelta;
}
2 changes: 1 addition & 1 deletion src/InputCtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static auto glfw_input_callback(FpFn fpFn) {

struct CameraState {
/* glm::mat4x4 transformation; */
glm::vec3 eye = {0, 0, 5};
glm::vec3 eye = {0, 0, 10};
glm::vec3 lookat = {0, 0, 0};
glm::vec3 up_vector = {0, 1, 0};
glm::vec3 keep_up_axis = {0, 1, 0};
Expand Down
87 changes: 79 additions & 8 deletions src/OBJ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
#include <fstream>
#include <sstream>

void OBJ::load_obj(std::string path) {
void OBJ::load_obj(std::string path, bool grouped) {
std::ifstream file(path);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << path << '\n';
return;
}

std::string line;
unsigned int current_group = 0;

while (std::getline(file, line)) {
if (line.substr(0, 2) == "v ") {
std::istringstream s(line.substr(2));
Expand All @@ -33,8 +35,15 @@ void OBJ::load_obj(std::string path) {
for (size_t i = 2; i < indices.size(); i++) {
glm::uvec3 face = glm::uvec3(indices[0], indices[i - 1], indices[i]);
faces.push_back(face);

smoothing_groups[current_group].push_back(faces.size() - 1);
}
}
} else if (line.substr(0, 7) == "#group ") {
std::istringstream s(line.substr(7));
unsigned int group;
s >> group;
if (grouped) current_group = group;
}
}

file.close();
Expand All @@ -52,13 +61,26 @@ static glm::vec3 compute_normal(glm::vec3 a, glm::vec3 b, glm::vec3 c) {
return glm::normalize(glm::cross(ab, ac));
}

void OBJ::draw_obj() {
glBegin(GL_TRIANGLES);
static glm::vec3 compute_contrib_normal(glm::vec3 v0, glm::vec3 v1, glm::vec3 v2, uint32_t vert) {
std::vector<glm::vec3> face = {v0, v1, v2};
auto const& a = face.at(vert);
auto const& b = face.at((vert + 1) % 3);
auto const& c = face.at((vert + 2) % 3);

glm::vec3 ab = b - a;
glm::vec3 ac = c - a;
glm::vec3 norm = glm::cross(ab, ac);
float contrib_w = asinf(static_cast<float>(norm.length()) / (ab.length() * ac.length()));

for (auto face : faces) {
auto const &a = vertices.at(face[0]);
auto const &b = vertices.at(face[1]);
auto const &c = vertices.at(face[2]);
return glm::normalize(norm) * contrib_w;
}

static void object_draw_flat_pass(OBJ const& obj) {
glBegin(GL_TRIANGLES);
for (auto face : obj.faces) {
auto const& a = obj.vertices.at(face[0]);
auto const& b = obj.vertices.at(face[1]);
auto const& c = obj.vertices.at(face[2]);

glm::vec3 norm = compute_normal(a, b, c);
glNormal3fv(glm::value_ptr(norm));
Expand All @@ -67,6 +89,55 @@ void OBJ::draw_obj() {
glVertex3fv(glm::value_ptr(b));
glVertex3fv(glm::value_ptr(c));
}
CHECK_GL(glEnd());
}

static void normal_compute_pass(OBJ const& obj, std::vector<unsigned int> const& face_indices, std::vector<glm::vec3>& vertex_normal_buffer) {
for (auto const& index : face_indices) {
auto const& face = obj.faces.at(index);
auto const& a = obj.vertices.at(face[0]);
auto const& b = obj.vertices.at(face[1]);
auto const& c = obj.vertices.at(face[2]);

vertex_normal_buffer[face[0]] += compute_contrib_normal(a, b, c, 0);
vertex_normal_buffer[face[1]] += compute_contrib_normal(a, b, c, 1);
vertex_normal_buffer[face[2]] += compute_contrib_normal(a, b, c, 2);
}
for (auto& vn : vertex_normal_buffer) {
vn = glm::normalize(vn);
}
}

static void object_draw_smooth_pass(OBJ const& obj, std::vector<unsigned int> const& face_indices, std::vector<glm::vec3> const& vertex_normal_buffer) {
glBegin(GL_TRIANGLES);
for (auto const& index : face_indices) {
auto const& face = obj.faces.at(index);
auto const& a = obj.vertices.at(face[0]);
auto const& b = obj.vertices.at(face[1]);
auto const& c = obj.vertices.at(face[2]);

auto const& n0 = vertex_normal_buffer.at(face[0]);
auto const& n1 = vertex_normal_buffer.at(face[1]);
auto const& n2 = vertex_normal_buffer.at(face[2]);

glNormal3fv(glm::value_ptr(n0));
glVertex3fv(glm::value_ptr(a));
glNormal3fv(glm::value_ptr(n1));
glVertex3fv(glm::value_ptr(b));
glNormal3fv(glm::value_ptr(n2));
glVertex3fv(glm::value_ptr(c));
}
CHECK_GL(glEnd());
}

void OBJ::draw_obj() {
object_draw_flat_pass(*this);
}

void OBJ::draw_obj_smooth() {
for (auto const& [i, group] : smoothing_groups) {
std::vector<glm::vec3> vert_norm_buffer(vertices.size(), glm::vec3(0.0f));
normal_compute_pass(*this, group, vert_norm_buffer);
object_draw_smooth_pass(*this, group, vert_norm_buffer);
}
}
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ int main() {
}

// Create main window
constexpr char title[] = "Example";
constexpr char title[] = "Homework2: OpenCV 3D Logo";
GLFWwindow *window = glfwCreateWindow(1024, 768, title, NULL, NULL);

// Test if window creation succeed
Expand Down