Compare commits
3 commits
18a1cc79df
...
881d09f9bc
Author | SHA1 | Date | |
---|---|---|---|
881d09f9bc | |||
62835505f9 | |||
3fc20fcd4e |
10 changed files with 167 additions and 13 deletions
20
assets/shaders/ghost.fs
Normal file
20
assets/shaders/ghost.fs
Normal file
|
@ -0,0 +1,20 @@
|
|||
#version 330 core
|
||||
|
||||
in vec3 vPos;
|
||||
in vec3 vNormal;
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
#define NR_POINT_LIGHTS 4
|
||||
|
||||
uniform vec3 viewPos;
|
||||
uniform float transparency;
|
||||
uniform vec3 color;
|
||||
|
||||
|
||||
|
||||
// Main
|
||||
|
||||
void main() {
|
||||
FragColor = vec4(color, 1) * (1-transparency);
|
||||
}
|
18
assets/shaders/ghost.vs
Normal file
18
assets/shaders/ghost.vs
Normal file
|
@ -0,0 +1,18 @@
|
|||
#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 mat3 normalMatrix;
|
||||
uniform mat4 view;
|
||||
uniform mat4 projection;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||
vPos = vec3(model * vec4(aPos, 1.0));
|
||||
vNormal = normalMatrix * aNormal;
|
||||
}
|
|
@ -25,6 +25,7 @@ Data::Vector3::operator glm::vec3() const { return vector; };
|
|||
Data::Vector3::operator rp::Vector3() const { return rp::Vector3(X(), Y(), Z()); };
|
||||
|
||||
// Operators
|
||||
|
||||
Data::Vector3 Data::Vector3::operator *(float scale) const {
|
||||
return Data::Vector3(this->X() * scale, this->Y() * scale, this->Z() * scale);
|
||||
}
|
||||
|
@ -33,6 +34,11 @@ Data::Vector3 Data::Vector3::operator /(float scale) const {
|
|||
return Data::Vector3(this->X() / scale, this->Y() / scale, this->Z() / scale);
|
||||
}
|
||||
|
||||
// Component-wise
|
||||
Data::Vector3 Data::Vector3::operator *(Data::Vector3 other) const {
|
||||
return Data::Vector3(this->X() * other.X(), this->Y() * other.Y(), this->Z() * other.Z());
|
||||
}
|
||||
|
||||
Data::Vector3 Data::Vector3::operator +(Data::Vector3 other) const {
|
||||
return Data::Vector3(this->X() + other.X(), this->Y() + other.Y(), this->Z() + other.Z());
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace Data {
|
|||
inline float Z() const { return vector.z; }
|
||||
inline float Magnitude() const { return glm::length(vector); }
|
||||
inline Data::Vector3 Unit() const { return glm::normalize(vector); }
|
||||
inline Data::Vector3 Abs() const { return glm::abs(vector); }
|
||||
|
||||
Data::Vector3 Cross(Data::Vector3) const;
|
||||
float Dot(Data::Vector3) const;
|
||||
|
@ -42,6 +43,7 @@ namespace Data {
|
|||
// Operators
|
||||
Data::Vector3 operator *(float) const;
|
||||
Data::Vector3 operator /(float) const;
|
||||
Data::Vector3 operator *(Data::Vector3) const; // Component-wise
|
||||
Data::Vector3 operator +(Data::Vector3) const;
|
||||
Data::Vector3 operator -(Data::Vector3) const;
|
||||
Data::Vector3 operator -() const;
|
||||
|
|
|
@ -44,7 +44,8 @@ Data::CFrame Handles::GetCFrameOfHandle(HandleFace face) {
|
|||
if (glm::abs(glm::dot(glm::vec3(localFrame.Rotation() * face.normal), upAxis)) > 0.9999f)
|
||||
upAxis = glm::vec3(0, 1, 0);
|
||||
|
||||
Data::Vector3 handlePos = localFrame * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
||||
Data::Vector3 handleOffset = this->worldMode ? ((Data::Vector3::ONE * 2.f) + adornee->lock()->GetAABB() * 0.5f) : Data::Vector3(2.f + adornee->lock()->size * 0.5f);
|
||||
Data::Vector3 handlePos = localFrame * (handleOffset * face.normal);
|
||||
Data::CFrame cframe(handlePos, handlePos + localFrame.Rotation() * face.normal, upAxis);
|
||||
|
||||
return cframe;
|
||||
|
@ -55,11 +56,12 @@ Data::CFrame Handles::PartCFrameFromHandlePos(HandleFace face, Data::Vector3 new
|
|||
|
||||
Data::CFrame localFrame = worldMode ? Data::CFrame::IDENTITY + adornee->lock()->position() : adornee->lock()->cframe;
|
||||
Data::CFrame inverseFrame = localFrame.Inverse();
|
||||
Data::Vector3 handleOffset = this->worldMode ? ((Data::Vector3::ONE * 2.f) + adornee->lock()->GetAABB() * 0.5f) : Data::Vector3(2.f + adornee->lock()->size * 0.5f);
|
||||
|
||||
Data::Vector3 handlePos = localFrame * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
||||
Data::Vector3 handlePos = localFrame * (handleOffset * face.normal);
|
||||
|
||||
// glm::vec3 localPos = inverseFrame * newPos;
|
||||
glm::vec3 newPartPos = newPos - localFrame.Rotation() * ((2.f + adornee->lock()->size * 0.5f) * face.normal);
|
||||
glm::vec3 newPartPos = newPos - localFrame.Rotation() * (handleOffset * face.normal);
|
||||
return adornee->lock()->cframe.Rotation() + newPartPos;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <optional>
|
||||
#include "physics/simulation.h"
|
||||
|
||||
using Data::Vector3;
|
||||
|
||||
// template <typename T, typename U>
|
||||
// constexpr FieldCodec fieldCodecOf() {
|
||||
// return FieldCodec {
|
||||
|
@ -25,7 +27,7 @@ constexpr FieldCodec cframePositionCodec() {
|
|||
return FieldCodec {
|
||||
.write = [](Data::Variant source, void* destination) {
|
||||
Data::CFrame* cframe = static_cast<Data::CFrame*>(destination);
|
||||
*cframe = cframe->Rotation() + source.get<Data::Vector3>();
|
||||
*cframe = cframe->Rotation() + source.get<Vector3>();
|
||||
},
|
||||
.read = [](void* source) -> Data::Variant {
|
||||
return *static_cast<Data::CFrame*>(source);
|
||||
|
@ -37,7 +39,7 @@ constexpr FieldCodec cframeRotationCodec() {
|
|||
return FieldCodec {
|
||||
.write = [](Data::Variant source, void* destination) {
|
||||
Data::CFrame* cframe = static_cast<Data::CFrame*>(destination);
|
||||
*cframe = Data::CFrame::FromEulerAnglesXYZ(source.get<Data::Vector3>()) + cframe->Position();
|
||||
*cframe = Data::CFrame::FromEulerAnglesXYZ(source.get<Vector3>()) + cframe->Position();
|
||||
},
|
||||
.read = [](void* source) -> Data::Variant {
|
||||
return static_cast<Data::CFrame*>(source)->ToEulerAnglesXYZ();
|
||||
|
@ -71,13 +73,13 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par
|
|||
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||
}}, { "Position", {
|
||||
.backingField = &cframe,
|
||||
.type = &Data::Vector3::TYPE,
|
||||
.type = &Vector3::TYPE,
|
||||
.codec = cframePositionCodec(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
.flags = PropertyFlags::PROP_NOSAVE
|
||||
}}, { "Rotation", {
|
||||
.backingField = &cframe,
|
||||
.type = &Data::Vector3::TYPE,
|
||||
.type = &Vector3::TYPE,
|
||||
.codec = cframeRotationCodec(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
.flags = PropertyFlags::PROP_NOSAVE
|
||||
|
@ -88,8 +90,8 @@ Part::Part(PartConstructParams params): Instance(&TYPE), cframe(Data::CFrame(par
|
|||
.updateCallback = memberFunctionOf(&Part::onUpdated, this),
|
||||
}}, { "Size", {
|
||||
.backingField = &size,
|
||||
.type = &Data::Vector3::TYPE,
|
||||
.codec = fieldCodecOf<Data::Vector3, glm::vec3>(),
|
||||
.type = &Vector3::TYPE,
|
||||
.codec = fieldCodecOf<Vector3, glm::vec3>(),
|
||||
.updateCallback = memberFunctionOf(&Part::onUpdated, this)
|
||||
}}, { "Color", {
|
||||
.backingField = &color,
|
||||
|
@ -122,4 +124,32 @@ void Part::OnParentUpdated(std::optional<std::shared_ptr<Instance>> oldParent, s
|
|||
|
||||
void Part::onUpdated(std::string property) {
|
||||
syncPartPhysics(std::dynamic_pointer_cast<Part>(this->shared_from_this()));
|
||||
}
|
||||
|
||||
// Expands provided extents to fit point
|
||||
static void expandMaxExtents(Vector3* min, Vector3* max, Vector3 point) {
|
||||
*min = Vector3(glm::min(min->X(), point.X()), glm::min(min->Y(), point.Y()), glm::min(min->Z(), point.Z()));
|
||||
*max = Vector3(glm::max(max->X(), point.X()), glm::max(max->Y(), point.Y()), glm::max(max->Z(), point.Z()));
|
||||
}
|
||||
|
||||
static Vector3 verts[8] {
|
||||
{-1, -1, -1},
|
||||
{-1, -1, 1},
|
||||
{-1, 1, -1},
|
||||
{-1, 1, 1},
|
||||
{1, -1, -1},
|
||||
{1, -1, 1},
|
||||
{1, 1, -1},
|
||||
{1, 1, 1},
|
||||
};
|
||||
|
||||
Vector3 Part::GetAABB() {
|
||||
Vector3 min(0, 0, 0);
|
||||
Vector3 max(0, 0, 0);
|
||||
for (Vector3 vert : verts) {
|
||||
Vector3 worldVert = this->cframe.Rotation() * ((Data::Vector3)this->size * vert);
|
||||
expandMaxExtents(&min, &max, worldVert);
|
||||
}
|
||||
|
||||
return (min - max).Abs() / 2;
|
||||
}
|
|
@ -48,4 +48,7 @@ public:
|
|||
virtual const InstanceType* GetClass() override;
|
||||
|
||||
inline Data::Vector3 position() { return cframe.Position(); }
|
||||
|
||||
// Calculate size of axis-aligned bounding box
|
||||
Data::Vector3 GetAABB();
|
||||
};
|
|
@ -29,6 +29,7 @@ Shader* shader = NULL;
|
|||
Shader* skyboxShader = NULL;
|
||||
Shader* handleShader = NULL;
|
||||
Shader* identityShader = NULL;
|
||||
Shader* ghostShader = NULL;
|
||||
extern Camera camera;
|
||||
Skybox* skyboxTexture = NULL;
|
||||
Texture3D* studsTexture = NULL;
|
||||
|
@ -63,6 +64,7 @@ void renderInit(GLFWwindow* window, int width, int height) {
|
|||
skyboxShader = new Shader("assets/shaders/skybox.vs", "assets/shaders/skybox.fs");
|
||||
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");
|
||||
}
|
||||
|
||||
void renderParts() {
|
||||
|
@ -126,7 +128,7 @@ void renderParts() {
|
|||
sorted[distance] = part;
|
||||
} else {
|
||||
glm::mat4 model = part->cframe;
|
||||
if (part->name == "camera") model = camera.getLookAt();
|
||||
// if (part->name == "camera") model = camera.getLookAt();
|
||||
model = glm::scale(model, part->size);
|
||||
shader->set("model", model);
|
||||
shader->set("material", Material {
|
||||
|
@ -149,7 +151,7 @@ void renderParts() {
|
|||
for (std::map<float, std::shared_ptr<Part>>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); it++) {
|
||||
std::shared_ptr<Part> part = it->second;
|
||||
glm::mat4 model = part->cframe;
|
||||
if (part->name == "camera") model = camera.getLookAt();
|
||||
// if (part->name == "camera") model = camera.getLookAt();
|
||||
model = glm::scale(model, part->size);
|
||||
shader->set("model", model);
|
||||
shader->set("material", Material {
|
||||
|
@ -256,6 +258,45 @@ void renderHandles() {
|
|||
}
|
||||
}
|
||||
|
||||
void renderAABB() {
|
||||
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);
|
||||
|
||||
// Use shader
|
||||
ghostShader->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();
|
||||
ghostShader->set("projection", projection);
|
||||
ghostShader->set("view", view);
|
||||
|
||||
// Pass in the camera position
|
||||
ghostShader->set("viewPos", camera.cameraPos);
|
||||
|
||||
ghostShader->set("transparency", 0.5f);
|
||||
ghostShader->set("color", glm::vec3(1.f, 0.f, 0.f));
|
||||
|
||||
// Sort by nearest
|
||||
for (InstanceRef inst : workspace()->GetChildren()) {
|
||||
if (inst->GetClass()->className != "Part") continue;
|
||||
std::shared_ptr<Part> part = std::dynamic_pointer_cast<Part>(inst);
|
||||
glm::mat4 model = Data::CFrame::IDENTITY + part->cframe.Position();
|
||||
printf("AABB is supposedly (%f, %f, %f)\n", part->GetAABB().X(), part->GetAABB().Y(), part->GetAABB().Z());
|
||||
model = glm::scale(model, (glm::vec3)part->GetAABB());
|
||||
ghostShader->set("model", model);
|
||||
glm::mat3 normalMatrix = glm::mat3(glm::transpose(glm::inverse(model)));
|
||||
ghostShader->set("normalMatrix", normalMatrix);
|
||||
|
||||
CUBE_MESH->bind();
|
||||
glDrawArrays(GL_TRIANGLES, 0, CUBE_MESH->vertexCount);
|
||||
}
|
||||
}
|
||||
|
||||
void render(GLFWwindow* window) {
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
@ -263,6 +304,8 @@ void render(GLFWwindow* window) {
|
|||
renderSkyBox();
|
||||
renderHandles();
|
||||
renderParts();
|
||||
// TODO: Make this a debug flag
|
||||
// renderAABB();
|
||||
}
|
||||
|
||||
void setViewport(int width, int height) {
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
|
||||
bool simulationPlaying = false;
|
||||
|
||||
bool worldSpaceTransforms = false;
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
|
@ -102,6 +104,16 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
}
|
||||
});
|
||||
|
||||
connect(ui->actionToggleSpace, &QAction::triggered, this, [&]() {
|
||||
worldSpaceTransforms = !worldSpaceTransforms;
|
||||
updateToolbars();
|
||||
if (worldSpaceTransforms) {
|
||||
ui->actionToggleSpace->setText("W");
|
||||
} else {
|
||||
ui->actionToggleSpace->setText("L");
|
||||
}
|
||||
});
|
||||
|
||||
connect(ui->actionSave, &QAction::triggered, this, [&]() {
|
||||
std::optional<std::string> path;
|
||||
if (!dataModel->HasFile())
|
||||
|
@ -305,8 +317,11 @@ void MainWindow::updateToolbars() {
|
|||
ui->actionGridSnapOff->setChecked(snappingMode == GridSnappingMode::SNAP_OFF);
|
||||
|
||||
// editorToolHandles->worldMode = false;
|
||||
if (selectedTool == SelectedTool::MOVE) editorToolHandles->worldMode = true;
|
||||
if (selectedTool == SelectedTool::SCALE) editorToolHandles->worldMode = false;
|
||||
if (selectedTool == SelectedTool::SCALE)
|
||||
editorToolHandles->worldMode = false;
|
||||
else
|
||||
editorToolHandles->worldMode = worldSpaceTransforms;
|
||||
|
||||
editorToolHandles->active = selectedTool != SelectedTool::SELECT;
|
||||
editorToolHandles->handlesType =
|
||||
selectedTool == SelectedTool::MOVE ? HandlesType::MoveHandles
|
||||
|
|
|
@ -124,6 +124,7 @@
|
|||
<addaction name="actionToolMove"/>
|
||||
<addaction name="actionToolScale"/>
|
||||
<addaction name="actionToolRotate"/>
|
||||
<addaction name="actionToggleSpace"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionDelete"/>
|
||||
<addaction name="actionCopy"/>
|
||||
|
@ -465,6 +466,20 @@
|
|||
<enum>QAction::MenuRole::QuitRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionToggleSpace">
|
||||
<property name="text">
|
||||
<string>L</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Switch between local and world space transformations</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+L</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::MenuRole::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
Loading…
Add table
Reference in a new issue