diff --git a/.gitmodules b/.gitmodules index aab1040..4efe3c6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "external/glm"] path = external/glm url = https://github.com/g-truc/glm +[submodule "external/stb"] + path = external/stb + url = https://github.com/nothings/stb diff --git a/prefilter/genie.lua b/prefilter/genie.lua new file mode 100644 index 0000000..1763444 --- /dev/null +++ b/prefilter/genie.lua @@ -0,0 +1,27 @@ +solution "prefilter" + configurations { "Debug", "Release" } + + project "prefilter" + kind "ConsoleApp" + language "C++" + files { "**.h", "**.cpp", "**.c" } + + includedirs { + "../external/CImg", + "../external/glm", + "../external/stb" + } + + defines { + "cimg_display=0" + } + + configuration "Debug" + targetdir "bin" + defines { "DEBUG" } + flags { "Symbols" } + + configuration "Release" + targetdir "bin" + defines { "NDEBUG" } + flags { "Optimize" } diff --git a/prefilter/prefilterAreaLight.cpp b/prefilter/prefilterAreaLight.cpp new file mode 100644 index 0000000..4bf660e --- /dev/null +++ b/prefilter/prefilterAreaLight.cpp @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include +#include +using namespace std; + +#include "CImg.h" +using namespace cimg_library; + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" + +void filter(CImg& imageInput, CImg& imageOutput, const int level, const int Nlevels) +{ + // distance to texture plane + // in shader: LOD = log(powf(2.0f, Nlevels - 1.0f) * dist) / log(3) + const float dist = powf(3.0f, level) / powf(2.0f, Nlevels - 1.0f); + + // filter size + // at distance 1 ~= Gaussian of std 0.75 + const float filterStd = 0.75f * dist * imageInput.width(); + + cout << "level " << level << endl; + cout << "distance to texture plane = " << dist << endl; + cout << "filterStd = " << filterStd << endl << endl; + + CImg tmp(imageInput.width(), imageInput.height(), 1, 4); + + for (int j = 0; j < imageInput.height(); ++j) + for (int i = 0; i < imageInput.width(); ++i) + { + tmp(i, j, 0, 0) = imageInput(i, j, 0, 0); + tmp(i, j, 0, 1) = imageInput(i, j, 0, 1); + tmp(i, j, 0, 2) = imageInput(i, j, 0, 2); + tmp(i, j, 0, 3) = 1.0f; + } + + tmp.blur(filterStd, filterStd, filterStd, false); + + // renormalise based on alpha + for (int j = 0; j < imageInput.height(); ++j) + for (int i = 0; i < imageInput.width(); ++i) + { + float alpha = tmp(i, j, 0, 3); + for (int k = 0; k < tmp.spectrum(); ++k) + tmp(i, j, 0, k) /= alpha; + } + + // rescale image + imageOutput = tmp.resize(imageOutput, 5); // 5 = cubic interpolation +} + +// Adapted from https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_texture_shared_exponent.txt +//////// +#define RGB9E5_EXPONENT_BITS 5 +#define RGB9E5_MANTISSA_BITS 9 +#define RGB9E5_EXP_BIAS 15 +#define RGB9E5_MAX_VALID_BIASED_EXP 31 + +#define MAX_RGB9E5_EXP (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS) +#define RGB9E5_MANTISSA_VALUES (1< 0.0) + { + if (x >= MAX_RGB9E5) + return MAX_RGB9E5; + } + else + { + /* NaN gets here too since comparisons with NaN always fail! */ + return 0.0f; + } + + return x; +} + +float Max(float a, float b) +{ + return a >= b ? a : b; +} + +float MaxOf3(float x, float y, float z) +{ + return Max(Max(x, y), z); +} + +/* Ok, FloorLog2 is not correct for the denorm and zero values, but we + are going to do a max of this value with the minimum rgb9e5 exponent + that will hide these problem cases. */ +int FloorLog2(float x) +{ + float754 f; + + f.value = x; + return (f.field.biasedexponent - 127); +} + +int Max(int x, int y) +{ + if (x > y) { + return x; + } else { + return y; + } +} + +rgb9e5 float3_to_rgb9e5(const float r, const float g, const float b) +{ + rgb9e5 retval; + float maxrgb; + int rm, gm, bm; + float rc, gc, bc; + int exp_shared; + double denom; + + rc = ClampRange_for_rgb9e5(r); + gc = ClampRange_for_rgb9e5(g); + bc = ClampRange_for_rgb9e5(b); + + maxrgb = MaxOf3(rc, gc, bc); + exp_shared = Max(-RGB9E5_EXP_BIAS-1, FloorLog2(maxrgb)) + 1 + RGB9E5_EXP_BIAS; + assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP); + assert(exp_shared >= 0); + /* This pow function could be replaced by a table. */ + denom = pow(2, exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS); + + int maxm = (int) floor(maxrgb / denom + 0.5f); + if (maxm == MAX_RGB9E5_MANTISSA+1) { + denom *= 2; + exp_shared += 1; + assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP); + } else { + assert(maxm <= MAX_RGB9E5_MANTISSA); + } + + rm = (int) floor(rc / denom + 0.5); + gm = (int) floor(gc / denom + 0.5); + bm = (int) floor(bc / denom + 0.5); + + assert(rm <= MAX_RGB9E5_MANTISSA); + assert(gm <= MAX_RGB9E5_MANTISSA); + assert(bm <= MAX_RGB9E5_MANTISSA); + assert(rm >= 0); + assert(gm >= 0); + assert(bm >= 0); + + retval.field.r = rm; + retval.field.g = gm; + retval.field.b = bm; + retval.field.biasedexponent = exp_shared; + + return retval; +} +//////// + +int main(int argc, char* argv[]) +{ + // Skip executable argument + argc--; + argv++; + + if (argc < 1) + { + printf("Syntax: \n"); + return 0; + } + + string filenameInput(argv[0]); + size_t pos = filenameInput.find_last_of("."); + string filename = filenameInput.substr(0, pos); + string extension = filenameInput.substr(pos + 1, string::npos); + + // input image + int x, y, n; + float* data = stbi_loadf(filenameInput.c_str(), &x, &y, &n, 3); + + int offset = 0; + CImg imageInput(x, y, 1, 3); + for (int j = 0; j < y; ++j) + for (int i = 0; i < x; ++i) + { + for (int k = 0; k < imageInput.spectrum(); ++k) + imageInput(i, j, 0, k) = data[offset++]; + } + + // filtered levels + //unsigned int Nlevels; + //for (Nlevels = 1; (imageInput.width() >> Nlevels) > 0; ++Nlevels); + + // Beyond 8 levels, the result is ~= a constant colour + // so pretend we have 12 levels, but truncate at 8 + const unsigned int Nlevels = 12; + const unsigned int maxLevels = 8; + + uint32_t* dataOut = new uint32_t[x * y]; + + // borders + for (unsigned int level = 0; level < maxLevels; ++level) + { + stringstream filenameOutput(stringstream::in | stringstream::out); + filenameOutput << filename << "_" << level << ".png"; + + cout << "processing file " << filenameOutput.str() << endl; + + CImg imageOutput(x, y, 1, 4); + filter(imageInput, imageOutput, level, Nlevels); + + offset = 0; + for (int j = 0; j < y; ++j) + for (int i = 0; i < x; ++i) + { + float r = imageOutput(i, j, 0, 0); + float g = imageOutput(i, j, 0, 1); + float b = imageOutput(i, j, 0, 2); + + rgb9e5 value = float3_to_rgb9e5(r, g, b); + dataOut[offset++] = value.raw; + } + + stbi_write_png(filenameOutput.str().c_str(), x, y, 4, dataOut, 0); + } + + delete[] dataOut; + + return 0; +} diff --git a/webgl/images/stained_glass_0.png b/webgl/images/stained_glass_0.png new file mode 100644 index 0000000..3203879 Binary files /dev/null and b/webgl/images/stained_glass_0.png differ diff --git a/webgl/images/stained_glass_1.png b/webgl/images/stained_glass_1.png new file mode 100644 index 0000000..c792274 Binary files /dev/null and b/webgl/images/stained_glass_1.png differ diff --git a/webgl/images/stained_glass_2.png b/webgl/images/stained_glass_2.png new file mode 100644 index 0000000..a32c28c Binary files /dev/null and b/webgl/images/stained_glass_2.png differ diff --git a/webgl/images/stained_glass_3.png b/webgl/images/stained_glass_3.png new file mode 100644 index 0000000..d558070 Binary files /dev/null and b/webgl/images/stained_glass_3.png differ diff --git a/webgl/images/stained_glass_4.png b/webgl/images/stained_glass_4.png new file mode 100644 index 0000000..968c986 Binary files /dev/null and b/webgl/images/stained_glass_4.png differ diff --git a/webgl/images/stained_glass_5.png b/webgl/images/stained_glass_5.png new file mode 100644 index 0000000..5636279 Binary files /dev/null and b/webgl/images/stained_glass_5.png differ diff --git a/webgl/images/stained_glass_6.png b/webgl/images/stained_glass_6.png new file mode 100644 index 0000000..6f9d1cd Binary files /dev/null and b/webgl/images/stained_glass_6.png differ diff --git a/webgl/images/stained_glass_7.png b/webgl/images/stained_glass_7.png new file mode 100644 index 0000000..5fda949 Binary files /dev/null and b/webgl/images/stained_glass_7.png differ diff --git a/webgl/ltc_quad.html b/webgl/ltc_quad.html index fb9f254..1029143 100644 --- a/webgl/ltc_quad.html +++ b/webgl/ltc_quad.html @@ -64,7 +64,6 @@ -