From 205fb2da8c7ad7f0684734bfd238b67d4640c265 Mon Sep 17 00:00:00 2001 From: lenn Date: Tue, 24 Feb 2026 17:29:48 +0800 Subject: [PATCH] update --- camera.h | 2 +- main.cpp | 136 +++++++++++++++++++++++++++++++++++++++----- shader/heatmap.frag | 27 +++++++++ shader/heatmap.vert | 28 +++++++++ shader/panel.frag | 29 ++++++++++ shader/panel.vert | 19 +++++++ 6 files changed, 227 insertions(+), 14 deletions(-) create mode 100644 shader/heatmap.frag create mode 100644 shader/heatmap.vert create mode 100644 shader/panel.frag create mode 100644 shader/panel.vert diff --git a/camera.h b/camera.h index a6571f2..10d0b95 100644 --- a/camera.h +++ b/camera.h @@ -23,7 +23,7 @@ public: : front_(glm::vec3(0.0f, 0.0f, -1.0f)), yaw_(yaw), pitch_(pitch), position_(position) , worldUp_(up){ zoom_ = 45.0f; - mouseSensitivity_ = 0.1f; + mouseSensitivity_ = 0.08f; moveSpeed_ = 2.5f; updateCameraVectors(); } diff --git a/main.cpp b/main.cpp index fa942ca..52141c5 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,5 @@ #include "lopenglprogram.h" #include "camera.h" -#include -#include #include #include #include @@ -10,6 +8,7 @@ #include #include #include +#include #include @@ -33,6 +32,15 @@ public: if (window_) { glfwMakeContextCurrent(window_.get()); } + if (panelIbo_) { + glDeleteBuffers(1, &panelIbo_); + } + if (panelVbo_) { + glDeleteBuffers(1, &panelVbo_); + } + if (panelVao_) { + glDeleteVertexArrays(1, &panelVao_); + } if (bgVao_) { glDeleteVertexArrays(1, &bgVao_); } @@ -59,7 +67,7 @@ public: #if __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif - window_.reset(glfwCreateWindow(800, 600, "3dviewer", nullptr, nullptr)); + window_.reset(glfwCreateWindow(viewport_.width, viewport_.height, "3dviewer", nullptr, nullptr)); if (!window_) { std::cout << "Failed to create GLFW window" << std::endl; glfwTerminate(); @@ -71,7 +79,9 @@ public: return false; } - glViewport(0, 0, 800, 600); + glViewport(0, 0, viewport_.width, viewport_.height); + glEnable(GL_DEPTH_TEST); + glfwSetInputMode(window_.get(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetWindowUserPointer(window_.get(), this); glfwSetFramebufferSizeCallback(window_.get(), &GLWidget::framebufferSizeCallback); glfwSetCursorPosCallback(window_.get(), &GLWidget::mouseCallback); @@ -83,6 +93,11 @@ public: bgVertShaderPath_ = vp; bgFragShaderPath_ = fp; } + + void setPanelShaderPath(std::string vp, std::string fp) { + panelVertShaderPath_ = vp; + panelFragShaderPath_ = fp; + } private: void initBgGeometry() { if (bgVbo_) { @@ -121,6 +136,10 @@ private: glDeleteVertexArrays(1, &panelVao_); panelVao_ = 0; } + if (panelIbo_) { + glDeleteBuffers(1, &panelIbo_); + panelIbo_ = 0; + } const float y = panelHeight_ * 0.5f; const float x = panelWidth_ * 0.5f; @@ -178,7 +197,22 @@ private: }; glGenVertexArrays(1, &panelVao_); - + glBindVertexArray(panelVao_); + + glGenBuffers(1, &panelVbo_); + glBindBuffer(GL_ARRAY_BUFFER, panelVbo_); + glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); + + glGenBuffers(1, &panelIbo_); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, panelIbo_); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idx), idx, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(V), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(V), (void*)(3 * sizeof(float))); + + glBindVertexArray(0); } bool initBgProgram() { @@ -212,6 +246,35 @@ private: return true; } + bool initPanelProgram() { + auto vshader = std::make_unique(LOpenGLShader::ShaderType::Vertex); + auto fshader = std::make_unique(LOpenGLShader::ShaderType::Fragment); + if (!vshader->compileShaderFromFile(panelVertShaderPath_)) { + std::cout << "Vertex shader compile failed: " << panelVertShaderPath_ << "\n" << vshader->Log() << std::endl; + return false; + } + if (!fshader->compileShaderFromFile(panelFragShaderPath_)) { + std::cout << "Fragment shader compile failed: " << panelFragShaderPath_ << "\n" << fshader->Log() << std::endl; + return false; + } + panelProg_ = std::make_unique(); + if (!panelProg_->addShader(std::move(vshader))) { + std::cout << "Failed to attach vertex shader\n"; + return false; + } + if (!panelProg_->addShader(std::move(fshader))) { + std::cout << "Failed to attach fragment shader\n"; + return false; + } + bool ret = panelProg_->Link(); + if (!ret) { + std::cout << "Failed to link panel program\n"; + return false; + } + + return true; + } + void drawBg() { if (!bgProg_ || !bgVao_ || !bgVbo_) { std::cout << "check !bgProg_ || !bgVao_ || !bgVbo_ failed\n"; @@ -221,14 +284,39 @@ private: bgProg_->setUniformValue("uViewport", glm::vec2(viewport_.width, viewport_.height)); bgProg_->setUniformValue("uMajorStep", 120.0f); bgProg_->setUniformValue("uMinorStep", 24.0f); + bgProg_->setUniformValue("uLightMode", lightMode_); + glDisable(GL_DEPTH_TEST); glBindVertexArray(bgVao_); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); - glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); } + void drawPanel() { + if (!panelProg_ || !panelVao_ || !panelVbo_ || !panelIbo_) { + std:: cout << "check !panelProg_ || !panelVao || !panelVbo || !panelIbo\n"; + return; + } + auto [model, view, projection] = getMVP(); + panelProg_->Use(); + panelProg_->setUniformValue("model", model); + panelProg_->setUniformValue("view", view); + panelProg_->setUniformValue("projection", projection); + panelProg_->setUniformValue("uLightMode", lightMode_); + glBindVertexArray(panelVao_); + glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr); + glBindVertexArray(0); + } + + std::tuple getMVP() { + auto model = glm::mat4(1.0f); + auto view = camera_.getViewMatrix(); + auto projection = glm::perspective(glm::radians(camera_.Zoom()), + (float)viewport_.width / (float)viewport_.height, 0.1f, 100.0f); + return {model, view, projection}; + } + public: void eventLoop() { @@ -239,11 +327,19 @@ public: if (!initBgProgram()) { return; } + initPanelGeometry_(); + if (!initPanelProgram()) { + return; + } while (!glfwWindowShouldClose(window_.get())) { - processInput(window_.get()); + const float now = static_cast(glfwGetTime()); + const float deltaTime = now - lastFrame_; + lastFrame_ = now; + processInput(window_.get(), deltaTime); glClearColor(0.08f, 0.08f, 0.10f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); drawBg(); + drawPanel(); glfwSwapBuffers(window_.get()); glfwPollEvents(); } @@ -263,10 +359,23 @@ private: glViewport(0, 0, width, height); } - void processInput(GLFWwindow* window) { + void processInput(GLFWwindow* window, float deltaTime) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + camera_.keyboardCallback(Camera::FORWARD, deltaTime); + } + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) { + camera_.keyboardCallback(Camera::BACKWARD, deltaTime); + } + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { + camera_.keyboardCallback(Camera::LEFT, deltaTime); + } + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) { + camera_.keyboardCallback(Camera::RIGHT, deltaTime); + } + lightMode_ = glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS; } static void mouseCallback(GLFWwindow* window, double x, double y) { @@ -282,7 +391,6 @@ private: float ypos = static_cast(y); if (camera_.firstMouse()) { - std::cout << "in firstMouse()\n"; lastX_ = x; lastY_ = y; camera_.triggleFirstMouse(); @@ -298,10 +406,8 @@ private: } static void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - std::cout << "scrollCallback\n"; auto* self = static_cast(glfwGetWindowUserPointer(window)); if (!self) { - std::cout << "auto* self = static_cast(glfwGetWindowUserPointer(window)) failed\n"; return; } self->onScrollRoll(xoffset, yoffset); @@ -324,25 +430,29 @@ private: std::string panelFragShaderPath_; unsigned int panelVao_ = 0; unsigned int panelVbo_ = 0; + unsigned int panelIbo_ = 0; float panelWidth_ = 0.25; float panelHeight_ = 0.35; float panelDepth_ = 0.05; ViewPort viewport_{800, 600}; - Camera camera_; + Camera camera_{glm::vec3(0.0f, 0.0f, 2.0f)}; bool firstMouse_ = true; float lastX_; float lastY_; + float lastFrame_ = 0.0f; + bool lightMode_ = false; bool deinit_; }; int main() { { - GLWidget glw({600, 800}); + GLWidget glw({800, 600}); glw.setBgShaderPath("../shader/bg.vert", "../shader/bg.frag"); + glw.setPanelShaderPath("../shader/panel.vert", "../shader/panel.frag"); glw.eventLoop(); } glfwTerminate(); diff --git a/shader/heatmap.frag b/shader/heatmap.frag new file mode 100644 index 0000000..6853c38 --- /dev/null +++ b/shader/heatmap.frag @@ -0,0 +1,27 @@ +#version 330 core +in vec2 vUV; +in vec3 vWorldPos; +out vec4 FragColor; + +uniform sampler2D uHeightTex; +uniform float uMinV; +uniform float uMaxV; +uniform float uHeightScale; +uniform vec2 uTexelSize; +uniform vec2 uPlaneSize; +uniform vec3 uCameraPos; +uniform vec3 uLightDir; +uniform vec3 uColorZero; +uniform vec3 uColorLow; +uniform vec3 uColorMid; +uniform vec3 uColorHigh; + +float saturate(float x) { + return clamp(x, 0.0, 1.0); +} + +float value01(float v) { + return saturate((v - uMinV) / max(uMaxV - uMinV, 1e-6)); +} + +float maxNeighborValue(vec2 uv) \ No newline at end of file diff --git a/shader/heatmap.vert b/shader/heatmap.vert new file mode 100644 index 0000000..4b1c2d2 --- /dev/null +++ b/shader/heatmap.vert @@ -0,0 +1,28 @@ +#version 330 core +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec2 aUV; + +out vec2 vUV; +out vec3 vWorldPos; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; +uniform sampler2D uHeightTex; +uniform float uMinV; +uniform float uMaxV; +uniform float uHeightScale; +uniform float uBaseZ; + +float value01(float v) { + return clamp((v - uMinV) / max(uMaxV - uMinV, 1e-6), 0.0, 1.0); +} + +void main() { + vUV = aUV; + float v = texture(uHeightTex, aUV).r; + float h = value01(v) * uHeightScale; + vec3 world = aPos + vec3(0.0, 0.0, uBaseZ + h); + vWorldPos = world; + gl_Position = projection * view * model * vec4(world, 1.0); +} \ No newline at end of file diff --git a/shader/panel.frag b/shader/panel.frag new file mode 100644 index 0000000..3b71c5a --- /dev/null +++ b/shader/panel.frag @@ -0,0 +1,29 @@ +#version 330 core + +in vec3 vWorldPos; +in vec3 vWorldNormal; + +out vec4 FragColor; +uniform bool uLightMode; + +void main() { + vec3 N = normalize(vWorldNormal); + float isTop = step(0.75, N.y); + + vec3 topBase; + vec3 sideBase; + + if (uLightMode) { + // 浅色主题 偏亮的工业灰 + topBase = vec3(0.78, 0.80, 0.84); + sideBase = vec3(0.68, 0.70, 0.74); + } + else { + // 深色主题 偏暗的工业灰 + topBase = vec3(0.30, 0.31, 0.32); + sideBase = vec3(0.27, 0.28, 0.29); + } + + vec3 baseColor = mix(sideBase, topBase, isTop); + FragColor = vec4(clamp(baseColor, 0.0, 1.0), 1.0); +} \ No newline at end of file diff --git a/shader/panel.vert b/shader/panel.vert new file mode 100644 index 0000000..bd572d0 --- /dev/null +++ b/shader/panel.vert @@ -0,0 +1,19 @@ +#version 330 core + +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec3 aN; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +out vec3 vWorldPos; +out vec3 vWorldNormal; + +void main() { + vec4 worldPos = model * vec4(aPos, 1.0); + mat3 normalMat = transpose(inverse(mat3(model))); + vWorldPos = worldPos.xyz; + vWorldNormal = normalize(normalMat * aN); + gl_Position = projection * view * worldPos; +}