Skip to content

Instantly share code, notes, and snippets.

@amoshyc
Created December 30, 2018 17:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amoshyc/f5d6be225b284c07ce6b2e914889a771 to your computer and use it in GitHub Desktop.
Save amoshyc/f5d6be225b284c07ce6b2e914889a771 to your computer and use it in GitHub Desktop.
#include "../Externals/Include/Include.h"
#include "Object.hpp"
#define sz(x) (int(x.size()))
using namespace glm;
using namespace std;
#define SHADOW_MAP_SIZE 2048
Object quad;
Object suit;
vec3 light_pos = vec3(-31.75, 26.05, -97.72);
void My_Reshape(int width, int height);
static const GLfloat window_positions[] = {
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f};
struct {
struct {
mat4 view;
mat4 proj;
} eye;
} matrices;
struct {
struct {
GLint mvp;
} light;
struct {
GLuint shadow_tex;
GLuint skybox_tex;
GLint mv_matrix;
GLint proj_matrix;
GLint shadow_matrix;
GLint light_pos;
GLint is_quad;
GLint shadow;
} view;
struct {
GLuint view;
GLuint proj;
} skybox;
struct {
GLuint mode;
GLuint tex[3];
} fuse;
} uniforms;
struct {
GLuint fbo;
GLuint depthMap;
} shadowBuffer;
struct {
int width = 1440 * 2 / 3;
int height = 900 * 2 / 3;
} viewportSize;
struct {
GLuint vao;
GLuint vbo;
GLuint tex;
} skybox;
struct {
int mode = 0;
GLuint vao;
GLuint vbo;
GLuint fbo[3];
GLuint rbo[3];
GLuint tex[3];
} fuse;
GLuint depthProg;
GLuint blinnPhongProg;
GLuint skyboxProg;
GLuint fuseProg;
float skyboxVertices[] = {
-1.0f, +1.0f, -1.0f, -1.0f, -1.0f, -1.0f, +1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, -1.0f, +1.0f, -1.0f,
-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, -1.0f, -1.0f, +1.0f, -1.0f,
-1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, -1.0f, +1.0f,
+1.0f, -1.0f, -1.0f, +1.0f, -1.0f, +1.0f, +1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, +1.0f, +1.0f, +1.0f, -1.0f, +1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, +1.0f, -1.0f, +1.0f, +1.0f, +1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, +1.0f, +1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f,
-1.0f, +1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f, +1.0f,
+1.0f, +1.0f, +1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f, -1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, -1.0f,
+1.0f, -1.0f, -1.0f, -1.0f, -1.0f, +1.0f, +1.0f, -1.0f, +1.0f};
GLuint createProgram(string name) {
auto vs_path = "shaders/" + name + ".vs.glsl";
auto fs_path = "shaders/" + name + ".fs.glsl";
auto program = glCreateProgram();
auto vs_shader = glCreateShader(GL_VERTEX_SHADER);
auto fs_shader = glCreateShader(GL_FRAGMENT_SHADER);
char **vs_source = loadShaderSource(vs_path.c_str());
char **fs_source = loadShaderSource(fs_path.c_str());
glShaderSource(vs_shader, 1, vs_source, NULL);
glShaderSource(fs_shader, 1, fs_source, NULL);
freeShaderSource(vs_source);
freeShaderSource(fs_source);
cout << "Compiling " << vs_path << endl;
glCompileShader(vs_shader);
shaderLog(vs_shader);
cout << "Compiling " << fs_path << endl;
glCompileShader(fs_shader);
shaderLog(fs_shader);
glAttachShader(program, vs_shader);
glAttachShader(program, fs_shader);
glLinkProgram(program);
return program;
}
void My_Init() {
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_STENCIL_TEST);
depthProg = createProgram("shadow");
uniforms.light.mvp = glGetUniformLocation(depthProg, "mvp");
// ----- End Initialize Depth Shader Program -----
skyboxProg = createProgram("skybox");
uniforms.skybox.proj = glGetUniformLocation(skyboxProg, "proj");
uniforms.skybox.view = glGetUniformLocation(skyboxProg, "view");
// ----- Begin Initialize Blinn-Phong Shader Program -----
blinnPhongProg = createProgram("blinnphong");
uniforms.view.proj_matrix =
glGetUniformLocation(blinnPhongProg, "proj_matrix");
uniforms.view.mv_matrix = glGetUniformLocation(blinnPhongProg, "mv_matrix");
uniforms.view.shadow_matrix =
glGetUniformLocation(blinnPhongProg, "shadow_matrix");
uniforms.view.shadow_tex =
glGetUniformLocation(blinnPhongProg, "shadow_tex");
uniforms.view.skybox_tex =
glGetUniformLocation(blinnPhongProg, "skybox_tex");
uniforms.view.light_pos = glGetUniformLocation(blinnPhongProg, "light_pos");
uniforms.view.is_quad = glGetUniformLocation(blinnPhongProg, "is_quad");
uniforms.view.shadow = glGetUniformLocation(blinnPhongProg, "shadow");
// ----- End Initialize Blinn-Phong Shader Program -----
fuseProg = createProgram("fuse");
uniforms.fuse.tex[0] = glGetUniformLocation(fuseProg, "tex0");
uniforms.fuse.tex[1] = glGetUniformLocation(fuseProg, "tex1");
uniforms.fuse.tex[2] = glGetUniformLocation(fuseProg, "tex2");
uniforms.fuse.mode = glGetUniformLocation(fuseProg, "mode");
quad = Object("quad.obj");
quad.model = mat4();
quad.model = translate(quad.model, vec3(-10, -13, -8));
quad.model = translate(quad.model, vec3(+3, 0, +8));
quad.model = scale(quad.model, vec3(1.1, 1, 1.5));
suit = Object("nanosuit.obj");
suit.model = mat4();
suit.model = translate(suit.model, vec3(-10, -13, -8));
suit.model = scale(suit.model, vec3(0.5, 0.35, 0.5));
// Skybox
cout << "Loading Skybox" << endl;
vector<string> filenames = {"right.jpg", "left.jpg", "top.jpg",
"bottom.jpg", "front.jpg", "back.jpg"};
glGenTextures(1, &skybox.tex);
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox.tex);
for (int i = 0; i < 6; i++) {
auto name = filenames[i];
auto path = "boxes/" + name;
int w, h, c;
unsigned char *data = stbi_load(path.c_str(), &w, &h, &c, 0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, w, h, 0,
GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
cout << "\t" << name << ": " << w << ", " << h << endl;
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glGenVertexArrays(1, &skybox.vao);
glBindVertexArray(skybox.vao);
glGenBuffers(1, &skybox.vbo);
glBindBuffer(GL_ARRAY_BUFFER, skybox.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices,
GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
// ----- Begin Initialize Shadow Framebuffer Object -----
glGenFramebuffers(1, &shadowBuffer.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, shadowBuffer.fbo);
glGenTextures(1, &shadowBuffer.depthMap);
glBindTexture(GL_TEXTURE_2D, shadowBuffer.depthMap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, SHADOW_MAP_SIZE,
SHADOW_MAP_SIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
GL_COMPARE_REF_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
shadowBuffer.depthMap, 0);
// ----- End Initialize Shadow Framebuffer Object -----
glGenVertexArrays(1, &fuse.vao);
glBindVertexArray(fuse.vao);
glGenBuffers(1, &fuse.vbo);
glBindBuffer(GL_ARRAY_BUFFER, fuse.vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(window_positions), window_positions,
GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 4, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 4,
(const GLvoid *)(sizeof(GL_FLOAT) * 2));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glGenFramebuffers(1, &fuse.fbo[0]);
glGenFramebuffers(1, &fuse.fbo[1]);
glGenFramebuffers(1, &fuse.fbo[2]);
My_Reshape(viewportSize.width, viewportSize.height);
}
void renderShadow(const mat4 &light_vp_matrix) {
glBindFramebuffer(GL_FRAMEBUFFER, shadowBuffer.fbo);
glClear(GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE);
glUseProgram(depthProg);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(4.0f, 4.0f);
glUniformMatrix4fv(uniforms.light.mvp, 1, GL_FALSE,
value_ptr(light_vp_matrix * quad.model));
quad.render();
glUniformMatrix4fv(uniforms.light.mvp, 1, GL_FALSE,
value_ptr(light_vp_matrix * suit.model));
suit.render();
glDisable(GL_POLYGON_OFFSET_FILL);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, viewportSize.width, viewportSize.height);
}
void renderObject(const mat4 &shadow_sbpv_matrix, bool shadow, bool draw_quad,
bool draw_suit) {
glUseProgram(blinnPhongProg);
glUniform1i(uniforms.view.shadow, int(shadow));
glUniformMatrix4fv(uniforms.view.proj_matrix, 1, GL_FALSE,
value_ptr(matrices.eye.proj));
glUniformMatrix4fv(uniforms.view.light_pos, 1, GL_FALSE,
value_ptr(light_pos));
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, shadowBuffer.depthMap);
glUniform1i(uniforms.view.shadow_tex, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox.tex);
glUniform1i(uniforms.view.skybox_tex, 1);
if (draw_quad) {
mat4 quad_mv = matrices.eye.view * quad.model;
mat4 shadow_matrix = shadow_sbpv_matrix * quad.model;
glUniform1i(uniforms.view.is_quad, 1);
glUniformMatrix4fv(uniforms.view.mv_matrix, 1, GL_FALSE,
value_ptr(quad_mv));
glUniformMatrix4fv(uniforms.view.shadow_matrix, 1, GL_FALSE,
value_ptr(shadow_matrix));
quad.render();
}
if (draw_suit) {
mat4 suit_mv = matrices.eye.view * suit.model;
mat4 shadow_matrix = shadow_sbpv_matrix * suit.model;
glUniform1i(uniforms.view.is_quad, 0);
glUniformMatrix4fv(uniforms.view.mv_matrix, 1, GL_FALSE,
value_ptr(suit_mv));
glUniformMatrix4fv(uniforms.view.shadow_matrix, 1, GL_FALSE,
value_ptr(shadow_matrix));
suit.render();
}
}
void renderSkybox() {
glUseProgram(skyboxProg);
mat4 view = mat4(mat3(matrices.eye.view));
mat4 proj = matrices.eye.proj;
glUniformMatrix4fv(uniforms.skybox.view, 1, GL_FALSE, value_ptr(view));
glUniformMatrix4fv(uniforms.skybox.proj, 1, GL_FALSE, value_ptr(proj));
glBindVertexArray(skybox.vao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, skybox.tex);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
void My_Display() {
static const GLfloat black[] = {0.0f, 0.0f, 0.0f, 1.0f};
static const GLfloat zero = 1.0f;
mat4 scale_bias_matrix = translate(mat4(), vec3(0.5f, 0.5f, 0.5f)) *
scale(mat4(), vec3(0.5f, 0.5f, 0.5f));
const float shadow_range = 15.0f;
mat4 light_proj_matrix = ortho(-shadow_range, shadow_range, -shadow_range,
shadow_range, 0.0f, 500.0f);
mat4 light_view_matrix =
lookAt(light_pos, vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 1.0f, 0.0f));
mat4 light_vp_matrix = light_proj_matrix * light_view_matrix;
mat4 shadow_sbpv_matrix = scale_bias_matrix * light_vp_matrix;
{ // stage 1
renderShadow(light_vp_matrix);
glBindFramebuffer(GL_FRAMEBUFFER, fuse.fbo[0]);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDisable(GL_DEPTH_TEST);
renderObject(shadow_sbpv_matrix, false, false, true); // suit
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00);
renderObject(shadow_sbpv_matrix, true, true, false); // quad
glStencilMask(0xFF);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
{ // stage 2
glBindFramebuffer(GL_FRAMEBUFFER, fuse.fbo[1]);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilMask(0xFF);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDisable(GL_DEPTH_TEST);
renderObject(shadow_sbpv_matrix, false, false, true); // suit
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glEnable(GL_DEPTH_TEST);
glStencilFunc(GL_NOTEQUAL, 1, 0xFF);
glStencilMask(0x00);
renderObject(shadow_sbpv_matrix, false, true, true); // quad
glStencilMask(0xFF);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
{ // stage 3
glBindFramebuffer(GL_FRAMEBUFFER, fuse.fbo[2]);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
renderObject(shadow_sbpv_matrix, false, false, true);
renderSkybox();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glUseProgram(fuseProg);
glUniform1i(uniforms.fuse.mode, fuse.mode);
glBindVertexArray(fuse.vao);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, fuse.tex[0]);
glUniform1i(uniforms.fuse.tex[0], 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, fuse.tex[1]);
glUniform1i(uniforms.fuse.tex[1], 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, fuse.tex[2]);
glUniform1i(uniforms.fuse.tex[2], 2);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glutSwapBuffers();
}
void My_Reshape(int width, int height) {
viewportSize.width = width;
viewportSize.height = height;
float viewportAspect = (float)width / (float)height;
matrices.eye.proj =
perspective(radians(80.0f), viewportAspect, 0.1f, 1000.0f);
matrices.eye.view = lookAt(vec3(0.0f, 0.0f, 0.0f), vec3(-1.0f, -1.0f, 0.0f),
vec3(0.0f, 1.0f, 0.0f));
// If the windows is reshaped, we need to reset some settings of framebuffer
for (int i = 0; i < 3; i++) {
glDeleteRenderbuffers(1, &fuse.rbo[i]);
glDeleteTextures(1, &fuse.tex[i]);
glGenRenderbuffers(1, &fuse.rbo[i]);
glBindRenderbuffer(GL_RENDERBUFFER, fuse.rbo[i]);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width,
height);
glGenTextures(1, &fuse.tex[i]);
glBindTexture(GL_TEXTURE_2D, fuse.tex[i]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fuse.fbo[i]);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
fuse.rbo[i]);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, fuse.tex[i], 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << endl;
}
glutPostRedisplay();
}
void My_Keyboard(unsigned char key, int x, int y) {
if (key == 'i') {
fuse.mode = (fuse.mode + 1) % 4;
cout << "Mode: " << fuse.mode << endl;
}
if (key == 'q') {
suit.model = rotate(suit.model, radians(10.0f), vec3(0, 1, 0));
}
if (key == 'e') {
suit.model = rotate(suit.model, radians(-10.0f), vec3(0, 1, 0));
}
glutPostRedisplay();
}
void My_Timer(int val) {
glutPostRedisplay();
glutTimerFunc(16, My_Timer, val);
}
int main(int argc, char *argv[]) {
// Initialize GLUT and GLEW, then create a window.
////////////////////
glutInit(&argc, argv);
#ifdef _MSC_VER
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
#else
glutInitDisplayMode(GLUT_3_2_CORE_PROFILE | GLUT_RGBA | GLUT_DOUBLE |
GLUT_DEPTH);
#endif
glutInitWindowPosition(100, 100);
glutInitWindowSize(1440 * 2 / 3, 900 * 2 / 3);
glutCreateWindow(__FILENAME__); // You cannot use OpenGL functions before
// this line; The OpenGL context must be
// created first by glutCreateWindow()!
#ifdef _MSC_VER
glewInit();
#endif
dumpInfo();
My_Init();
////////////////////
// Register GLUT callback functions.
///////////////////////////////
glutDisplayFunc(My_Display);
glutReshapeFunc(My_Reshape);
glutKeyboardFunc(My_Keyboard);
glutTimerFunc(16, My_Timer, 0);
///////////////////////////////
// Enter main event loop.
//////////////
glutMainLoop();
//////////////
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment