PBR checkpoint
[opengl.git] / skybox.cpp
1 #include "shapes.hpp"
2 #include "skybox.hpp"
3 #include <glm/gtc/type_ptr.hpp>
4
5 Skybox::Skybox(const Image img): program("skyboxvert.glsl", "skyboxfrag.glsl") {
6         Program equiProg("equirectangularvert.glsl", "equirectangularfrag.glsl");
7         glUseProgram(equiProg.progId);
8         
9         GLuint equiTexId;
10         glGenTextures(1, &equiTexId);
11         glBindTexture(GL_TEXTURE_2D, equiTexId);
12
13         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_SHORT, (unsigned short*)img.data());
14
15         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
16         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
17         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
18         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
19
20         // generate framebuffers to store cubemap in
21         GLuint captureFBO, captureRBO;
22         glGenFramebuffers(1, &captureFBO);
23         glGenRenderbuffers(1, &captureRBO);
24
25         glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
26         glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
27         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512);
28         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureFBO);
29
30         // generate and setup cubemap texture
31         glGenTextures(1, &texId);
32         glBindTexture(GL_TEXTURE_CUBE_MAP, texId);
33         for (GLuint i = 0; i < 6; i++)
34                 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr);
35         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
36         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
37         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
38         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
39         glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
40
41         // generate cube to render
42         glGenVertexArrays(1, &vao);
43         glBindVertexArray(vao);
44
45         GLuint vbo;
46         glGenBuffers(1, &vbo);
47
48         auto vertices = cube();
49
50         glBindBuffer(GL_ARRAY_BUFFER, vbo);
51         glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
52         
53         GLuint posLoc = glGetAttribLocation(program.progId, "pos");
54         glEnableVertexAttribArray(posLoc);
55         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
56
57         // render the cube
58         glm::mat4 captureProj = glm::perspective(glm::radians(90.f), 1.f, 0.1f, 10.f);
59         glm::mat4 captureViews[] = {
60                 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 1,  0,  0), glm::vec3(0, -1,  0)),
61                 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3(-1,  0,  0), glm::vec3(0, -1,  0)),
62                 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0,  1,  0), glm::vec3(0,  0,  1)),
63                 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0, -1,  0), glm::vec3(0,  0, -1)),
64                 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0,  0,  1), glm::vec3(0, -1,  0)),
65                 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0,  0, -1), glm::vec3(0, -1,  0))
66         };
67
68         glUniform1i(glGetUniformLocation(equiProg.progId, "equirectangularMap"), 0);
69         glUniformMatrix4fv(glGetUniformLocation(equiProg.progId, "projection"), 1, GL_FALSE, glm::value_ptr(captureProj));
70         glActiveTexture(GL_TEXTURE0);
71         glBindTexture(GL_TEXTURE_2D, equiTexId);
72
73         glViewport(0, 0, 512, 512);
74         glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
75         for (GLuint i = 0; i < 6; i++) {
76                 glUniformMatrix4fv(glGetUniformLocation(equiProg.progId, "view"), 1, GL_FALSE, glm::value_ptr(captureViews[i]));
77                 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, texId, 0);
78                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
79                 glDrawArrays(GL_TRIANGLES, 0, 36);
80         }
81         
82         
83         // switch back to regular skybox shader
84         glUseProgram(program.progId);
85         glDepthFunc(GL_LEQUAL);
86
87         glGenVertexArrays(1, &vao);
88         glBindVertexArray(vao);
89
90         glGenBuffers(1, &vbo);
91
92         // reverse so facing inside out
93         std::reverse(vertices.begin(), vertices.end());
94
95         glBindBuffer(GL_ARRAY_BUFFER, vbo);
96         glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
97         
98         posLoc = glGetAttribLocation(program.progId, "pos");
99         glEnableVertexAttribArray(posLoc);
100         glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);
101
102         // restore default framebuffer
103         glBindFramebuffer(GL_FRAMEBUFFER, 0);
104 }
105
106 void Skybox::draw(glm::mat4 proj, glm::mat4 view) const {
107         glUseProgram(program.progId);
108
109         glBindVertexArray(vao);
110
111         GLuint projLoc = glGetUniformLocation(program.progId, "projection");
112         glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
113
114         GLuint viewLoc = glGetUniformLocation(program.progId, "view");
115         view = glm::mat4(glm::mat3(view));
116         glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
117
118         glActiveTexture(GL_TEXTURE0);
119         glBindTexture(GL_TEXTURE_CUBE_MAP, texId);
120         glDrawArrays(GL_TRIANGLES, 0, 36);
121
122         if (glGetError()) exit(1);
123 }
124
125 GLuint Skybox::getTexture() const {
126         return texId;
127 }