From 9602aa96c0fe1f0164f46f10d26791a9eefb00d9 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Sat, 12 Apr 2025 23:48:13 +0200 Subject: [PATCH] feat(rendering): basic outline feature --- assets/shaders/outline.fs | 11 +++ assets/shaders/outline.vs | 15 +++++ assets/shaders/wireframe.fs | 11 +++ assets/shaders/wireframe.vs | 15 +++++ core/src/rendering/renderer.cpp | 116 +++++++++++++++++++++++++++++++- core/src/rendering/renderer.h | 2 + editor/mainwindow.cpp | 15 +++++ 7 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 assets/shaders/outline.fs create mode 100644 assets/shaders/outline.vs create mode 100644 assets/shaders/wireframe.fs create mode 100644 assets/shaders/wireframe.vs diff --git a/assets/shaders/outline.fs b/assets/shaders/outline.fs new file mode 100644 index 0000000..53ee504 --- /dev/null +++ b/assets/shaders/outline.fs @@ -0,0 +1,11 @@ +#version 330 core + +out vec4 FragColor; + +uniform vec3 color; + +// Main + +void main() { + FragColor = vec4(color, 1); +} \ No newline at end of file diff --git a/assets/shaders/outline.vs b/assets/shaders/outline.vs new file mode 100644 index 0000000..52ee47b --- /dev/null +++ b/assets/shaders/outline.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; + +out vec3 vPos; +out vec3 vNormal; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); +} diff --git a/assets/shaders/wireframe.fs b/assets/shaders/wireframe.fs new file mode 100644 index 0000000..53ee504 --- /dev/null +++ b/assets/shaders/wireframe.fs @@ -0,0 +1,11 @@ +#version 330 core + +out vec4 FragColor; + +uniform vec3 color; + +// Main + +void main() { + FragColor = vec4(color, 1); +} \ No newline at end of file diff --git a/assets/shaders/wireframe.vs b/assets/shaders/wireframe.vs new file mode 100644 index 0000000..52ee47b --- /dev/null +++ b/assets/shaders/wireframe.vs @@ -0,0 +1,15 @@ +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; + +out vec3 vPos; +out vec3 vNormal; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); +} diff --git a/core/src/rendering/renderer.cpp b/core/src/rendering/renderer.cpp index 5c2f55e..eac9bf4 100644 --- a/core/src/rendering/renderer.cpp +++ b/core/src/rendering/renderer.cpp @@ -28,10 +28,14 @@ Shader* skyboxShader = NULL; Shader* handleShader = NULL; Shader* identityShader = NULL; Shader* ghostShader = NULL; +Shader* wireframeShader = NULL; +Shader* outlineShader = NULL; extern Camera camera; Skybox* skyboxTexture = NULL; Texture3D* studsTexture = NULL; +bool wireframeRendering = false; + static int viewportWidth, viewportHeight; void renderInit(GLFWwindow* window, int width, int height) { @@ -45,7 +49,6 @@ void renderInit(GLFWwindow* window, int width, int height) { glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - skyboxTexture = new Skybox({ "assets/textures/skybox/null_plainsky512_lf.jpg", "assets/textures/skybox/null_plainsky512_rt.jpg", @@ -63,6 +66,8 @@ void renderInit(GLFWwindow* window, int width, int height) { handleShader = new Shader("assets/shaders/handle.vs", "assets/shaders/handle.fs"); identityShader = new Shader("assets/shaders/identity.vs", "assets/shaders/identity.fs"); ghostShader = new Shader("assets/shaders/ghost.vs", "assets/shaders/ghost.fs"); + wireframeShader = new Shader("assets/shaders/wireframe.vs", "assets/shaders/wireframe.fs"); + outlineShader = new Shader("assets/shaders/outline.vs", "assets/shaders/outline.fs"); } void renderParts() { @@ -308,6 +313,112 @@ void renderAABB() { } } +void renderWireframe() { + glDepthMask(GL_TRUE); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + + // Use shader + wireframeShader->use(); + + // view/projection transformations + glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f); + glm::mat4 view = camera.getLookAt(); + wireframeShader->set("projection", projection); + wireframeShader->set("view", view); + + // Pass in the camera position + wireframeShader->set("viewPos", camera.cameraPos); + + wireframeShader->set("transparency", 0.5f); + wireframeShader->set("color", glm::vec3(1.f, 0.f, 0.f)); + + // Sort by nearest + for (InstanceRef inst : gWorkspace()->GetChildren()) { + if (inst->GetClass()->className != "Part") continue; + std::shared_ptr part = std::dynamic_pointer_cast(inst); + glm::mat4 model = part->cframe; + model = glm::scale(model, (glm::vec3)part->size); + wireframeShader->set("model", model); + glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model))); + wireframeShader->set("normalMatrix", normalMatrix); + + CUBE_MESH->bind(); + glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount); + } + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); +} + +void renderOutline() { + glDepthMask(GL_TRUE); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); + glLineWidth(10.f); + + // Use shader + wireframeShader->use(); + + // view/projection transformations + glm::mat4 projection = glm::perspective(glm::radians(45.f), (float)viewportWidth / (float)viewportHeight, 0.1f, 1000.0f); + glm::mat4 view = camera.getLookAt(); + wireframeShader->set("projection", projection); + wireframeShader->set("view", view); + + // Pass in the camera position + wireframeShader->set("viewPos", camera.cameraPos); + + wireframeShader->set("transparency", 0.5f); + wireframeShader->set("color", glm::vec3(0.204, 0.584, 0.922)); + + // Sort by nearest + for (InstanceRef inst : gWorkspace()->GetChildren()) { + if (inst->GetClass()->className != "Part") continue; + std::shared_ptr part = std::dynamic_pointer_cast(inst); + if (!part->selected) continue; + glm::mat4 model = part->cframe; + model = glm::scale(model, (glm::vec3)part->size / glm::vec3(2) + glm::vec3(0.001)); + wireframeShader->set("model", model); + glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model))); + wireframeShader->set("normalMatrix", normalMatrix); + + // CUBE_MESH->bind(); + // glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount); + + glBegin(GL_LINES); + // Upper face + glVertex3f(-1., 1., -1.); glVertex3f(1., 1., -1.); + glVertex3f(-1., 1., 1.); glVertex3f(1., 1., 1.); + + glVertex3f(-1., 1., -1.); glVertex3f(-1., 1., 1.); + glVertex3f(1., 1., -1.); glVertex3f(1., 1., 1.); + + // Lower face + glVertex3f(-1., -1., -1.); glVertex3f(1., -1., -1.); + glVertex3f(-1., -1., 1.); glVertex3f(1., -1., 1.); + + glVertex3f(-1., -1., -1.); glVertex3f(-1., -1., 1.); + glVertex3f(1., -1., -1.); glVertex3f(1., -1., 1.); + + // Connecting vertical lines + glVertex3f(-1., -1., -1.); glVertex3f(-1., 1., -1.); + glVertex3f(1., -1., -1.); glVertex3f(1., 1., -1.); + glVertex3f(-1., -1., 1.); glVertex3f(-1., 1., 1.); + glVertex3f(1., -1., 1.); glVertex3f(1., 1., 1.); + glEnd(); + } + + glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); +} + void render(GLFWwindow* window) { glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -315,6 +426,9 @@ void render(GLFWwindow* window) { renderSkyBox(); renderHandles(); renderParts(); + renderOutline(); + if (wireframeRendering) + renderWireframe(); // TODO: Make this a debug flag // renderAABB(); } diff --git a/core/src/rendering/renderer.h b/core/src/rendering/renderer.h index 0596e69..3b57d13 100644 --- a/core/src/rendering/renderer.h +++ b/core/src/rendering/renderer.h @@ -1,6 +1,8 @@ #pragma once #include +extern bool wireframeRendering; + void renderInit(GLFWwindow* window, int width, int height); void render(GLFWwindow* window); void setViewport(int width, int height); \ No newline at end of file diff --git a/editor/mainwindow.cpp b/editor/mainwindow.cpp index 9603a63..18148dd 100644 --- a/editor/mainwindow.cpp +++ b/editor/mainwindow.cpp @@ -1,6 +1,7 @@ #include "mainwindow.h" #include "./ui_mainwindow.h" #include "common.h" +#include #include #include #include @@ -92,6 +93,20 @@ MainWindow::MainWindow(QWidget *parent) ui->propertiesView->setSelected(newSelection[0].lock()); }); + addSelectionListener([&](auto oldSelection, auto newSelection, bool __) { + for (InstanceRefWeak inst : oldSelection) { + if (inst.expired() || inst.lock()->GetClass() != &Part::TYPE) continue; + std::shared_ptr part = std::dynamic_pointer_cast(inst.lock()); + part->selected = false; + } + + for (InstanceRefWeak inst : newSelection) { + if (inst.expired() || inst.lock()->GetClass() != &Part::TYPE) continue; + std::shared_ptr part = std::dynamic_pointer_cast(inst.lock()); + part->selected = true; + } + }); + // ui->explorerView->Init(ui); // Baseplate