From 724a80cbecb587d1d069f7999758181b10d92f73 Mon Sep 17 00:00:00 2001 From: Luke Lau Date: Mon, 13 Apr 2020 14:23:44 +0100 Subject: [PATCH] First pass at PBO Turned off because its actually a bit slower --- clouds.cpp | 122 ++++++++++++++++++++++++++++++++----------------- program.cpp | 2 + program.hpp | 2 +- simulation.cpp | 8 +--- simulation.h | 6 +++ 5 files changed, 91 insertions(+), 49 deletions(-) diff --git a/clouds.cpp b/clouds.cpp index 3ed3b10..f6c0083 100644 --- a/clouds.cpp +++ b/clouds.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -14,13 +15,7 @@ #pragma clang diagnostic ignored "-Wdeprecated-declarations" -enum Mode { - render, - debugContDist, - debugColor, - debugProbExt, - debugProbAct -}; +enum Mode { render, debugContDist, debugColor, debugProbExt, debugProbAct }; Mode curMode = render; using namespace std; @@ -68,7 +63,7 @@ void precalculateBillboardTextures() { float r = distance(vec2(i, j), vec2(16, 16)) / 16; float density = (float)d / NQ; data[i + j * 32] = - 1 - (density * 0.7 * (metaballField(r) / normalizationFactor)); + 1 - (3 * density * 0.7 * (metaballField(r) / normalizationFactor)); } } @@ -82,7 +77,6 @@ void precalculateBillboardTextures() { glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, 32, 32, 0, GL_RED, GL_FLOAT, data); glGenerateMipmap(GL_TEXTURE_2D); // required, otherwise texture is blank - fprintf(stderr, "\r%i out of %i densities calculated%s", d + 1, NQ, d == NQ - 1 ? "\n" : ""); } @@ -115,9 +109,7 @@ void calculateMetaballs() { for (int i = 0; i < CLOUD_DIM_X; i++) { for (int j = 0; j < CLOUD_DIM_Y; j++) { for (int k = 0; k < CLOUD_DIM_Z; k++) { - Metaball m = { - vec3(i, j, k) * vec3(cloudScale), - {i, j, k} }; + Metaball m = {vec3(i, j, k) * vec3(cloudScale), {i, j, k}}; /* m.pos = (m.pos * vec3(2)) - (cloudScale / 2); */ m.pos -= vec3(CLOUD_DIM_X, CLOUD_DIM_Y, CLOUD_DIM_Z) * cloudScale / 2.f; m.d = cs.q[i][j][k]; @@ -127,20 +119,22 @@ void calculateMetaballs() { } } /* for (int z = 0; z < CLOUD_DIM_Z; z++) */ - /* metaballs[32 * CLOUD_DIM_Y * CLOUD_DIM_Z + 32 * CLOUD_DIM_Z + z].d = 1; */ + /* metaballs[32 * CLOUD_DIM_Y * CLOUD_DIM_Z + 32 * CLOUD_DIM_Z + z].d = 1; + */ } vec3 sunPos = {0, 10, 0}, sunDir = {0, -1, 0}; -size_t sunColorIdx = 0; -std::array sunColors = { - vec4(1,1,1,1), - vec4(0.988,0.309,0.677,1) -}; -vec3 camPos = {0, 0, -5}, viewPos = {0, 0, 0}; +size_t envColorIdx = 0; +// First color is sun color, second is sky color +std::array, 3> envColors{ + {{vec4(1, 1, 1, 1), vec4(0.9, 1, 1, 1)}, + {vec4(0.939, 0.632, 0.815, 1), vec4(0.9, 1, 1, 1)}, + {vec4(0.999, 0.999, 0.519, 1), vec4(0.981, 0.667, 0.118, 1)}}}; +vec3 camPos = {0, 0, -3}, viewPos = {0, 0, 0}; mat4 proj; // projection matrix mat4 view; // view matrix float znear = 0.001, zfar = 1000; -float width = 600, height = 400; +float width = 512, height = 512; float aspect = width / height; void setProjectionAndViewUniforms(GLuint progId) { @@ -166,7 +160,11 @@ mat4 faceView(mat4 m) { return m; } -GLuint attenuationTex; +#ifdef PBO +const int numPbos = 64; +GLuint pboBufs[numPbos]; +GLbyte sink[1000 * 1000 * 4]; +#endif void shadeClouds() { glDisable(GL_DEPTH_TEST); @@ -185,16 +183,16 @@ void shadeClouds() { GLuint modelLoc = glGetUniformLocation(bbProg, "model"); glUniform1i(glGetUniformLocation(bbProg, "debug"), 0); - /* GLuint pboBuf; */ - /* glGenBuffers(1, &pboBuf); */ - /* glBindBuffer(GL_PIXEL_PACK_BUFFER, pboBuf); */ - /* glViewport(0, 0, shadeWidth, shadeHeight); */ +#ifdef PBO + int pboIdx = 0; +#endif + auto begin_time = std::chrono::system_clock::now(); size_t i = 0; for (auto &k : metaballs) { - fprintf(stderr, "\rShading cloud %lu/%lu...", i++, metaballs.size()); + fprintf(stderr, "\rShading metaball %lu/%lu...", i++, metaballs.size()); // place the billboard at the center of k mat4 model = translate(mat4(1), k.pos); @@ -225,22 +223,47 @@ void shadeClouds() { // 1. First get position in opengl screen space: from [-1,1] // 2. Normalize to [0,1] // 3. Multiply by (width * height) - vec2 screenPos = + ivec2 screenPos = ((vec2(proj * view * model * vec4(0, 0, 0, 1)) + vec2(1)) / vec2(2)) * vec2(width, height); vec4 pixel; + +#ifndef PBO // TODO: This is a huge bottleneck - glReadPixels(screenPos.x, screenPos.y, 1, 1, GL_RGBA, GL_FLOAT, - value_ptr(pixel)); + glReadPixels(screenPos.x, screenPos.y, 1, 1, GL_RGBA, GL_FLOAT, &pixel); +#else + + glBindBuffer(GL_PIXEL_PACK_BUFFER, pboBufs[pboIdx]); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, + NULL); + + glBindBuffer(GL_PIXEL_PACK_BUFFER, pboBufs[(pboIdx + 1) % numPbos]); + GLuint offset = screenPos.x * 4 + screenPos.y * (int)width * 4; + ivec4 *src = (ivec4 *)glMapBufferRange(GL_PIXEL_PACK_BUFFER, offset, 4, GL_MAP_READ_BIT); + checkError(); + if (src) { + ivec4 t = src[(int)screenPos.x + (int)screenPos.y * (int)width]; + pixel = vec4(t) / vec4(255.f); + } + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + + pboIdx = (pboIdx + 1) % numPbos; + + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); +#endif // Multiply the pixel value by the sunlight color. - pixel *= sunColors[sunColorIdx % sunColors.size()]; + pixel *= envColors[envColorIdx][0]; // Store the color into an array C[k] as the color of the billboard. k.col = pixel; } fprintf(stderr, "\n"); + auto elapsed = std::chrono::system_clock::now() - begin_time; + double elapsed_seconds = std::chrono::duration_cast >(elapsed).count(); + fprintf(stderr, "time with pbo: %f\n", elapsed_seconds); + saveFBO(); checkError(); /* glViewport(0, 0, width, height); */ @@ -253,7 +276,8 @@ void renderObject() { mat4 model = translate(mat4(1), sunPos); /* model = lookAt(sunPos, sunPos + sunDir, {0, 1, 0}) * model; */ model = translate(scale(translate(model, -sunPos), vec3(0.3)), sunPos); - glUniformMatrix4fv(glGetUniformLocation(sunProg, "model"), 1, GL_FALSE, glm::value_ptr(model)); + glUniformMatrix4fv(glGetUniformLocation(sunProg, "model"), 1, GL_FALSE, + glm::value_ptr(model)); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); } @@ -273,7 +297,8 @@ void renderClouds() { glBlendFunc(GL_ONE, GL_SRC_ALPHA); /* glBlendColor(1.f,1.f,1.f,1.f); */ - /* glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_SRC_ALPHA); */ + /* glBlendFuncSeparate(GL_ONE, GL_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_SRC_ALPHA); + */ glActiveTexture(GL_TEXTURE0); glUniform1i(glGetUniformLocation(bbProg, "tex"), 0); @@ -304,12 +329,16 @@ void renderClouds() { // Don't modulate it -- blend it glUniform1i(glGetUniformLocation(bbProg, "modulate"), 0); - glUniform1f(glGetUniformLocation(bbProg, "debugColor"), curMode == debugColor); + glUniform1f(glGetUniformLocation(bbProg, "debugColor"), + curMode == debugColor); if (curMode != render) { float debugVal = 0; - if (curMode == debugContDist) debugVal = k.d; - else if (curMode == debugProbAct) debugVal = cs.p_act[k.coords.x][k.coords.y][k.coords.z]; - else if (curMode == debugProbExt) debugVal = cs.p_ext[k.coords.x][k.coords.y][k.coords.z]; + if (curMode == debugContDist) + debugVal = k.d; + else if (curMode == debugProbAct) + debugVal = cs.p_act[k.coords.x][k.coords.y][k.coords.z] / P_ACT; + else if (curMode == debugProbExt) + debugVal = cs.p_ext[k.coords.x][k.coords.y][k.coords.z] / P_EXT; glUniform1f(glGetUniformLocation(bbProg, "debugVal"), debugVal); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); model = scale(model, vec3(0.2)); @@ -344,7 +373,9 @@ void display() { glUseProgram(bbProg); setProjectionAndViewUniforms(bbProg); - glClearColor(0.83, 1, 1, 1); // background color + vec4 skyColor = envColors[envColorIdx][1]; + glClearColor(skyColor.r, skyColor.g, skyColor.b, + skyColor.a); // background color glClear(GL_COLOR_BUFFER_BIT); renderObject(); // render things that aren't clouds renderClouds(); @@ -390,7 +421,7 @@ void keyboard(unsigned char key, int x, int y) { needsRedisplay = true; } if (key == 's') { - sunColorIdx++; + envColorIdx = (envColorIdx + 1) % envColors.size(); needsRedisplay = true; needsReshading = true; } @@ -424,7 +455,7 @@ void passiveMotion(int x, int y) { int main(int argc, char **argv) { glutInit(&argc, argv); - glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB | + glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_3_2_CORE_PROFILE); glutInitWindowSize(width, height); glutCreateWindow("Clouds"); @@ -466,14 +497,21 @@ int main(int argc, char **argv) { initClouds(&cs); calculateMetaballs(); - glGenTextures(1, &attenuationTex); - glutKeyboardFunc(keyboard); glutMotionFunc(motion); glutPassiveMotionFunc(passiveMotion); glutTimerFunc(16, timer, 0); - // set up billboard prog +#ifdef PBO + // setup PBOs for buffering readPixels + glGenBuffers(numPbos, pboBufs); + for (int i = 0; i < numPbos; i++) { + glBindBuffer(GL_PIXEL_PACK_BUFFER, pboBufs[i]); + glBufferData(GL_PIXEL_PACK_BUFFER, width * height * 4, NULL, + GL_DYNAMIC_READ); + } + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); +#endif glutMainLoop(); diff --git a/program.cpp b/program.cpp index 2275dcb..deb068b 100644 --- a/program.cpp +++ b/program.cpp @@ -3,6 +3,8 @@ #include #include +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + using namespace std; void attachShader(GLuint progId, string filePath, GLenum type) { diff --git a/program.hpp b/program.hpp index 3fa8879..ae3eb3f 100644 --- a/program.hpp +++ b/program.hpp @@ -1,7 +1,7 @@ #ifndef PROGRAM_HPP #define PROGRAM_HPP #include -#include +#include class Program { public: Program(const std::string vert, const std::string frag); diff --git a/simulation.cpp b/simulation.cpp index 4e107e7..33b58de 100644 --- a/simulation.cpp +++ b/simulation.cpp @@ -15,17 +15,13 @@ inline void set(float x[CLOUD_DIM_X][CLOUD_DIM_Y][CLOUD_DIM_Z], int i, int j, in x[i][j][k] = y; } -#define P_EXT 0.1 -#define P_HUM 0.1 -#define P_ACT 0.001 - void initClouds(Clouds *cs) { for (int i = 0; i < CLOUD_DIM_X; i++) { for (int j = 0; j < CLOUD_DIM_Y; j++) { for (int k = 0; k < CLOUD_DIM_Z; k++) { cs->act[i][j][k] = randf() < 0.01; cs->cld[i][j][k] = false; - cs->hum[i][j][k] = randf() < 0.1; + cs->hum[i][j][k] = randf() < 0.01; cs->p_ext[i][j][k] = 0.f; cs->p_hum[i][j][k] = 0.f; cs->p_act[i][j][k] = 0.f; @@ -46,7 +42,7 @@ void initClouds(Clouds *cs) { cs->vz[k] = floor(randf() * 3); // generate ellipsoids of probability - const int numEllipsoids = CLOUD_DIM_X * CLOUD_DIM_Y * CLOUD_DIM_Z * 0.002; + const int numEllipsoids = CLOUD_DIM_X * CLOUD_DIM_Y * CLOUD_DIM_Z * 0.001; for (int n = 0; n < numEllipsoids; n++) { const float maxSize = 8, minSize = 4; float delta = maxSize - minSize; diff --git a/simulation.h b/simulation.h index ef53425..1985ee3 100644 --- a/simulation.h +++ b/simulation.h @@ -1,9 +1,15 @@ #define CLOUD_DIM_X 64 #define CLOUD_DIM_Y 16 #define CLOUD_DIM_Z 64 + /* #define CLOUD_DIM_X 16 */ /* #define CLOUD_DIM_Y 16 */ /* #define CLOUD_DIM_Z 16 */ + +#define P_EXT 0.1 +#define P_HUM 0.1 +#define P_ACT 0.001 + struct Clouds { // TODO: make more efficient bool hum[CLOUD_DIM_X][CLOUD_DIM_Y][CLOUD_DIM_Z]; -- 2.30.2