PBR checkpoint
[opengl.git] / skybox.cpp
index 79ce9d022029cf121fc51c02f1cf05e67026382a..45ab4eacaa8ecf31d5ce50e92470d04d92186fbe 100644 (file)
@@ -1,26 +1,44 @@
 #include "shapes.hpp"
 #include "skybox.hpp"
-#include "image.hpp"
 #include <glm/gtc/type_ptr.hpp>
 
-Skybox::Skybox(const std::vector<std::string> faces): program("skyboxvert.glsl", "skyboxfrag.glsl") {
-       glGenTextures(1, &texId);
-       glBindTexture(GL_TEXTURE_CUBE_MAP, texId);
-       glDepthFunc(GL_LEQUAL);
+Skybox::Skybox(const Image img): program("skyboxvert.glsl", "skyboxfrag.glsl") {
+       Program equiProg("equirectangularvert.glsl", "equirectangularfrag.glsl");
+       glUseProgram(equiProg.progId);
        
-       int width, height, numChans;
-       for (int i = 0; i < faces.size(); i++) {
-               Image img(faces[i]);
+       GLuint equiTexId;
+       glGenTextures(1, &equiTexId);
+       glBindTexture(GL_TEXTURE_2D, equiTexId);
 
-               glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data());
-       }
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_SHORT, (unsigned short*)img.data());
 
-       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_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
+
+       // generate framebuffers to store cubemap in
+       GLuint captureFBO, captureRBO;
+       glGenFramebuffers(1, &captureFBO);
+       glGenRenderbuffers(1, &captureRBO);
+
+       glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+       glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
+       glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512);
+       glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureFBO);
+
+       // generate and setup cubemap texture
+       glGenTextures(1, &texId);
+       glBindTexture(GL_TEXTURE_CUBE_MAP, texId);
+       for (GLuint i = 0; i < 6; i++)
+               glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr);
        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);
+       glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
+       // generate cube to render
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
 
@@ -29,15 +47,60 @@ Skybox::Skybox(const std::vector<std::string> faces): program("skyboxvert.glsl",
 
        auto vertices = cube();
 
+       glBindBuffer(GL_ARRAY_BUFFER, vbo);
+       glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
+       
+       GLuint posLoc = glGetAttribLocation(program.progId, "pos");
+       glEnableVertexAttribArray(posLoc);
+       glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+       // render the cube
+       glm::mat4 captureProj = glm::perspective(glm::radians(90.f), 1.f, 0.1f, 10.f);
+       glm::mat4 captureViews[] = {
+               glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 1,  0,  0), glm::vec3(0, -1,  0)),
+               glm::lookAt(glm::vec3(0, 0, 0), glm::vec3(-1,  0,  0), glm::vec3(0, -1,  0)),
+               glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0,  1,  0), glm::vec3(0,  0,  1)),
+               glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0, -1,  0), glm::vec3(0,  0, -1)),
+               glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0,  0,  1), glm::vec3(0, -1,  0)),
+               glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0,  0, -1), glm::vec3(0, -1,  0))
+       };
+
+       glUniform1i(glGetUniformLocation(equiProg.progId, "equirectangularMap"), 0);
+       glUniformMatrix4fv(glGetUniformLocation(equiProg.progId, "projection"), 1, GL_FALSE, glm::value_ptr(captureProj));
+       glActiveTexture(GL_TEXTURE0);
+       glBindTexture(GL_TEXTURE_2D, equiTexId);
+
+       glViewport(0, 0, 512, 512);
+       glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+       for (GLuint i = 0; i < 6; i++) {
+               glUniformMatrix4fv(glGetUniformLocation(equiProg.progId, "view"), 1, GL_FALSE, glm::value_ptr(captureViews[i]));
+               glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, texId, 0);
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+               glDrawArrays(GL_TRIANGLES, 0, 36);
+       }
+       
+       
+       // switch back to regular skybox shader
+       glUseProgram(program.progId);
+       glDepthFunc(GL_LEQUAL);
+
+       glGenVertexArrays(1, &vao);
+       glBindVertexArray(vao);
+
+       glGenBuffers(1, &vbo);
+
        // reverse so facing inside out
        std::reverse(vertices.begin(), vertices.end());
 
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
        glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
        
-       GLuint posLoc = glGetAttribLocation(program.progId, "pos");
+       posLoc = glGetAttribLocation(program.progId, "pos");
        glEnableVertexAttribArray(posLoc);
        glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
+
+       // restore default framebuffer
+       glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
 void Skybox::draw(glm::mat4 proj, glm::mat4 view) const {
@@ -55,6 +118,8 @@ void Skybox::draw(glm::mat4 proj, glm::mat4 view) const {
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_CUBE_MAP, texId);
        glDrawArrays(GL_TRIANGLES, 0, 36);
+
+       if (glGetError()) exit(1);
 }
 
 GLuint Skybox::getTexture() const {