Computer Graphics
understanding how render works
Summary
In this course, I did six assignments.
- Just draw circle made of lots of triangle
- read and rotating bunny model with VBO and matrix
- rotate and zoom bunny model with mouse input(camera view port)
- lighting and phong shading
- add texture(diffuse and bump map)
- add shadow(multi-sampling for soft shadow)
I upload result video and sixth real code.
Language and Software
C++, visual studio
Result video
https://youtu.be/G3IzZyQKpiU
Sixth shadow code(except shader code)
#include "stdafx.h"
#include <stdlib.h>
#include<GL/glew.h>
#include <GLFW/glfw3.h>
#include<glm/glm.hpp>
#include<vector>
#include"toys.h"
#include<math.h>
#define GLM_ENABLE_EXPERIMENTAL
#define STB_IMAGE_IMPLEMENTATION
#include<glm/gtc/type_ptr.hpp>
#include<glm/gtx/transform.hpp>
#include"j3a.hpp"
#include"stb_image.h"
using namespace glm;
bool buttonPressed = false;
double lastX, lastY;
vec3 cameraPos = vec3(0, 0, 5);
vec3 lightPosition = vec3(5, 5, 5);
float theta = 0, phi = 0, fov = 60;
void render(GLFWwindow* window);
void init(void);
void cursorPosCB(GLFWwindow* window, double x, double y) {
if(buttonPressed == true){
int width, height;
glfwGetWindowSize(window, &width, &height);
float dx = (x - lastX)/width;
float dy = (y - lastY)/height;
theta += -dx*3.141592f;
phi += -dy * 3.141592f;
if (phi > 1.4) phi = 1.4f;
if (phi < -1.4)phi = -1.4f;
cameraPos = vec3(
rotate(theta, vec3(0, 1, 0))
*rotate(phi, vec3(1,0,0))
*vec4(0, 0, 5, 1)
);
lastX = x;
lastY = y;
}
}
void mouseButtonCB(GLFWwindow* window, int button, int state, int mods) {
if (button == GLFW_MOUSE_BUTTON_1)
{
if (state == GLFW_PRESS) {
buttonPressed = true;
glfwGetCursorPos(window, &lastX, &lastY);
}
else
buttonPressed = false;
}
}
void scrollCB(GLFWwindow* window, double, double y) {
fov += y*10;
if (fov > 170)fov = 170;
if (fov < 10)fov = 10;
}
int main(void) {
if (!glfwInit())
exit(EXIT_FAILURE);
#ifdef __APPLE__
GLFWwindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
GLFWwindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
GLFWwindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#endif
glfwWindowHint(GLFW_SAMPLES, 4);
GLFWwindow* window = glfwCreateWindow(640, 640, "Hello", NULL, NULL);
glfwSetCursorPosCallback(window, cursorPosCB);
glfwSetMouseButtonCallback(window, mouseButtonCB);
glfwSetScrollCallback(window, scrollCB);
glfwMakeContextCurrent(window);
glewInit();
init();
glfwSwapInterval(1);
while (!glfwWindowShouldClose(window)) {
render(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
}
GLuint vertexBuffer = 0;
GLuint normalBuffer = 0;
GLuint texCoordBuffer = 0;
GLuint vertexArrayID = 0;
GLuint elementArray = 0;
GLuint textureID = 0;
GLuint bumpID = 0;
Program prog;
Program shadowProg;
GLuint shadowTex = 0;
GLuint shadowDepth = 0;
GLuint shadowFBO = 0;
void init(void) {
prog.loadShaders("shader.vert", "shader.frag");
shadowProg.loadShaders("shadow.vert", "shadow.frag");
#pragma region Init_rotateBunny
loadJ3A("dwarf.j3a");
glGenVertexArrays(1, &vertexArrayID);
glBindVertexArray(vertexArrayID);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, nVertices[0] * sizeof(glm::vec3), vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &normalBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glBufferData(GL_ARRAY_BUFFER, nVertices[0] * sizeof(glm::vec3), normals[0], GL_STATIC_DRAW);
glGenBuffers(1, &texCoordBuffer);
glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, nVertices[0] * sizeof(glm::vec2), texCoords[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0);
glGenBuffers(1, &vertexArrayID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexArrayID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nTriangles[0] * sizeof(glm::u32vec3), triangles[0], GL_STATIC_DRAW);
int w = 0, h = 0, n = 0;
void* buf = stbi_load("dwarfD.jpg", &w, &h, &n, 4); // n must be 4
//Generate texture & set parameters
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//Send data & delete buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB8_ALPHA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(buf);
buf = stbi_load("dwarfB.jpg", &w, &h, &n, 4);
//Generate texture & set parameters
glGenTextures(1, &bumpID);
glBindTexture(GL_TEXTURE_2D, bumpID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
//Send data & delete buffer
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(buf);
//Shadow Map
glGenTextures(1, &shadowTex);
glBindTexture(GL_TEXTURE_2D, shadowTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 1024, 1024, 0, GL_RGB, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Depth Map
glGenTextures(1, &shadowDepth);
glBindTexture(GL_TEXTURE_2D, shadowDepth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
//Frame buffer object for Depth&Shadow Map
glGenFramebuffers(1, &shadowFBO);
glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, shadowTex, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowDepth, 0);
GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, drawBuffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) printf("FBO Error\n");
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
}
void render(GLFWwindow* window) {
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, shadowFBO);
glViewport(0, 0, 1024, 1024);
glClearColor(1, 1, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(shadowProg.programID);
mat4 shadowProjMat = ortho(-2.f, 2.f, -2.f, 2.f, 0.01f, 10.f);
mat4 shadowViewMat = lookAt(lightPosition, vec3(0,0,0), vec3(0,1,0) );
mat4 modelMat = mat4(1);//rotate(-theta, vec3(0, 1, 0))*rotate(-phi, vec3(1, 0, 0));
mat4 shadowMVP = shadowProjMat * shadowViewMat *modelMat;
GLuint loc = glGetUniformLocation(shadowProg.programID, "shadowMVP");
glUniformMatrix4fv(loc, 1, false, value_ptr(shadowMVP));
mat4 biasMatrix = translate(vec3(0.5))*scale(vec3(0.5));
mat4 shadowBiasMVP = biasMatrix * shadowMVP;
glBindVertexArray(vertexArrayID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexArrayID);
glDrawElements(GL_TRIANGLES, nTriangles[0] * 3, GL_UNSIGNED_INT, 0);
glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
glViewport(0, 0, width, height);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(prog.programID);
mat4 rotMat = rotate(0 * 3.14159f / 180, glm::vec3(1, 0, 0));
#pragma region LinkMatrix
loc = glGetUniformLocation(prog.programID, "rotMT");
glUniformMatrix4fv(loc, 1, false, value_ptr(rotMat));
#pragma endregion
loc = glGetUniformLocation(prog.programID, "cameraPosition");
glUniform3fv(loc, 1, value_ptr(cameraPos));
mat4 viewingMat = lookAt(cameraPos, vec3(0), vec3(0, 1, 0));
loc = glGetUniformLocation(prog.programID, "viewMat");
glUniformMatrix4fv(loc, 1, false, value_ptr(viewingMat));
mat4 projMat = perspective(fov*3.141592f / 180, width / (float)height, 0.1f, 100.0f);
loc = glGetUniformLocation(prog.programID, "projMat");
glUniformMatrix4fv(loc, 1, false, value_ptr(projMat));
loc = glGetUniformLocation(prog.programID, "lightPos");
glUniform3fv(loc, 1, value_ptr(lightPosition));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
loc = glGetUniformLocation(prog.programID, "diffTex");
glUniform1i(loc, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, bumpID);
loc = glGetUniformLocation(prog.programID, "bumpTex");
glUniform1i(loc, 1);
loc = glGetUniformLocation(prog.programID, "shadowMVP");
glUniformMatrix4fv(loc, 1, false, value_ptr(shadowMVP));
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, shadowTex);
loc = glGetUniformLocation(prog.programID, "shadowMap");
glUniform1i(loc, 2);
//Draw!
glBindVertexArray(vertexArrayID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexArrayID);
glDrawElements(GL_TRIANGLES, nTriangles[0] * 3, GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
}