Fri, 06 Mar 2020 20:13:10 +0200
Added axes rendering
CMakeLists.txt | file | annotate | diff | comparison | revisions | |
src/basics.h | file | annotate | diff | comparison | revisions | |
src/gl/axesprogram.cpp | file | annotate | diff | comparison | revisions | |
src/gl/axesprogram.h | file | annotate | diff | comparison | revisions | |
src/gl/basicshaderprogram.cpp | file | annotate | diff | comparison | revisions | |
src/gl/basicshaderprogram.h | file | annotate | diff | comparison | revisions | |
src/gl/gridprogram.cpp | file | annotate | diff | comparison | revisions | |
src/gl/gridprogram.h | file | annotate | diff | comparison | revisions | |
src/gl/partrenderer.cpp | file | annotate | diff | comparison | revisions | |
src/gl/partrenderer.h | file | annotate | diff | comparison | revisions | |
src/ui/canvas.cpp | file | annotate | diff | comparison | revisions | |
src/ui/canvas.h | file | annotate | diff | comparison | revisions |
--- a/CMakeLists.txt Fri Mar 06 16:08:53 2020 +0200 +++ b/CMakeLists.txt Fri Mar 06 20:13:10 2020 +0200 @@ -36,6 +36,7 @@ src/uiutilities.cpp src/version.cpp src/gl/axesprogram.cpp + src/gl/basicshaderprogram.cpp src/gl/compiler.cpp src/gl/gridprogram.cpp src/gl/partrenderer.cpp @@ -76,6 +77,7 @@ src/utility.h src/version.h src/gl/axesprogram.h + src/gl/basicshaderprogram.h src/gl/common.h src/gl/compiler.h src/gl/gridprogram.h
--- a/src/basics.h Fri Mar 06 16:08:53 2020 +0200 +++ b/src/basics.h Fri Mar 06 20:13:10 2020 +0200 @@ -151,5 +151,9 @@ return {point.x(), point.y()}; } +constexpr float PIf = static_cast<float>(M_PI); +constexpr double PI = M_PI; +constexpr long double PIl = M_PIl; + Q_DECLARE_METATYPE(glm::vec3) Q_DECLARE_METATYPE(glm::mat4)
--- a/src/gl/axesprogram.cpp Fri Mar 06 16:08:53 2020 +0200 +++ b/src/gl/axesprogram.cpp Fri Mar 06 20:13:10 2020 +0200 @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "gridprogram.h" +#include "axesprogram.h" // Based on https://stackoverflow.com/q/30842755 const char vertexShaderSource[] = R"( @@ -31,8 +31,8 @@ void main() { - gl_Position = projection * view * model * vec4(in_position, 0.0, 1.0); - ex_uv = ex_color; + gl_Position = projection * view * model * vec4(in_position, 1.0); + ex_color = in_color; } )"; @@ -44,7 +44,7 @@ void main(void) { - color = vec4(ex_color, 1) + color = vec4(ex_color, 1); } )"; @@ -67,102 +67,43 @@ AxesVertex{{0, 0, 10000}, {0, 0, 1}}, }; -AxesProgram::AxesProgram(QObject* parent) : - QObject{parent}, - buffer{QOpenGLBuffer::VertexBuffer}, - vertexShader{QOpenGLShader::Vertex}, - fragmentShader{QOpenGLShader::Fragment} +const char* AxesProgram::vertexShaderSource() const { + return ::vertexShaderSource; } -void AxesProgram::initialize() +const char* AxesProgram::fragmentShaderSource() const { - if (not isInitialized) - { - this->initializeOpenGLFunctions(); - this->isInitialized = true; - this->program.emplace(this); - gl::buildShaders(&*this->program, ::vertexShaderSource, ::fragmentShaderSource); - this->program->bind(); - this->buffer.create(); - this->buffer.bind(); - this->buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); - this->buffer.allocate(data, countof(data) * sizeof data[0]); - this->vertexArrayObject.create(); - this->vertexArrayObject.bind(); - this->program->enableAttributeArray(0); - this->program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0); - this->program->setUniformVector("gridColor", this->gridColor); - this->vertexArrayObject.release(); - this->buffer.release(); - this->program->release(); - this->checkForGLErrors(); - } + return ::fragmentShaderSource; } -void AxesProgram::setViewMatrix(const glm::mat4& newViewMatrix) +const void* AxesProgram::vertexData() const { - this->setMatrix("view", newViewMatrix); + return ::data; } -void AxesProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix) +GLenum AxesProgram::drawMode() const { - this->setMatrix("projection", newProjectionMatrix); -} - -void AxesProgram::setModelMatrix(const glm::mat4& newModelMatrix) -{ - this->setMatrix("model", newModelMatrix); + return GL_LINES; } -void AxesProgram::setGridMatrix(const glm::mat4& newGridMatrix) +int AxesProgram::vertexSize() const { - this->setMatrix("grid", newGridMatrix); + return sizeof data[0]; } -void AxesProgram::setMatrix(const char* name, const glm::mat4& matrix) +int AxesProgram::vertexCount() const { - Q_ASSERT(this->isInitialized); - this->program->bind(); - this->program->setUniformMatrix(name, matrix); - this->program->release(); - this->checkForGLErrors(); + return countof(data); } -void GridProgram::setGridColor(const QColor& newGridColor) -{ - const glm::vec4 vec = gl::colorToVector4(newGridColor); - if (this->isInitialized) - { - this->program->bind(); - this->program->setUniformVector("gridColor", vec); - this->program->release(); - this->checkForGLErrors(); - } - else - { - this->gridColor = vec; - } -} - -void GridProgram::draw() +void AxesProgram::setupVertexArrays() { - this->program->bind(); - this->vertexArrayObject.bind(); - glDrawArrays(GL_QUADS, 0, countof(data)); - this->vertexArrayObject.release(); - this->program->release(); - this->checkForGLErrors(); + for (int i : {0, 1}) + { + this->program->enableAttributeArray(i); + } + const int stride = this->vertexSize(); + this->program->setAttributeBuffer(0, GL_FLOAT, offsetof(AxesVertex, position), 3, stride); + this->program->setAttributeBuffer(1, GL_FLOAT, offsetof(AxesVertex, color), 3, stride); } - -void GridProgram::teardown() -{ - this->vertexArrayObject.destroy(); - this->buffer.destroy(); - this->program.reset(); -} - -void GridProgram::checkForGLErrors() -{ - gl::checkForGLErrors(qobject_cast<QWidget*>(this->parent())); -}
--- a/src/gl/axesprogram.h Fri Mar 06 16:08:53 2020 +0200 +++ b/src/gl/axesprogram.h Fri Mar 06 20:13:10 2020 +0200 @@ -1,11 +1,18 @@ -#ifndef AXESPROGRAM_H -#define AXESPROGRAM_H +#pragma once +#include "gl/common.h" +#include "gl/basicshaderprogram.h" - -class AxesProgram +class AxesProgram : public AbstractBasicShaderProgram { + Q_OBJECT public: - AxesProgram(); + using AbstractBasicShaderProgram::AbstractBasicShaderProgram; +protected: + const char* vertexShaderSource() const override; + const char* fragmentShaderSource() const override; + const void* vertexData() const override; + GLenum drawMode() const override; + int vertexSize() const override; + int vertexCount() const override; + void setupVertexArrays() override; }; - -#endif // AXESPROGRAM_H \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/basicshaderprogram.cpp Fri Mar 06 20:13:10 2020 +0200 @@ -0,0 +1,96 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2020 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "basicshaderprogram.h" + +AbstractBasicShaderProgram::AbstractBasicShaderProgram(QObject* parent) : + QObject{parent}, + buffer{QOpenGLBuffer::VertexBuffer}, + vertexShader{QOpenGLShader::Vertex}, + fragmentShader{QOpenGLShader::Fragment} +{ +} + +void AbstractBasicShaderProgram::initialize() +{ + if (not isInitialized) + { + this->initializeOpenGLFunctions(); + this->isInitialized = true; + this->program.emplace(this); + gl::buildShaders(&*this->program, this->vertexShaderSource(), this->fragmentShaderSource()); + this->program->bind(); + this->buffer.create(); + this->buffer.bind(); + this->buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); + this->buffer.allocate(this->vertexData(), this->vertexCount() * this->vertexSize()); + this->vertexArrayObject.create(); + this->vertexArrayObject.bind(); + this->setupVertexArrays(); + this->vertexArrayObject.release(); + this->buffer.release(); + this->program->release(); + this->checkForGLErrors(); + } +} + +void AbstractBasicShaderProgram::setViewMatrix(const glm::mat4& newViewMatrix) +{ + this->setMatrix("view", newViewMatrix); +} + +void AbstractBasicShaderProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix) +{ + this->setMatrix("projection", newProjectionMatrix); +} + +void AbstractBasicShaderProgram::setModelMatrix(const glm::mat4& newModelMatrix) +{ + this->setMatrix("model", newModelMatrix); +} + +void AbstractBasicShaderProgram::setMatrix(const char* name, const glm::mat4& matrix) +{ + Q_ASSERT(this->isInitialized); + this->program->bind(); + this->program->setUniformMatrix(name, matrix); + this->program->release(); + this->checkForGLErrors(); +} + +void AbstractBasicShaderProgram::draw() +{ + this->program->bind(); + this->vertexArrayObject.bind(); + glDrawArrays(this->drawMode(), 0, this->vertexCount()); + this->vertexArrayObject.release(); + this->program->release(); + this->checkForGLErrors(); +} + +void AbstractBasicShaderProgram::teardown() +{ + this->vertexArrayObject.destroy(); + this->buffer.destroy(); + this->program.reset(); +} + +void AbstractBasicShaderProgram::checkForGLErrors() +{ + gl::checkForGLErrors(qobject_cast<QWidget*>(this->parent())); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl/basicshaderprogram.h Fri Mar 06 20:13:10 2020 +0200 @@ -0,0 +1,32 @@ +#pragma once +#include "common.h" + +class AbstractBasicShaderProgram : public QObject, protected QOpenGLFunctions +{ + Q_OBJECT +public: + AbstractBasicShaderProgram(QObject* parent = nullptr); + ~AbstractBasicShaderProgram() = default; + void initialize(); + Q_SLOT void setViewMatrix(const glm::mat4& newViewMatrix); + Q_SLOT void setProjectionMatrix(const glm::mat4& newProjectionMatrix); + Q_SLOT void setModelMatrix(const glm::mat4& newModelMatrix); + void draw(); + void teardown(); +protected: + void setMatrix(const char* name, const glm::mat4& matrix); + void checkForGLErrors(); + virtual const char* vertexShaderSource() const = 0; + virtual const char* fragmentShaderSource() const = 0; + virtual const void* vertexData() const = 0; + virtual int vertexSize() const = 0; + virtual int vertexCount() const = 0; + virtual void setupVertexArrays() = 0; + virtual GLenum drawMode() const = 0; + bool isInitialized = false; + QOpenGLBuffer buffer; + QOpenGLShader vertexShader; + QOpenGLShader fragmentShader; + std::optional<gl::ShaderProgram> program{std::nullopt}; + QOpenGLVertexArrayObject vertexArrayObject; +};
--- a/src/gl/gridprogram.cpp Fri Mar 06 16:08:53 2020 +0200 +++ b/src/gl/gridprogram.cpp Fri Mar 06 20:13:10 2020 +0200 @@ -64,68 +64,11 @@ static const glm::vec2 data[] = {{-1, -1}, {-1, 1}, {1, 1}, {1, -1}}; -GridProgram::GridProgram(QObject* parent) : - QObject{parent}, - buffer{QOpenGLBuffer::VertexBuffer}, - vertexShader{QOpenGLShader::Vertex}, - fragmentShader{QOpenGLShader::Fragment} -{ -} - -void GridProgram::initialize() -{ - if (not isInitialized) - { - this->initializeOpenGLFunctions(); - this->isInitialized = true; - this->program.emplace(this); - gl::buildShaders(&*this->program, ::vertexShaderSource, ::fragmentShaderSource); - this->program->bind(); - this->buffer.create(); - this->buffer.bind(); - this->buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); - this->buffer.allocate(data, countof(data) * sizeof data[0]); - this->vertexArrayObject.create(); - this->vertexArrayObject.bind(); - this->program->enableAttributeArray(0); - this->program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0); - this->program->setUniformVector("gridColor", this->gridColor); - this->vertexArrayObject.release(); - this->buffer.release(); - this->program->release(); - this->checkForGLErrors(); - } -} - -void GridProgram::setViewMatrix(const glm::mat4& newViewMatrix) -{ - this->setMatrix("view", newViewMatrix); -} - -void GridProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix) -{ - this->setMatrix("projection", newProjectionMatrix); -} - -void GridProgram::setModelMatrix(const glm::mat4& newModelMatrix) -{ - this->setMatrix("model", newModelMatrix); -} - void GridProgram::setGridMatrix(const glm::mat4& newGridMatrix) { this->setMatrix("grid", newGridMatrix); } -void GridProgram::setMatrix(const char* name, const glm::mat4& matrix) -{ - Q_ASSERT(this->isInitialized); - this->program->bind(); - this->program->setUniformMatrix(name, matrix); - this->program->release(); - this->checkForGLErrors(); -} - void GridProgram::setGridColor(const QColor& newGridColor) { const glm::vec4 vec = gl::colorToVector4(newGridColor); @@ -142,24 +85,39 @@ } } -void GridProgram::draw() +const char* GridProgram::vertexShaderSource() const +{ + return ::vertexShaderSource; +} + +const char* GridProgram::fragmentShaderSource() const { - this->program->bind(); - this->vertexArrayObject.bind(); - glDrawArrays(GL_QUADS, 0, countof(data)); - this->vertexArrayObject.release(); - this->program->release(); - this->checkForGLErrors(); + return ::fragmentShaderSource; +} + +const void* GridProgram::vertexData() const +{ + return ::data; } -void GridProgram::teardown() +int GridProgram::vertexSize() const { - this->vertexArrayObject.destroy(); - this->buffer.destroy(); - this->program.reset(); + return sizeof data[0]; +} + +int GridProgram::vertexCount() const +{ + return countof(data); } -void GridProgram::checkForGLErrors() +void GridProgram::setupVertexArrays() { - gl::checkForGLErrors(qobject_cast<QWidget*>(this->parent())); + this->program->enableAttributeArray(0); + this->program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0); + this->program->setUniformVector("gridColor", this->gridColor); } + +GLenum GridProgram::drawMode() const +{ + return GL_QUADS; +}
--- a/src/gl/gridprogram.h Fri Mar 06 16:08:53 2020 +0200 +++ b/src/gl/gridprogram.h Fri Mar 06 20:13:10 2020 +0200 @@ -17,33 +17,24 @@ */ #pragma once +#include "basicshaderprogram.h" #include "common.h" -class GridProgram : public QObject, protected QOpenGLFunctions +class GridProgram : public AbstractBasicShaderProgram { Q_OBJECT public: - GridProgram(QObject* parent = nullptr); - GridProgram(const GridProgram&) = delete; - GridProgram(GridProgram&&) = delete; - ~GridProgram() = default; - void initialize(); - void setViewMatrix(const glm::mat4& newViewMatrix); - void setProjectionMatrix(const glm::mat4& newProjectionMatrix); - void setModelMatrix(const glm::mat4& newModelMatrix); + using AbstractBasicShaderProgram::AbstractBasicShaderProgram; void setGridMatrix(const glm::mat4& newGridMatrix); void setGridColor(const QColor& newGridColor); - void operator=(GridProgram) = delete; - void draw(); - void teardown(); +protected: + const char* vertexShaderSource() const override; + const char* fragmentShaderSource() const override; + const void* vertexData() const override; + int vertexSize() const override; + int vertexCount() const override; + void setupVertexArrays() override; + GLenum drawMode() const override; private: - void setMatrix(const char* name, const glm::mat4& matrix); - void checkForGLErrors(); - bool isInitialized = false; - QOpenGLBuffer buffer; - QOpenGLShader vertexShader; - QOpenGLShader fragmentShader; - std::optional<gl::ShaderProgram> program{std::nullopt}; glm::vec4 gridColor = {1.0f, 1.0f, 1.0f, 0.75f}; - QOpenGLVertexArrayObject vertexArrayObject; };
--- a/src/gl/partrenderer.cpp Fri Mar 06 16:08:53 2020 +0200 +++ b/src/gl/partrenderer.cpp Fri Mar 06 20:13:10 2020 +0200 @@ -80,7 +80,7 @@ 0.1f, 10000.f); this->compiler->setUniformMatrix("projectionMatrix", this->projectionMatrix); - emit projectionMatrixChanged(); + emit projectionMatrixChanged(this->projectionMatrix); } static GLenum getGlTypeForArrayClass(const gl::ArrayClass vboClass) @@ -192,14 +192,14 @@ const double z = 2 * std::exp(this->zoom) * (1 + this->compiler->modelDistance()); this->viewMatrix = glm::lookAt(glm::vec3{0, 0, z}, {0, 0, 0}, {0, -1, 0}); this->compiler->setUniformMatrix("viewMatrix", this->viewMatrix); - emit this->viewMatrixChanged(); + emit this->viewMatrixChanged(this->viewMatrix); } void PartRenderer::updateModelMatrix() { this->modelMatrix = glm::mat4_cast(this->modelQuaternion); this->compiler->setUniformMatrix("modelMatrix", modelMatrix); - emit this->modelMatrixChanged(); + emit this->modelMatrixChanged(this->modelMatrix); this->update(); }
--- a/src/gl/partrenderer.h Fri Mar 06 16:08:53 2020 +0200 +++ b/src/gl/partrenderer.h Fri Mar 06 20:13:10 2020 +0200 @@ -46,9 +46,9 @@ QPoint lastMousePosition; gl::RenderPreferences renderPreferences; signals: - void projectionMatrixChanged(); - void modelMatrixChanged(); - void viewMatrixChanged(); + void projectionMatrixChanged(const glm::mat4& newMatrix); + void modelMatrixChanged(const glm::mat4& newMatrix); + void viewMatrixChanged(const glm::mat4& newMatrix); void renderPreferencesChanged(); private: void setFragmentStyle(gl::FragmentStyle fragStyle);
--- a/src/ui/canvas.cpp Fri Mar 06 16:08:53 2020 +0200 +++ b/src/ui/canvas.cpp Fri Mar 06 20:13:10 2020 +0200 @@ -7,8 +7,7 @@ DocumentManager* documents, const ldraw::ColorTable& colorTable, QWidget* parent) : - PartRenderer{model, documents, colorTable, parent}, - gridProgram{this} + PartRenderer{model, documents, colorTable, parent} { this->setMouseTracking(true); } @@ -70,12 +69,12 @@ if (angle_x < angle_y) { this->newStatusText("rotate by X axis"); - this->gridMatrix = glm::rotate(this->gridMatrix, float{M_PI} / 2, glm::vec3{1, 0, 0}); + this->gridMatrix = glm::rotate(this->gridMatrix, PIf / 2, glm::vec3{1, 0, 0}); } else { this->newStatusText("rotate by Y axis"); - this->gridMatrix = glm::rotate(this->gridMatrix, float{M_PI} / 2, glm::vec3{0, 1, 0}); + this->gridMatrix = glm::rotate(this->gridMatrix, PIf / 2, glm::vec3{0, 1, 0}); } this->updateGridMatrix(); this->update(); @@ -119,18 +118,20 @@ // functions so that when initialization sets up, the signals also set up the matrices on our side. this->gridProgram.emplace(this); this->gridProgram->initialize(); - connect(this, &PartRenderer::projectionMatrixChanged, [&]() - { - this->gridProgram->setProjectionMatrix(this->projectionMatrix); - }); - connect(this, &PartRenderer::modelMatrixChanged, [&]() + this->axesProgram.emplace(this); + this->axesProgram->initialize(); + for (AbstractBasicShaderProgram* program : { + static_cast<AbstractBasicShaderProgram*>(&*this->gridProgram), + static_cast<AbstractBasicShaderProgram*>(&*this->axesProgram), + }) { - this->gridProgram->setModelMatrix(this->modelMatrix); - }); - connect(this, &PartRenderer::viewMatrixChanged, [&]() - { - this->gridProgram->setViewMatrix(this->viewMatrix); - }); + connect(this, &PartRenderer::projectionMatrixChanged, + program, &AbstractBasicShaderProgram::setProjectionMatrix); + connect(this, &PartRenderer::modelMatrixChanged, + program, &AbstractBasicShaderProgram::setModelMatrix); + connect(this, &PartRenderer::viewMatrixChanged, + program, &AbstractBasicShaderProgram::setViewMatrix); + } connect(this, &PartRenderer::renderPreferencesChanged, [&]() { if (this->gridProgram.has_value()) @@ -140,14 +141,7 @@ } }); PartRenderer::initializeGL(); - /* - this->gridMatrix = glm::mat4{ - {-4, 0, 0, 0}, - {0, 6.9266, -3.6955, 0}, - {0, -16.7222, -1.5307, 0}, - {0, -13.273, -9.255, 1}, - }; - */ + // Set up XZ grid matrix this->gridMatrix = glm::mat4{ {1, 0, 0, 0}, {0, 0, 1, 0}, @@ -160,10 +154,21 @@ void Canvas::paintGL() { PartRenderer::paintGL(); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - this->gridProgram->draw(); - glDisable(GL_BLEND); + // Render axes + { + glLineWidth(5); + glEnable(GL_LINE_SMOOTH); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + this->axesProgram->draw(); + glDisable(GL_LINE_SMOOTH); + } + // Render grid + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + this->gridProgram->draw(); + glDisable(GL_BLEND); + } if (this->worldPosition.has_value()) { QPainter painter{this}; @@ -175,22 +180,6 @@ painter.setPen(Qt::white); painter.drawText(pos + QPointF{5, 5}, vectorToString(*this->worldPosition)); } - { - QPainter axisPainter{this}; - axisPainter.setRenderHint(QPainter::Antialiasing); - axisPainter.setPen(Qt::red); - axisPainter.drawLine( - this->modelToScreenCoordinates({10, 0, 0}), - this->modelToScreenCoordinates({-10, 0, 0})); - axisPainter.setPen(Qt::green); - axisPainter.drawLine( - this->modelToScreenCoordinates({0, 10, 0}), - this->modelToScreenCoordinates({0, -10, 0})); - axisPainter.setPen(Qt::blue); - axisPainter.drawLine( - this->modelToScreenCoordinates({0, 0, 10}), - this->modelToScreenCoordinates({0, 0, -10})); - } } void Canvas::updateGridMatrix()
--- a/src/ui/canvas.h Fri Mar 06 16:08:53 2020 +0200 +++ b/src/ui/canvas.h Fri Mar 06 20:13:10 2020 +0200 @@ -1,6 +1,7 @@ #pragma once #include "gl/partrenderer.h" #include "gl/gridprogram.h" +#include "gl/axesprogram.h" class Canvas : public PartRenderer { @@ -27,6 +28,7 @@ glm::vec3 cameraVector() const; bool isGridPerpendicularToScreen(float threshold) const; std::optional<GridProgram> gridProgram; + std::optional<AxesProgram> axesProgram; std::optional<glm::vec3> worldPosition; glm::mat4 gridMatrix; geom::Plane gridPlane;