3 #include <glm/gtc/type_ptr.hpp>
5 GLuint setupCubeVertices(GLuint progId, bool reverse = false);
7 Skybox::Skybox(const Image img): program("skyboxvert.glsl", "skyboxfrag.glsl") {
8 Program equiProg("skyboxvert.glsl", "equirectangularfrag.glsl");
9 glUseProgram(equiProg.progId);
12 glGenTextures(3, allTexIds);
13 hdrTexId = allTexIds[0], cubemapTexId = allTexIds[1], irradianceTexId = allTexIds[2];
15 glBindTexture(GL_TEXTURE_2D, hdrTexId);
17 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, img.width(), img.height(), 0, GL_RGB, GL_UNSIGNED_SHORT, (unsigned short*)img.data());
19 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
20 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
21 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
22 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
24 // generate framebuffers to store cubemap in
25 GLuint captureFBO, captureRBO;
26 glGenFramebuffers(1, &captureFBO);
27 glGenRenderbuffers(1, &captureRBO);
29 glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
30 glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
31 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512);
32 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureFBO);
34 // setup cubemap texture
35 glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexId);
36 for (GLuint i = 0; i < 6; i++)
37 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 512, 512, 0, GL_RGB, GL_FLOAT, nullptr);
38 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
39 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
40 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
41 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
42 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
45 setupCubeVertices(equiProg.progId);
48 glm::mat4 captureProj = glm::perspective(glm::radians(90.f), 1.f, 0.1f, 10.f);
49 glm::mat4 captureViews[] = {
50 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 1, 0, 0), glm::vec3(0, -1, 0)),
51 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3(-1, 0, 0), glm::vec3(0, -1, 0)),
52 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0, 1, 0), glm::vec3(0, 0, 1)),
53 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0, -1, 0), glm::vec3(0, 0, -1)),
54 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0, 0, 1), glm::vec3(0, -1, 0)),
55 glm::lookAt(glm::vec3(0, 0, 0), glm::vec3( 0, 0, -1), glm::vec3(0, -1, 0))
58 glUniform1i(glGetUniformLocation(equiProg.progId, "equirectangularMap"), 0);
59 glUniformMatrix4fv(glGetUniformLocation(equiProg.progId, "projection"), 1, GL_FALSE, glm::value_ptr(captureProj));
60 glActiveTexture(GL_TEXTURE0);
61 glBindTexture(GL_TEXTURE_2D, hdrTexId);
63 glViewport(0, 0, 512, 512);
64 glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
65 for (GLuint i = 0; i < 6; i++) {
66 glUniformMatrix4fv(glGetUniformLocation(equiProg.progId, "view"), 1, GL_FALSE, glm::value_ptr(captureViews[i]));
67 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cubemapTexId, 0);
68 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
69 glDrawArrays(GL_TRIANGLES, 0, 36);
72 // setup irradiance map texture
73 glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceTexId);
74 for (GLuint i = 0; i < 6; i++)
75 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 32, 32, 0, GL_RGB, GL_FLOAT, nullptr);
76 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
77 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
78 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
79 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
80 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
82 // bind framebuffers for rendering irradiance map into
83 glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
84 glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
85 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 32, 32);
87 Program irradianceProg("skyboxvert.glsl", "irradiancefrag.glsl");
88 glUseProgram(irradianceProg.progId);
89 glUniform1i(glGetUniformLocation(irradianceProg.progId, "environmentMap"), 0);
90 glUniformMatrix4fv(glGetUniformLocation(irradianceProg.progId, "projection"), 1, GL_FALSE, glm::value_ptr(captureProj));
91 glActiveTexture(GL_TEXTURE0);
92 glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexId);
95 setupCubeVertices(irradianceProg.progId);
97 // render irradiance map
98 glViewport(0, 0, 32, 32);
99 glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
100 for (GLuint i = 0; i < 6; i++) {
101 glUniformMatrix4fv(glGetUniformLocation(irradianceProg.progId, "view"), 1, GL_FALSE, glm::value_ptr(captureViews[i]));
102 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, irradianceTexId, 0);
103 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
104 glDrawArrays(GL_TRIANGLES, 0, 36);
107 // switch back to regular skybox shader
108 glUseProgram(program.progId);
109 glDepthFunc(GL_LEQUAL);
111 // reverse so facing inside out
112 vao = setupCubeVertices(program.progId, true);
114 // restore default framebuffer
115 glBindFramebuffer(GL_FRAMEBUFFER, 0);
118 void Skybox::draw(glm::mat4 proj, glm::mat4 view) const {
119 glUseProgram(program.progId);
121 glBindVertexArray(vao);
123 GLuint projLoc = glGetUniformLocation(program.progId, "projection");
124 glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
126 GLuint viewLoc = glGetUniformLocation(program.progId, "view");
127 view = glm::mat4(glm::mat3(view));
128 glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
130 glActiveTexture(GL_TEXTURE0);
131 glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceTexId);
132 glDrawArrays(GL_TRIANGLES, 0, 36);
134 if (glGetError()) exit(1);
137 GLuint setupCubeVertices(GLuint progId, bool reverse) {
139 glGenVertexArrays(1, &vao);
140 glBindVertexArray(vao);
143 glGenBuffers(1, &vbo);
145 auto vertices = cube();
148 std::reverse(vertices.begin(), vertices.end());
150 glBindBuffer(GL_ARRAY_BUFFER, vbo);
151 glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
153 GLuint posLoc = glGetAttribLocation(progId, "pos");
154 glEnableVertexAttribArray(posLoc);
155 glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);