Question
Write an OpenGL program that display a rotating bunny. 1) Initially place a bunny 5 units along the x-axis at (5, 0, 0) of world
Write an OpenGL program that display a rotating bunny.
1) Initially place a bunny 5 units along the x-axis at (5, 0, 0) of world coordinate system. This is already implemented in the provided starting code.
2) Draw a ground plane and xyz-axis of world coordinate system. Draw xyz axis from an arrow object. This is already implemented in the provided starting code.
3) Rotate the bunny around the global y-axis of world coordinate system (WCS) and at the same time rotate around its own x-axis of local coordinate system (LCS).
For the rotating bunny, do the following transformation in order:
a. rotate the bunny around its own x-axis of local coordinate system by 'a' degree; (grade: 4 points)
b. then rotate the bunny by 'b' degrees around the global y-axis of world coordinate system. (grade: 3 points)
Note that the rotation around its own x-axis will not change the center position of bunny. The center position of bunny is changed when it rotates around the global y-axis. Some implementation hints are given below.
4) The program should have user-interaction controls to allow users to interactively increase or decrease a and b. The controls can be buttons, checkboxes, mouse clicks, mouse motion, etc. as long as it is easy to use. (grade: 2 points)
5) Have a Reset button that can reset the bunny to the initial state, a to 0 and b to 0. (grade: 1 point)
A starting code (c++) animating a bunny has been provided. GUI is implemented by Nanogui and GLFW.
To build the code, the following libraries are needed: GLEW, GLFW, Nanogui.
Hints:
1. Every bunny transformation can be implemented by modifying the ModelView matrix in the OpenGL code. The ModelView matrix is used to transform the vertex coordinates from world coordinate system (WCS) to camera coordinate system (CCS).
2. How to rotate the bunny around its own x-axis of local coordinate system (LCS)? Here are some hints that you can consider:
a. Track the direction of the bunnys x-axis of LCS and represent it in WCS.
b. Construct a rotation matrix, with the rotation axis to be the bunnys x-axis and the rotation angle to be 'a' degree. Rodrigues rotation formula gives the form of this matrix.
c. The rotation pivot point is the origin of bunnys LCS, but not the origin of WCS. Think about how to make the bunny rotate around its own origin.
main.cpp
#include "Renderer.h"
int main() {
Renderer m_renderer;
m_renderer.run();
return EXIT_SUCCESS;
}
Animation.h
#pragma once
#include
#include
#include
#include
class Animation
{
public:
Animation();
~Animation();
void init();
void update(float delta_time);
void reset();
glm::mat4 get_model_mat() { return m_model_mat; };
private:
glm::mat4 m_model_mat;
};
Camera.h
#pragma once
#include
#include
#include
#include
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT,
UP,
DOWN,
ROTATE_X_UP,
ROTATE_X_DOWN,
ROTATE_Y_UP,
ROTATE_Y_DOWN,
ROTATE_Z_UP,
ROTATE_Z_DOWN,
};
class Camera {
public:
// Camera view parameters
glm::vec3 ori_position;
glm::vec3 ori_front;
glm::vec3 ori_up;
glm::vec3 ori_right;
glm::vec3 position;
glm::vec3 front;
glm::vec3 up;
glm::vec3 right;
// Camera projection parameters
float ori_zoom;
float zoom;
float near;
float far;
unsigned int width;
unsigned int height;
// Camera projection matrix: used for projection
glm::mat4 proj_mat;
// Camera view matrix: used for changing camera rotation and position
glm::mat4 view_mat;
// Camera parameter initialization
Camera(
glm::vec3 position_ = glm::vec3(0, 1, 10),
glm::vec3 front_ = glm::vec3(0, 0, -1),
glm::vec3 up_ = glm::vec3(0, 1, 0),
glm::vec3 right_ = glm::vec3(1, 0, 0),
float zoom_ = 45.0,
float near_ = 0.1,
float far_ = 100,
unsigned int width_ = 1600,
unsigned int height_ = 900
)
{
this->ori_position = position_;
this->ori_front = front_;
this->ori_up = up_;
this->ori_right = right_;
this->ori_zoom = zoom_;
this->near = near_;
this->far = far_;
this->width = width_;
this->height = height_;
}
void init() {
reset();
};
void reset() {
this->position = ori_position;
this->front = ori_front;
this->up = ori_up;
this->right = ori_right;
this->zoom = ori_zoom;
}
void process_keyboard(Camera_Movement direction, GLfloat delta_time)
{
GLfloat velocity = delta_time;
if (direction == FORWARD)
this->position += this->front * velocity;
if (direction == BACKWARD)
this->position -= this->front * velocity;
if (direction == LEFT)
this->position -= this->right * velocity;
if (direction == RIGHT)
this->position += this->right * velocity;
if (direction == UP)
this->position += this->up * velocity;
if (direction == DOWN)
this->position -= this->up * velocity;
if (direction == ROTATE_X_UP)
rotate_x(velocity);
if (direction == ROTATE_X_DOWN)
rotate_x(-velocity);
if (direction == ROTATE_Y_UP)
rotate_y(velocity);
if (direction == ROTATE_Y_DOWN)
rotate_y(-velocity);
if (direction == ROTATE_Z_UP)
rotate_z(velocity);
if (direction == ROTATE_Z_DOWN)
rotate_z(-velocity);
}
// Rotate specific angle along local camera system(LCS)
void rotate_x(GLfloat angle)
{
glm::vec3 up = this->up;
glm::mat4 rotation_mat(1);
rotation_mat = glm::rotate(rotation_mat, angle, this->right);
this->up = glm::normalize(glm::vec3(rotation_mat * glm::vec4(up, 1.0)));
this->front = glm::normalize(glm::cross(this->up, this->right));
}
void rotate_y(GLfloat angle)
{
glm::vec3 front = this->front;
glm::mat4 rotation_mat(1);
rotation_mat = glm::rotate(rotation_mat, angle, this->up);
this->front = glm::normalize(glm::vec3(rotation_mat * glm::vec4(front, 1.0)));
this->right = glm::normalize(glm::cross(this->front, this->up));
}
void rotate_z(GLfloat angle)
{
glm::vec3 right = this->right;
glm::mat4 rotation_mat(1);
rotation_mat = glm::rotate(rotation_mat, angle, this->front);
this->right = glm::normalize(glm::vec3(rotation_mat * glm::vec4(right, 1.0)));
this->up = glm::normalize(glm::cross(this->right, this->front));
}
// Get camera view matrix
glm::mat4 get_view_mat()
{
this->view_mat = glm::lookAt(this->position, this->position + this->front, this->up);
return this->view_mat;
}
// Get camera projection matrix
glm::mat4 get_projection_mat()
{
this->proj_mat = glm::perspective(this->zoom, (GLfloat)this->width / (GLfloat)this->height, this->near, this->far);
return this->proj_mat;
}
};
Lighting.h
#pragma once
#include
#include
#include
class Lighting {
struct Direction_Light {
bool status;
glm::vec3 direction;
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
};
struct Point_Light {
bool status;
glm::vec3 position;
float constant;
float linear;
float quadratic;
glm::vec4 ambient;
glm::vec4 diffuse;
glm::vec4 specular;
};
public:
Direction_Light direction_light;
Point_Light point_light;
Lighting() {
}
~Lighting() {}
void init()
{
direction_light.status = true;
direction_light.direction = glm::vec3(0.0f, -1.0f, 0.0f);
direction_light.ambient = glm::vec4(0.1f, 0.1f, 0.1f, 1.0f);
direction_light.diffuse = glm::vec4(0.3f, 0.3f, 0.3f, 1.0f);
direction_light.specular = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
point_light.status = true;
point_light.position = glm::vec3(1.2f, 1.0f, 2.0f);
point_light.ambient = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
point_light.diffuse = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
point_light.specular = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
point_light.constant = 1.0f;
point_light.linear = 0.09f;
point_light.quadratic = 0.032f;
};
};
Object.h
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
class Object
{
public:
struct Vertex {
// Position
glm::vec3 Position;
// Normal
glm::vec3 Normal;
// TexCoords
glm::vec2 TexCoords;
};
struct Vertex_Index {
int pos_idx;
int normal_idx;
int texcoord_idx;
};
struct Face_Index {
Vertex_Index vertex[3];
};
// veo and vao vector
std::vector
std::vector
// obj original data vector
std::vector
std::vector
std::vector
// obj face index vector
std::vector
glm::vec3 obj_center;
glm::vec4 obj_color = glm::vec4(0.7, 0.7, 0.7, 1.0);
GLfloat shininess = 32.0f;
std::string m_obj_path;
std::string obj_name;
GLuint vao, vbo;
public:
void load_obj(std::string obj_path)
{
int path_str_length = obj_path.size();
std::string suffix = obj_path.substr(path_str_length - 3, path_str_length);
if (suffix == "obj") {
this->vao_vertices.clear();
this->veo_indices.clear();
this->indexed_faces.clear();
this->ori_positions.clear();
this->ori_normals.clear();
this->ori_texcoords.clear();
std::ifstream ifs;
// Store original data vector
try {
ifs.open(obj_path);
std::string one_line;
while (getline(ifs, one_line)) {
std::stringstream ss(one_line);
std::string type;
ss >> type;
if (type == "v") {
glm::vec3 vert_pos;
ss >> vert_pos[0] >> vert_pos[1] >> vert_pos[2];
this->ori_positions.push_back(vert_pos);
}
else if (type == "vt") {
glm::vec2 tex_coord;
ss >> tex_coord[0] >> tex_coord[1];
this->ori_texcoords.push_back(tex_coord);
}
else if (type == "vn") {
glm::vec3 vert_norm;
ss >> vert_norm[0] >> vert_norm[1] >> vert_norm[2];
this->ori_normals.push_back(vert_norm);
}
else if (type == "f") {
Face_Index face_idx;
// Here we only accept face number 3
for (int i = 0; i < 3; i++) {
std::string s_vertex;
ss >> s_vertex;
int pos_idx = -1;
int tex_idx = -1;
int norm_idx = -1;
sscanf(s_vertex.c_str(), "%d/%d/%d", &pos_idx, &tex_idx, &norm_idx);
// We have to use index -1 because the obj index starts at 1
// Incorrect input will be set as -1
face_idx.vertex[i].pos_idx = pos_idx > 0 ? pos_idx - 1 : -1;
face_idx.vertex[i].texcoord_idx = tex_idx > 0 ? tex_idx - 1 : -1;
face_idx.vertex[i].normal_idx = norm_idx > 0 ? norm_idx - 1 : -1;
}
indexed_faces.push_back(face_idx);
}
}
}
catch (const std::exception&) {
std::cout << "Error: Obj file cannot be read ";
}
// Retrieve data from index and assign to vao and veo
for (int i = 0; i < indexed_faces.size(); i++) {
Face_Index cur_idx_face = indexed_faces[i];
// If no normal: recalculate for them
glm::vec3 v0 = ori_positions[cur_idx_face.vertex[0].pos_idx];
glm::vec3 v1 = ori_positions[cur_idx_face.vertex[1].pos_idx];
glm::vec3 v2 = ori_positions[cur_idx_face.vertex[2].pos_idx];
glm::vec3 new_normal = glm::cross(v1 - v0, v2 - v0);
for (int j = 0; j < 3; j++) {
Vertex cur_vertex;
Vertex_Index cur_idx_vertex = cur_idx_face.vertex[j];
if (cur_idx_vertex.pos_idx >= 0) {
cur_vertex.Position = ori_positions[cur_idx_vertex.pos_idx];
}
if (cur_idx_vertex.normal_idx >= 0) {
cur_vertex.Normal = ori_normals[cur_idx_vertex.normal_idx];
}
else {
cur_vertex.Normal = new_normal;
}
if (cur_idx_vertex.texcoord_idx >= 0) {
cur_vertex.TexCoords = ori_texcoords[cur_idx_vertex.texcoord_idx];
}
vao_vertices.push_back(cur_vertex);
veo_indices.push_back(i * 3 + j);
}
}
}
};
void calculate_center()
{
glm::vec3 max_bound(INT_MIN);
glm::vec3 min_bound(INT_MAX);
for (auto vertex : this->vao_vertices) {
max_bound[0] = std::max(vertex.Position[0], max_bound[0]);
max_bound[1] = std::max(vertex.Position[1], max_bound[1]);
max_bound[2] = std::max(vertex.Position[2], max_bound[2]);
min_bound[0] = std::min(vertex.Position[0], min_bound[0]);
min_bound[1] = std::min(vertex.Position[1], min_bound[1]);
min_bound[2] = std::min(vertex.Position[2], min_bound[2]);
}
this->obj_center = (max_bound + min_bound) * 0.5f;
};
Object(std::string obj_path) {
this->m_obj_path = obj_path;
load_obj(this->m_obj_path);
calculate_center();
};
~Object() {};
};
Renderer.h
#pragma once
#include
#define GLEW_STATIC
#include
#include
#include
#include
#include
#include
#include
#include "Shader.h"
#include "Camera.h"
#include "Object.h"
#include "Lighting.h"
#include "Animation.h"
class Renderer
{
public:
GLFWwindow * m_window;
static Camera* m_camera;
static Lighting* m_lightings;
static Animation* m_animation;
static nanogui::Screen* m_nanogui_screen;
std::vector
glm::vec4 background_color = glm::vec4(0.1, 0.1, 0.1, 0.1);
bool is_scean_reset = true;
std::string model_name;
GLfloat delta_time = 0.0;
GLfloat last_frame = 0.0;
static bool keys[1024];
public:
Renderer();
~Renderer();
void nanogui_init(GLFWwindow* window);
void init();
void display(GLFWwindow* window);
void run();
void load_models();
void draw_scene(Shader& shader);
void camera_move();
void draw_object(Shader& shader, Object& object);
void bind_vaovbo(Object &cur_obj);
void setup_uniform_values(Shader& shader);
void scean_reset();
};
Shader.h
#ifndef SHADER_H
#define SHADER_H
#include
#include
#include
#include
#include
class Shader {
public:
GLuint program;
Shader(const GLchar* vertex_shader_path, const GLchar* fragment_shader_path, const GLchar* geometry_shader_path = nullptr) {
std::string vertex_code;
std::string fragment_code;
std::string geometry_code;
std::ifstream v_shader_file;
std::ifstream f_shader_file;
std::ifstream g_shader_file;
v_shader_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
f_shader_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
g_shader_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
v_shader_file.open(vertex_shader_path);
f_shader_file.open(fragment_shader_path);
std::stringstream v_shader_stream, f_shader_stream;
v_shader_stream << v_shader_file.rdbuf();
f_shader_stream << f_shader_file.rdbuf();
v_shader_file.close();
f_shader_file.close();
vertex_code = v_shader_stream.str();
fragment_code = f_shader_stream.str();
if (geometry_shader_path != nullptr) {
g_shader_file.open(geometry_shader_path);
std::stringstream g_shader_stream;
g_shader_stream << g_shader_file.rdbuf();
g_shader_file.close();
geometry_code = g_shader_stream.str();
}
}
catch (const std::exception&) {
std::cout << "Error: Shader not read ";
}
const char* v_shader_code = vertex_code.c_str();
const char* f_shader_code = fragment_code.c_str();
GLuint vertex, fragement, geometry;
GLchar info_log[512];
vertex = glCreateShader(GL_VERTEX_SHADER);
fragement = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertex, 1, &v_shader_code, NULL);
glShaderSource(fragement, 1, &f_shader_code, NULL);
glCompileShader(vertex);
glCompileShader(fragement);
check_compile_error(vertex, "VERTEX");
check_compile_error(fragement, "FRAGMENT");
if (geometry_shader_path != nullptr) {
const char* g_shader_code = geometry_code.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &g_shader_code, NULL);
glCompileShader(geometry);
check_compile_error(geometry, "GEOMETRY");
}
this->program = glCreateProgram();
glAttachShader(this->program, vertex);
glAttachShader(this->program, fragement);
if (geometry_shader_path != nullptr) {
glAttachShader(this->program, geometry);
}
glLinkProgram(this->program);
check_compile_error(this->program, "PROGRAM");
glDeleteShader(vertex);
glDeleteShader(fragement);
if (geometry_shader_path != nullptr) {
glDeleteShader(geometry);
}
}
void use() { glUseProgram(this->program); }
private:
void check_compile_error(GLuint shader, std::string type) {
GLint success;
GLchar info_log[1024];
if (type == "PROGRAM") {
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, info_log);
std::cout << "| Error:: PROGRAM-LINKING-ERROR of type: " << type << "| " << info_log << " | -- --------------------------------------------------- -- | ";
}
}
else if (type == "VERTEX" || type == "FRAGMENT" || type == "GEOMETRY") {
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, info_log);
std::cout << "| Error:: SHADER-COMPILATION-ERROR of type: " << type << "| " << info_log << " | -- --------------------------------------------------- -- | ";
}
}
else {
std::cout << "Error: incorrect input type ";
}
}
};
#endif
Animation.cpp
#include "Animation.h"
Animation::Animation()
{
this->m_model_mat = glm::mat4();
}
Animation::~Animation()
{
}
void Animation::init()
{
reset();
}
void Animation::update(float delta_time)
{
}
void Animation::reset()
{
m_model_mat = glm::mat4();
m_model_mat = glm::translate(m_model_mat, glm::vec3(5.0, 0.0, 0.0));
}
Renderer.cpp
#include "Renderer.h"
Camera* Renderer::m_camera = new Camera();
Lighting* Renderer::m_lightings = new Lighting();
Animation* Renderer::m_animation = new Animation();
nanogui::Screen* Renderer::m_nanogui_screen = nullptr;
bool Renderer::keys[1024];
Renderer::Renderer()
{
}
Renderer::~Renderer()
{
}
void Renderer::nanogui_init(GLFWwindow* window)
{
m_nanogui_screen = new nanogui::Screen();
m_nanogui_screen->initialize(window, true);
glViewport(0, 0, m_camera->width, m_camera->height);
//glfwSwapInterval(0);
//glfwSwapBuffers(window);
// Create nanogui gui
nanogui::FormHelper *gui_1 = new nanogui::FormHelper(m_nanogui_screen);
nanogui::ref
//screen->setPosition(Eigen::Vector2i(-width/2 + 200, -height/2 + 300));
gui_1->addGroup("Camera Position");
gui_1->addVariable("X", m_camera->position[0])->setSpinnable(true);
gui_1->addVariable("Y", m_camera->position[1])->setSpinnable(true);
gui_1->addVariable("Z", m_camera->position[2])->setSpinnable(true);
gui_1->addButton("Reset Camera", []() {
m_camera->reset();
});
m_nanogui_screen->setVisible(true);
m_nanogui_screen->performLayout();
glfwSetCursorPosCallback(window,
[](GLFWwindow *window, double x, double y) {
m_nanogui_screen->cursorPosCallbackEvent(x, y);
}
);
glfwSetMouseButtonCallback(window,
[](GLFWwindow *, int button, int action, int modifiers) {
m_nanogui_screen->mouseButtonCallbackEvent(button, action, modifiers);
}
);
glfwSetKeyCallback(window,
[](GLFWwindow *window, int key, int scancode, int action, int mods) {
//screen->keyCallbackEvent(key, scancode, action, mods);
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if (key >= 0 && key < 1024)
{
if (action == GLFW_PRESS)
keys[key] = true;
else if (action == GLFW_RELEASE)
keys[key] = false;
}
}
);
glfwSetCharCallback(window,
[](GLFWwindow *, unsigned int codepoint) {
m_nanogui_screen->charCallbackEvent(codepoint);
}
);
glfwSetDropCallback(window,
[](GLFWwindow *, int count, const char **filenames) {
m_nanogui_screen->dropCallbackEvent(count, filenames);
}
);
glfwSetScrollCallback(window,
[](GLFWwindow *, double x, double y) {
m_nanogui_screen->scrollCallbackEvent(x, y);
//m_camera->ProcessMouseScroll(y);
}
);
glfwSetFramebufferSizeCallback(window,
[](GLFWwindow *, int width, int height) {
m_nanogui_screen->resizeCallbackEvent(width, height);
}
);
}
void Renderer::init()
{
glfwInit();
// Set all the required options for GLFW
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
m_camera->init();
m_lightings->init();
m_animation->init();
// Create a GLFWwindow object that we can use for GLFW's functions
this->m_window = glfwCreateWindow(m_camera->width, m_camera->height, "Assignment 1", nullptr, nullptr);
glfwMakeContextCurrent(this->m_window);
glewExperimental = GL_TRUE;
glewInit();
nanogui_init(this->m_window);
}
void Renderer::display(GLFWwindow* window)
{
Shader m_shader = Shader("./shader/basic.vert", "./shader/basic.frag");
// Main frame while loop
while (!glfwWindowShouldClose(window))
{
glfwPollEvents();
if (is_scean_reset) {
scean_reset();
is_scean_reset = false;
}
camera_move();
m_shader.use();
setup_uniform_values(m_shader);
draw_scene(m_shader);
m_nanogui_screen->drawWidgets();
// Swap the screen buffers
glfwSwapBuffers(window);
}
// Terminate GLFW, clearing any resources allocated by GLFW.
glfwTerminate();
return;
}
void Renderer::run()
{
init();
display(this->m_window);
}
void Renderer::load_models()
{
obj_list.clear();
Object main_object("./objs/bunny.obj");
main_object.obj_color = glm::vec4(0.7, 0.7, 0.7, 1.0);
main_object.obj_name = "main_object";
Object plane_object("./objs/plane.obj");
plane_object.obj_color = glm::vec4(0.5, 0.5, 0.5, 1.0);
plane_object.obj_name = "plane";
Object arrow_object("./objs/arrow.obj");
arrow_object.obj_name = "axis_arrow";
bind_vaovbo(main_object);
bind_vaovbo(plane_object);
bind_vaovbo(arrow_object);
// Here we only load one model
obj_list.push_back(main_object);
obj_list.push_back(plane_object);
obj_list.push_back(arrow_object);
}
void Renderer::draw_scene(Shader& shader)
{
// Set up some basic parameters
glClearColor(background_color[0], background_color[1], background_color[2], background_color[3]);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glFrontFace(GL_CW);
for (size_t i = 0; i < obj_list.size(); i++)
{
if (obj_list[i].obj_name == "main_object")
{
// Before draw the model, change its model mat
glm::mat4 main_object_model_mat = glm::mat4();
m_animation->update(delta_time);
main_object_model_mat = m_animation->get_model_mat();
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(main_object_model_mat));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(m_camera->get_view_mat()));
draw_object(shader, obj_list[i]);
}
if (obj_list[i].obj_name == "plane")
{
// Draw plane
glm::mat4 plane_model_mat = glm::mat4();
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(plane_model_mat));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(m_camera->get_view_mat()));
draw_object(shader, obj_list[i]);
}
if (obj_list[i].obj_name == "axis_arrow")
{
// Draw three axis
glm::mat4 model_mat_x = glm::mat4();
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(model_mat_x));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(m_camera->get_view_mat()));
obj_list[i].obj_color = glm::vec4(1, 0, 0, 1);
draw_object(shader, obj_list[i]);
glm::mat4 model_mat_y = glm::mat4();
model_mat_y = glm::rotate(model_mat_y, glm::radians(-90.0f), glm::vec3(0, 1, 0));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(model_mat_y));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(m_camera->get_view_mat()));
obj_list[i].obj_color = glm::vec4(0, 1, 0, 1);
draw_object(shader, obj_list[i]);
glm::mat4 model_mat_z = glm::mat4();
model_mat_z = glm::rotate(model_mat_z, glm::radians(90.0f), glm::vec3(0, 0, 1));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "model"), 1, GL_FALSE, glm::value_ptr(model_mat_z));
glUniformMatrix4fv(glGetUniformLocation(shader.program, "view"), 1, GL_FALSE, glm::value_ptr(m_camera->get_view_mat()));
obj_list[i].obj_color = glm::vec4(0, 0, 1, 1);
draw_object(shader, obj_list[i]);
}
}
}
void Renderer::camera_move()
{
GLfloat current_frame = glfwGetTime();
delta_time = current_frame - last_frame;
last_frame = current_frame;
// Camera controls
if (keys[GLFW_KEY_W])
m_camera->process_keyboard(FORWARD, delta_time);
if (keys[GLFW_KEY_S])
m_camera->process_keyboard(BACKWARD, delta_time);
if (keys[GLFW_KEY_A])
m_camera->process_keyboard(LEFT, delta_time);
if (keys[GLFW_KEY_D])
m_camera->process_keyboard(RIGHT, delta_time);
if (keys[GLFW_KEY_Q])
m_camera->process_keyboard(UP, delta_time);
if (keys[GLFW_KEY_E])
m_camera->process_keyboard(DOWN, delta_time);
if (keys[GLFW_KEY_I])
m_camera->process_keyboard(ROTATE_X_UP, delta_time);
if (keys[GLFW_KEY_K])
m_camera->process_keyboard(ROTATE_X_DOWN, delta_time);
if (keys[GLFW_KEY_J])
m_camera->process_keyboard(ROTATE_Y_UP, delta_time);
if (keys[GLFW_KEY_L])
m_camera->process_keyboard(ROTATE_Y_DOWN, delta_time);
if (keys[GLFW_KEY_U])
m_camera->process_keyboard(ROTATE_Z_UP, delta_time);
if (keys[GLFW_KEY_O])
m_camera->process_keyboard(ROTATE_Z_DOWN, delta_time);
}
void Renderer::draw_object(Shader& shader, Object& object)
{
glBindVertexArray(object.vao);
glUniform3f(glGetUniformLocation(shader.program, "m_object.object_color"), object.obj_color[0], object.obj_color[1], object.obj_color[2]);
glUniform1f(glGetUniformLocation(shader.program, "m_object.shininess"), object.shininess);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawArrays(GL_TRIANGLES, 0, object.vao_vertices.size());
glBindVertexArray(0);
}
void Renderer::bind_vaovbo(Object &cur_obj)
{
glGenVertexArrays(1, &cur_obj.vao);
glGenBuffers(1, &cur_obj.vbo);
glBindVertexArray(cur_obj.vao);
glBindBuffer(GL_ARRAY_BUFFER, cur_obj.vbo);
glBufferData(GL_ARRAY_BUFFER, cur_obj.vao_vertices.size() * sizeof(Object::Vertex), &cur_obj.vao_vertices[0], GL_STATIC_DRAW);
// Vertex Positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Object::Vertex), (GLvoid*)0);
// Vertex Normals
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Object::Vertex), (GLvoid*)offsetof(Object::Vertex, Normal));
// Vertex Texture Coords
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Object::Vertex), (GLvoid*)offsetof(Object::Vertex, TexCoords));
glBindVertexArray(0);
}
void Renderer::setup_uniform_values(Shader& shader)
{
// Camera uniform values
glUniform3f(glGetUniformLocation(shader.program, "camera_pos"), m_camera->position.x, m_camera->position.y, m_camera->position.z);
glUniformMatrix4fv(glGetUniformLocation(shader.program, "projection"), 1, GL_FALSE, glm::value_ptr(m_camera->get_projection_mat()));
// Light uniform values
glUniform1i(glGetUniformLocation(shader.program, "dir_light.status"), m_lightings->direction_light.status);
glUniform3f(glGetUniformLocation(shader.program, "dir_light.direction"), m_lightings->direction_light.direction[0], m_lightings->direction_light.direction[1], m_lightings->direction_light.direction[2]);
glUniform3f(glGetUniformLocation(shader.program, "dir_light.ambient"), m_lightings->direction_light.ambient[0], m_lightings->direction_light.ambient[1], m_lightings->direction_light.ambient[2]);
glUniform3f(glGetUniformLocation(shader.program, "dir_light.diffuse"), m_lightings->direction_light.diffuse[0], m_lightings->direction_light.diffuse[1], m_lightings->direction_light.diffuse[2]);
glUniform3f(glGetUniformLocation(shader.program, "dir_light.specular"), m_lightings->direction_light.specular[0], m_lightings->direction_light.specular[1], m_lightings->direction_light.specular[2]);
// Set current point light as camera's position
m_lightings->point_light.position = m_camera->position;
glUniform1i(glGetUniformLocation(shader.program, "point_light.status"), m_lightings->point_light.status);
glUniform3f(glGetUniformLocation(shader.program, "point_light.position"), m_lightings->point_light.position[0], m_lightings->point_light.position[1], m_lightings->point_light.position[2]);
glUniform3f(glGetUniformLocation(shader.program, "point_light.ambient"), m_lightings->point_light.ambient[0], m_lightings->point_light.ambient[1], m_lightings->point_light.ambient[2]);
glUniform3f(glGetUniformLocation(shader.program, "point_light.diffuse"), m_lightings->point_light.diffuse[0], m_lightings->point_light.diffuse[1], m_lightings->point_light.diffuse[2]);
glUniform3f(glGetUniformLocation(shader.program, "point_light.specular"), m_lightings->point_light.specular[0], m_lightings->point_light.specular[1], m_lightings->point_light.specular[2]);
glUniform1f(glGetUniformLocation(shader.program, "point_light.constant"), m_lightings->point_light.constant);
glUniform1f(glGetUniformLocation(shader.program, "point_light.linear"), m_lightings->point_light.linear);
glUniform1f(glGetUniformLocation(shader.program, "point_light.quadratic"), m_lightings->point_light.quadratic);
}
void Renderer::scean_reset()
{
load_models();
m_camera->reset();
}
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started