Thu, 27 Feb 2020 11:56:41 +0200
use glm::unProject to implement screenToModelCoordinates
/* * 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 "gridprogram.h" // Based on https://stackoverflow.com/q/30842755 const char vertexShaderSource[] = R"( #version 330 core layout (location = 0) in vec2 in_position; uniform mat4 view; uniform mat4 projection; uniform mat4 model; smooth out vec2 ex_uv; const mat4 stretch = mat4(vec4(10000, 0, 0, 0), vec4(0, 10000, 0, 0), vec4(0, 0, 10000, 0), vec4(0, 0, 0, 1)); const mat4 gridmatrix = mat4(vec4(1, 0, 0, 0), vec4(0, 1, 0, 0), vec4(0, 0, 1, 0), vec4(0, 0, 0, 1)); void main() { gl_Position = projection * view * model * gridmatrix * stretch * vec4(in_position, 0.0, 1.0); ex_uv = in_position; } )"; const char fragmentShaderSource[] = R"( #version 330 core out vec4 color; smooth in vec2 ex_uv; uniform vec4 gridColor; const float pi = 3.14159265f; void main(void) { float dx = fract(ex_uv.y / 0.0001f); float dy = fract(ex_uv.x / 0.0001f); /* compute distance to nearest unit line */ float d = min(min(min(dy, dx), 1 - dy), 1 - dx); /* use an extreme sigmoid to bring out the grid shape */ d = pow(1 - d, 50); /* fade the grid towards extreme co-ordinates */ d = (1.0f - 20 * max(abs(ex_uv.x), abs(ex_uv.y))) * d; /* add dashes */ d *= (1 + cos(ex_uv.y / 0.00001f * pi)) * 0.5f; d *= (1 + cos(ex_uv.x / 0.00001f * pi)) * 0.5f; color = vec4(gridColor.xyz, gridColor.w * d); } )"; 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) { Q_ASSERT(this->isInitialized); this->program->bind(); this->program->setUniformMatrix("view", newViewMatrix); this->program->release(); this->checkForGLErrors(); } void GridProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix) { Q_ASSERT(this->isInitialized); this->program->bind(); this->program->setUniformMatrix("projection", newProjectionMatrix); this->program->release(); this->checkForGLErrors(); } void GridProgram::setModelMatrix(const glm::mat4& newModelMatrix) { Q_ASSERT(this->isInitialized); this->program->bind(); this->program->setUniformMatrix("model", newModelMatrix); this->program->release(); this->checkForGLErrors(); } 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() { this->program->bind(); this->vertexArrayObject.bind(); glDrawArrays(GL_QUADS, 0, countof(data)); this->vertexArrayObject.release(); this->program->release(); this->checkForGLErrors(); } void GridProgram::teardown() { this->vertexArrayObject.destroy(); this->buffer.destroy(); this->program.reset(); } void GridProgram::checkForGLErrors() { gl::checkForGLErrors(qobject_cast<QWidget*>(this->parent())); }