From 0fc34a47aacdfcec1480dd8c91fc9d30e20adcb8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 7 Aug 2014 18:19:58 -0700 Subject: [PATCH] Show heightfield cursor. --- .../shaders/metavoxel_heightfield_cursor.frag | 20 +++ .../shaders/metavoxel_heightfield_cursor.vert | 31 ++++ interface/src/MetavoxelSystem.cpp | 140 +++++++++++++++++- interface/src/MetavoxelSystem.h | 19 ++- interface/src/ui/MetavoxelEditor.cpp | 10 +- .../metavoxels/src/MetavoxelClientManager.cpp | 6 +- 6 files changed, 204 insertions(+), 22 deletions(-) create mode 100644 interface/resources/shaders/metavoxel_heightfield_cursor.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_cursor.vert diff --git a/interface/resources/shaders/metavoxel_heightfield_cursor.frag b/interface/resources/shaders/metavoxel_heightfield_cursor.frag new file mode 100644 index 0000000000..20efc51e08 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_cursor.frag @@ -0,0 +1,20 @@ +#version 120 + +// +// metavoxel_heightfield_cursor.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/7/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the cursor texture +uniform sampler2D cursorMap; + +void main(void) { + // just multiply the color by the cursor texture + gl_FragColor = gl_Color * texture2D(cursorMap, gl_TexCoord[0].st); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_cursor.vert b/interface/resources/shaders/metavoxel_heightfield_cursor.vert new file mode 100644 index 0000000000..20502fbdce --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_cursor.vert @@ -0,0 +1,31 @@ +#version 120 + +// +// metavoxel_heighfield_cursor.vert +// vertex shader +// +// Created by Andrzej Kapolka on 8/7/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// the height texture +uniform sampler2D heightMap; + +// the distance between height points in texture space +uniform float heightScale; + +void main(void) { + // compute the view space coordinates + float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; + vec4 viewPosition = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + gl_Position = gl_ProjectionMatrix * viewPosition; + + // generate the texture coordinates from the view position + gl_TexCoord[0] = vec4(dot(viewPosition, gl_EyePlaneS[4]), dot(viewPosition, gl_EyePlaneT[4]), 0.0, 1.0); + + // the zero height should be invisible + gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0 - step(height, 0.0)); +} diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index f66d71070a..85a1f5a1fc 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -31,6 +31,10 @@ REGISTER_META_OBJECT(StaticModelRenderer) static int bufferPointVectorMetaTypeId = qRegisterMetaType(); +MetavoxelSystem::MetavoxelSystem() : + _cursorTexture(QOpenGLTexture::Target2D) { +} + void MetavoxelSystem::init() { MetavoxelClientManager::init(); DefaultMetavoxelRendererImplementation::init(); @@ -118,6 +122,105 @@ void MetavoxelSystem::render() { guideToAugmented(renderVisitor); } +class HeightfieldCursorRenderVisitor : public MetavoxelVisitor { +public: + + HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds); + + virtual int visit(MetavoxelInfo& info); + +private: + + Box _bounds; +}; + +HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const MetavoxelLOD& lod, const Box& bounds) : + MetavoxelVisitor(QVector() << + Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector(), lod), + _bounds(bounds) { +} + +int HeightfieldCursorRenderVisitor::visit(MetavoxelInfo& info) { + if (!info.getBounds().intersects(_bounds)) { + return STOP_RECURSION; + } + if (!info.isLeaf) { + return DEFAULT_ORDER; + } + BufferDataPointer buffer = info.inputValues.at(0).getInlineValue(); + if (buffer) { + buffer->render(true); + } + return STOP_RECURSION; +} + +void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float radius) { + // create the cursor texture lazily + if (!_cursorTexture.isCreated()) { + const int CURSOR_TEXTURE_SIZE = 512; + QImage cursorImage(CURSOR_TEXTURE_SIZE, CURSOR_TEXTURE_SIZE, QImage::Format_ARGB32_Premultiplied); + cursorImage.fill(0x0); + { + QPainter painter(&cursorImage); + const int ELLIPSE_EDGE = 10; + const int OUTER_WIDTH = 10; + QPen outerPen; + outerPen.setWidth(OUTER_WIDTH); + painter.setPen(outerPen); + const int HALF_TEXTURE_SIZE = CURSOR_TEXTURE_SIZE / 2; + painter.drawEllipse(QPoint(HALF_TEXTURE_SIZE, HALF_TEXTURE_SIZE), HALF_TEXTURE_SIZE - ELLIPSE_EDGE, + HALF_TEXTURE_SIZE - ELLIPSE_EDGE); + QPen innerPen(Qt::white); + const int INNER_WIDTH = 6; + innerPen.setWidth(INNER_WIDTH); + painter.setPen(innerPen); + painter.drawEllipse(QPoint(HALF_TEXTURE_SIZE, HALF_TEXTURE_SIZE), HALF_TEXTURE_SIZE - ELLIPSE_EDGE, + HALF_TEXTURE_SIZE - ELLIPSE_EDGE); + } + _cursorTexture.setData(cursorImage, QOpenGLTexture::DontGenerateMipMaps); + _cursorTexture.setWrapMode(QOpenGLTexture::ClampToEdge); + _cursorTexture.setMinificationFilter(QOpenGLTexture::Linear); + } + + glDepthFunc(GL_LEQUAL); + glEnable(GL_CULL_FACE); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -1.0f); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().bind(); + + glActiveTexture(GL_TEXTURE4); + float scale = 1.0f / radius; + glm::vec4 sCoefficients(scale, 0.0f, 0.0f, 0.5f - scale * position.x); + glm::vec4 tCoefficients(0.0f, 0.0f, scale, 0.5f - scale * position.z); + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); + + _cursorTexture.bind(1); + glActiveTexture(GL_TEXTURE0); + + glm::vec3 extents(radius, radius, radius); + HeightfieldCursorRenderVisitor visitor(getLOD(), Box(position - extents, position + extents)); + guideToAugmented(visitor); + + _cursorTexture.release(1); + glActiveTexture(GL_TEXTURE0); + + DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release(); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_CULL_FACE); + glDepthFunc(GL_LESS); +} + void MetavoxelSystem::deleteTextures(int heightID, int colorID) { glDeleteTextures(1, (GLuint*)&heightID); glDeleteTextures(1, (GLuint*)&colorID); @@ -239,7 +342,7 @@ PointBuffer::PointBuffer(const BufferPointVector& points) : _points(points) { } -void PointBuffer::render() { +void PointBuffer::render(bool cursor) { // initialize buffer, etc. on first render if (!_buffer.isCreated()) { _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); @@ -294,7 +397,7 @@ public: glm::vec3 vertex; }; -void HeightfieldBuffer::render() { +void HeightfieldBuffer::render(bool cursor) { // initialize textures, etc. on first render if (_heightTextureID == 0) { glGenTextures(1, &_heightTextureID); @@ -385,17 +488,24 @@ void HeightfieldBuffer::render() { glBindTexture(GL_TEXTURE_2D, _heightTextureID); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, _colorTextureID); + int heightScaleLocation; + if (cursor) { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getCursorHeightScaleLocation(); + } else { + heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation(); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, _colorTextureID); + } - DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( - DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue(heightScaleLocation, 1.0f / _heightSize); glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); - glBindTexture(GL_TEXTURE_2D, 0); + if (!cursor) { + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + } - glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glPopMatrix(); @@ -475,6 +585,18 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldProgram.setUniformValue("diffuseMap", 1); _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); _heightfieldProgram.release(); + + _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield_cursor.vert"); + _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_cursor.frag"); + _heightfieldCursorProgram.link(); + + _heightfieldCursorProgram.bind(); + _heightfieldCursorProgram.setUniformValue("heightMap", 0); + _heightfieldCursorProgram.setUniformValue("cursorMap", 1); + _cursorHeightScaleLocation = _heightfieldCursorProgram.uniformLocation("heightScale"); + _heightfieldCursorProgram.release(); } } @@ -771,6 +893,8 @@ ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; int DefaultMetavoxelRendererImplementation::_pointScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; int DefaultMetavoxelRendererImplementation::_heightScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram; +int DefaultMetavoxelRendererImplementation::_cursorHeightScaleLocation; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { GLdouble coefficients[] = { x, y, z, w }; diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index e7ee0d2c18..a2d3128cb7 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -31,6 +32,8 @@ class MetavoxelSystem : public MetavoxelClientManager { public: + MetavoxelSystem(); + virtual void init(); virtual MetavoxelLOD getLOD(); @@ -43,6 +46,8 @@ public: void simulate(float deltaTime); void render(); + void renderHeightfieldCursor(const glm::vec3& position, float radius); + Q_INVOKABLE void deleteTextures(int heightID, int colorID); protected: @@ -59,6 +64,8 @@ private: MetavoxelLOD _lod; QReadWriteLock _lodLock; Frustum _frustum; + + QOpenGLTexture _cursorTexture; }; /// Describes contents of a point in a point buffer. @@ -105,7 +112,7 @@ public: virtual ~BufferData(); - virtual void render() = 0; + virtual void render(bool cursor = false) = 0; }; typedef QExplicitlySharedDataPointer BufferDataPointer; @@ -116,7 +123,7 @@ public: PointBuffer(const BufferPointVector& points); - virtual void render(); + virtual void render(bool cursor = false); private: @@ -140,7 +147,7 @@ public: const QByteArray& getHeight() const { return _height; } const QByteArray& getColor() const { return _color; } - virtual void render(); + virtual void render(bool cursor = false); private: @@ -193,6 +200,9 @@ public: static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } static int getHeightScaleLocation() { return _heightScaleLocation; } + static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; } + static int getCursorHeightScaleLocation() { return _cursorHeightScaleLocation; } + Q_INVOKABLE DefaultMetavoxelRendererImplementation(); virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); @@ -206,6 +216,9 @@ private: static ProgramObject _heightfieldProgram; static int _heightScaleLocation; + + static ProgramObject _heightfieldCursorProgram; + static int _cursorHeightScaleLocation; }; /// Base class for spanner renderers; provides clipping. diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 01b5ad0718..28a4d6da27 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -1105,15 +1105,7 @@ void HeightfieldBrushTool::render() { return; } glm::vec3 point = origin + distance * direction; - - glPushMatrix(); - glTranslatef(point.x, point.y, point.z); - - glColor4f(1.0f, 0.0f, 0.0f, 1.0f); - - glutSolidSphere(1.0f, 8, 8); - - glPopMatrix(); + Application::getInstance()->getMetavoxels()->renderHeightfieldCursor(point, _radius->value()); } HeightBrushTool::HeightBrushTool(MetavoxelEditor* editor) : diff --git a/libraries/metavoxels/src/MetavoxelClientManager.cpp b/libraries/metavoxels/src/MetavoxelClientManager.cpp index 0ffdefd134..70b574d2a2 100644 --- a/libraries/metavoxels/src/MetavoxelClientManager.cpp +++ b/libraries/metavoxels/src/MetavoxelClientManager.cpp @@ -194,7 +194,8 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance glm::vec3 intersection = relativeEntry + planeDistance * _direction; if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && intersection.z >= intersection.x) { - intersectionDistance = distance + (accumulatedDistance + planeDistance) * (info.size / highest); + intersectionDistance = qMin(intersectionDistance, distance + + (accumulatedDistance + planeDistance) * (info.size / highest)); return SHORT_CIRCUIT; } } @@ -207,7 +208,8 @@ int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance glm::vec3 intersection = relativeEntry + planeDistance * _direction; if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && intersection.x >= intersection.z) { - intersectionDistance = distance + (accumulatedDistance + planeDistance) * (info.size / highest); + intersectionDistance = qMin(intersectionDistance, distance + + (accumulatedDistance + planeDistance) * (info.size / highest)); return SHORT_CIRCUIT; } }