feat(rendering): basic outline feature

This commit is contained in:
maelstrom 2025-04-12 23:48:13 +02:00
parent ee05b8d9d5
commit 9602aa96c0
7 changed files with 184 additions and 1 deletions

11
assets/shaders/outline.fs Normal file
View file

@ -0,0 +1,11 @@
#version 330 core
out vec4 FragColor;
uniform vec3 color;
// Main
void main() {
FragColor = vec4(color, 1);
}

15
assets/shaders/outline.vs Normal file
View file

@ -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);
}

View file

@ -0,0 +1,11 @@
#version 330 core
out vec4 FragColor;
uniform vec3 color;
// Main
void main() {
FragColor = vec4(color, 1);
}

View file

@ -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);
}

View file

@ -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> part = std::dynamic_pointer_cast<Part>(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> part = std::dynamic_pointer_cast<Part>(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();
}

View file

@ -1,6 +1,8 @@
#pragma once
#include <GLFW/glfw3.h>
extern bool wireframeRendering;
void renderInit(GLFWwindow* window, int width, int height);
void render(GLFWwindow* window);
void setViewport(int width, int height);

View file

@ -1,6 +1,7 @@
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include "common.h"
#include <memory>
#include <qclipboard.h>
#include <qmessagebox.h>
#include <qmimedata.h>
@ -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> part = std::dynamic_pointer_cast<Part>(inst.lock());
part->selected = false;
}
for (InstanceRefWeak inst : newSelection) {
if (inst.expired() || inst.lock()->GetClass() != &Part::TYPE) continue;
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst.lock());
part->selected = true;
}
});
// ui->explorerView->Init(ui);
// Baseplate