diff --git a/.clangd b/.clangd index 9dcba43..4ae1f41 100644 --- a/.clangd +++ b/.clangd @@ -1,6 +1,3 @@ -If: - OS: Windows - CompileFlags: Add: --target=x86_64-w64-mingw32 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index c456333..436c9df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,4 +43,6 @@ elseif(UNIX) ) endif() - +if (WIN32) + add_compile_options(--target=x86_64-w64-mingw32) +endif() diff --git a/main.cpp b/main.cpp index 0762b3b..d3d6730 100644 --- a/main.cpp +++ b/main.cpp @@ -58,6 +58,15 @@ public: if (heatmapIbo_) { glDeleteBuffers(1, &heatmapIbo_); } + if (skirtVao_) { + glDeleteVertexArrays(1, &skirtVao_); + } + if (skirtVbo_) { + glDeleteBuffers(1, &skirtVbo_); + } + if (skirtIbo_) { + glDeleteBuffers(1, &skirtIbo_); + } deinit_ = true; } @@ -301,6 +310,80 @@ private: glBindVertexArray(0); } + void initSkirtGeometry_() { + if (skirtIbo_) { + glDeleteBuffers(1, &skirtIbo_); + skirtIbo_ = 0; + } + if (skirtVao_) { + glDeleteVertexArrays(1, &skirtVao_); + skirtVao_ = 0; + } + if (skirtVbo_) { + glDeleteBuffers(1, &skirtVbo_); + skirtVbo_ = 0; + } + + skirtUVs.clear(); + skirtNormals.clear(); + const int cols = std::max(2, heatmapcols_); + const int rows = std::max(2, heatmaprows_); + + auto push_border = [&](int c, int r, const glm::vec3& n) { + const float u = (cols > 1) ? float(c) / float(cols - 1) : 0.0F; + const float v = (rows > 1) ? float(r) / float(rows - 1) : 0.0F; + skirtUVs.push_back(glm::vec2(u, v)); + skirtNormals.push_back(n); + }; + + for (int c = 0; c < cols; ++c) { + push_border(c, 0, glm::vec3(0.0F, -1.0F, 0.0F)); + } + for (int r = 1; r < rows; ++r) { + push_border(cols - 1, r, glm::vec3(1.0F, 0.0F, 0.0F)); + } + for (int c = cols -1; c >= 0; --c) { + push_border(c, rows - 1, glm::vec3(0.0F, 1.0F, 0.0F)); + } + for (int r = rows - 2; r >= 1; --r) { + push_border(0, r, glm::vec3(-1.0F, 0.0F, 0.0F)); + } + + const int border_count = skirtUVs.size(); + // TODO: fill + // std::vector verts; + // verts.assign(border_count * 2 * 8, 0.0F); + skirtVertices.assign(border_count * 8 * 2, 0.0F); + + std::vector idx; + idx.reserve(border_count * 6); + for (int i = 0; i < border_count; ++i) { + unsigned int next = (i + 1) % border_count; + const unsigned int top0 = unsigned(i * 2); + const unsigned int bot0 = unsigned(i * 2 + 1); + const unsigned int top1 = unsigned(next * 2); + const unsigned int bot1 = unsigned(next * 2 + 1); + idx.push_back(top0); + idx.push_back(top1); + idx.push_back(bot1); + + idx.push_back(top0); + idx.push_back(bot0); + idx.push_back(bot1); + } + skirtIndexCount_ = static_cast(idx.size()); + + glGenVertexArrays(1, &skirtVao_); + glBindVertexArray(skirtVao_); + + glGenBuffers(1, &skirtVbo_); + glBindBuffer(GL_ARRAY_BUFFER, skirtVbo_); + glBufferData(GL_ARRAY_BUFFER, skirtVertices.size() * sizeof(float), skirtVertices.data(), GL_STATIC_DRAW); + + glGenBuffers(1, &skirtIbo_); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, skirtIbo_); + } + bool initBgProgram() { auto vshader = std::make_unique(LOpenGLShader::ShaderType::Vertex); auto fshader = std::make_unique(LOpenGLShader::ShaderType::Fragment); @@ -560,6 +643,17 @@ private: unsigned int heatmapIbo_ = 0; int heatmapIndexCount = 0; + std::unique_ptr skirtProg_; + std::string skirtVertShaderPath_; + std::string skirtFragShaderPath_; + unsigned int skirtVao_ = 0; + unsigned int skirtVbo_ = 0; + unsigned int skirtIbo_ = 0; + std::vector skirtUVs; + std::vector skirtNormals; + int skirtIndexCount_ = 0; + std::vector skirtVertices; + ViewPort viewport_{800, 600}; Camera camera_{glm::vec3(0.0F, 0.0F, 2.0F)}; diff --git a/shader/skirt.frag b/shader/skirt.frag index 4226f05..3ec552b 100644 --- a/shader/skirt.frag +++ b/shader/skirt.frag @@ -33,5 +33,51 @@ vec3 colorRamp(float t) { } float maxNeighborValue(vec2 uv) { - + vec2 texelSizeF = 1.0 / uTexelSize; + ivec2 texelSizeI = ivec2(max(1.0, floor(uTexelSize + 0.5))); + ivec2 maxCoord = texelSizeI - 1; + + vec2 texelF = vec2(clamp(uv * maxCoord, vec2(0.0), vec2(maxCoord))); + ivec2 base = ivec2(floor(texelF)); + ivec2 base10 = min(base + ivec2(1, 0), maxCoord); + ivec2 base01 = min(base + ivec2(0, 1), maxCoord); + ivec2 base11 = min(base + ivec2(1, 1), maxCoord); + + float v00 = texelFetch(uColorHeigh, base, 0).r; + float v10 = texelFetch(uColorHeigh, base10, 0).r; + float v01 = texelFetch(uColorHeigh, base01, 0).r; + float v11 = texelFetch(uColorHeigh, base11, 0).r; + + return max(max(v00, v10), max(v01, v11)); +} + +vec3 colorRampWithZero(float t) { + const float zeroW = 0.005; + float blend = smoothstep(0.0, zeroW, t); + float tRamp = saturate(t - zeroW) / max(1.0 - zeroW, 1e-6); + vec3 ramp = colorRamp(tRamp); + return mix(uColorZero, ramp, blend); +} + +void main() { + vec3 N = normalize(vNormal); + vec3 L = normalize(uLightDir); + vec3 V = normalize(uCameraPos - vWorldPos); + vec3 H = normalize(L + V); + + float diff = saturate(dot(N, L)); + float spec = pow(saturate(dot(N, H)), 24.0); + + float vC = texture(uHeightTex, vUV).r; + bool isZero = abs(vC) <= 1e-6; + float t = value01(vC); + float m = maxNeighborValue(vUV); + float eps = max(1e-4, 0.001 * (uMaxV - uMinV)); + float force = smoothstep(uMaxV - eps, uMaxV, m); + t = max(t, force); + vec3 base = isZero ? uColorZero : colorRampWithZero(t); + + vec3 col = base * (0.35 + 0.65 * diff); + col += vec3(1.0) * spec * 0.10; + FragColor = vec4(clamp(col, 0.0, 1.0), 1.0); } \ No newline at end of file