From 416d9bac2ef25313f6ccd78b794b8cbfdbc46a91 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 20 Aug 2014 14:48:02 -0700 Subject: [PATCH] Working on texture rendering. --- .../shaders/metavoxel_heightfield_base.frag | 20 ++ .../shaders/metavoxel_heightfield_base.vert | 33 +++ .../shaders/metavoxel_heightfield_light.frag | 21 ++ .../shaders/metavoxel_heightfield_light.vert | 45 +++ ...heightfield_light_cascaded_shadow_map.frag | 44 +++ ...etavoxel_heightfield_light_shadow_map.frag | 33 +++ .../shaders/metavoxel_heightfield_splat.frag | 20 ++ .../shaders/metavoxel_heightfield_splat.vert | 33 +++ interface/src/MetavoxelSystem.cpp | 260 ++++++++++++------ interface/src/MetavoxelSystem.h | 49 +++- interface/src/renderer/TextureCache.cpp | 7 +- interface/src/renderer/TextureCache.h | 4 +- interface/src/ui/MetavoxelEditor.cpp | 6 +- .../metavoxels/src/MetavoxelMessages.cpp | 2 +- 14 files changed, 473 insertions(+), 104 deletions(-) create mode 100644 interface/resources/shaders/metavoxel_heightfield_base.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_base.vert create mode 100644 interface/resources/shaders/metavoxel_heightfield_light.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_light.vert create mode 100644 interface/resources/shaders/metavoxel_heightfield_light_cascaded_shadow_map.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_light_shadow_map.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_splat.frag create mode 100644 interface/resources/shaders/metavoxel_heightfield_splat.vert diff --git a/interface/resources/shaders/metavoxel_heightfield_base.frag b/interface/resources/shaders/metavoxel_heightfield_base.frag new file mode 100644 index 0000000000..9b64a59e6f --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_base.frag @@ -0,0 +1,20 @@ +#version 120 + +// +// metavoxel_heightfield_base.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/20/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 diffuse texture +uniform sampler2D diffuseMap; + +void main(void) { + // compute the base color based on OpenGL lighting model + gl_FragColor = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].st); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_base.vert b/interface/resources/shaders/metavoxel_heightfield_base.vert new file mode 100644 index 0000000000..3e4b081d6f --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_base.vert @@ -0,0 +1,33 @@ +#version 120 + +// +// metavoxel_heightfield_base.vert +// vertex shader +// +// Created by Andrzej Kapolka on 8/20/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; + +// the scale between height and color textures +uniform float colorScale; + +void main(void) { + // add the height to the position + float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; + gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + + // the zero height should be invisible + gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); + + // pass along the scaled/offset texture coordinates + gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale; +} diff --git a/interface/resources/shaders/metavoxel_heightfield_light.frag b/interface/resources/shaders/metavoxel_heightfield_light.frag new file mode 100644 index 0000000000..ce3f23e142 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_light.frag @@ -0,0 +1,21 @@ +#version 120 + +// +// metavoxel_heightfield_light.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/20/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 interpolated normal +varying vec4 normal; + +void main(void) { + // compute the base color based on OpenGL lighting model + gl_FragColor = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normalize(normal), gl_LightSource[0].position))); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_light.vert b/interface/resources/shaders/metavoxel_heightfield_light.vert new file mode 100644 index 0000000000..228d575b81 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_light.vert @@ -0,0 +1,45 @@ +#version 120 + +// +// metavoxel_heighfield_light.vert +// vertex shader +// +// Created by Andrzej Kapolka on 8/20/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; + +// the interpolated position +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // transform and store the normal for interpolation + vec2 heightCoord = gl_MultiTexCoord0.st; + float deltaX = texture2D(heightMap, heightCoord - vec2(heightScale, 0.0)).r - + texture2D(heightMap, heightCoord + vec2(heightScale, 0.0)).r; + float deltaZ = texture2D(heightMap, heightCoord - vec2(0.0, heightScale)).r - + texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; + normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); + + // add the height to the position + float height = texture2D(heightMap, heightCoord).r; + position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + gl_Position = gl_ProjectionMatrix * position; + + // the zero height should be invisible + gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); + + // and the shadow texture coordinates + gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_light_cascaded_shadow_map.frag b/interface/resources/shaders/metavoxel_heightfield_light_cascaded_shadow_map.frag new file mode 100644 index 0000000000..73382eb83c --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_light_cascaded_shadow_map.frag @@ -0,0 +1,44 @@ +#version 120 + +// +// metavoxel_heightfield_light_cascaded_shadow_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/20/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 shadow texture +uniform sampler2DShadow shadowMap; + +// the distances to the cascade sections +uniform vec3 shadowDistances; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated position +varying vec4 position; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the index of the cascade to use and the corresponding texture coordinates + int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); + vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), + dot(gl_EyePlaneR[shadowIndex], position)); + + // compute the base color based on OpenGL lighting model + float diffuse = dot(normalize(normal), gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); + gl_FragColor = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_light_shadow_map.frag b/interface/resources/shaders/metavoxel_heightfield_light_shadow_map.frag new file mode 100644 index 0000000000..4f2df8958b --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_light_shadow_map.frag @@ -0,0 +1,33 @@ +#version 120 + +// +// metavoxel_heightfield_light_shadow_map.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/20/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 shadow texture +uniform sampler2DShadow shadowMap; + +// the inverse of the size of the shadow map +const float shadowScale = 1.0 / 2048.0; + +// the interpolated normal +varying vec4 normal; + +void main(void) { + // compute the base color based on OpenGL lighting model + float diffuse = dot(normalize(normal), gl_LightSource[0].position); + float facingLight = step(0.0, diffuse) * 0.25 * + (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + + shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); + gl_FragColor = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_splat.frag b/interface/resources/shaders/metavoxel_heightfield_splat.frag new file mode 100644 index 0000000000..7b73cf331b --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_splat.frag @@ -0,0 +1,20 @@ +#version 120 + +// +// metavoxel_heightfield_splat.frag +// fragment shader +// +// Created by Andrzej Kapolka on 8/20/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 diffuse texture +uniform sampler2D diffuseMap; + +void main(void) { + // compute the base color based on OpenGL lighting model + gl_FragColor = gl_Color * texture2D(diffuseMap, gl_TexCoord[0].st); +} diff --git a/interface/resources/shaders/metavoxel_heightfield_splat.vert b/interface/resources/shaders/metavoxel_heightfield_splat.vert new file mode 100644 index 0000000000..0f36605454 --- /dev/null +++ b/interface/resources/shaders/metavoxel_heightfield_splat.vert @@ -0,0 +1,33 @@ +#version 120 + +// +// metavoxel_heighfield_splat.vert +// vertex shader +// +// Created by Andrzej Kapolka on 8/20/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; + +// the scale between height and texture textures +uniform float textureScale; + +void main(void) { + // add the height to the position + float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; + gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); + + // the zero height should be invisible + gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); + + // pass along the scaled/offset texture coordinates + gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * textureScale; +} diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 4cdd2498e6..41ae254c71 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -602,24 +602,23 @@ const int HeightfieldBuffer::SHARED_EDGE = 1; const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE; HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, - const QByteArray& height, const QByteArray& color, const QByteArray& texture) : + const QByteArray& height, const QByteArray& color, const QByteArray& texture, + const QVector& textures) : _translation(translation), _scale(scale), _heightBounds(translation, translation + glm::vec3(scale, scale, scale)), _colorBounds(_heightBounds), - _textureBounds(_heightBounds), _height(height), _color(color), _texture(texture), + _textures(textures), _heightTextureID(0), _colorTextureID(0), _textureTextureID(0), _heightSize(glm::sqrt(height.size())), _heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)), _colorSize(glm::sqrt(color.size() / HeightfieldData::COLOR_BYTES)), - _colorIncrement(scale / (_colorSize - SHARED_EDGE)), - _textureSize(glm::sqrt(texture.size())), - _textureIncrement(scale / (_textureSize - SHARED_EDGE)) { + _colorIncrement(scale / (_colorSize - SHARED_EDGE)) { _heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER; _heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER; @@ -628,9 +627,6 @@ HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, _colorBounds.maximum.x += _colorIncrement * SHARED_EDGE; _colorBounds.maximum.z += _colorIncrement * SHARED_EDGE; - - _textureBounds.maximum.x += _textureIncrement * SHARED_EDGE; - _textureBounds.maximum.z += _textureIncrement * SHARED_EDGE; } HeightfieldBuffer::~HeightfieldBuffer() { @@ -712,6 +708,15 @@ void HeightfieldBuffer::render(bool cursor) { int textureSize = glm::sqrt(_texture.size()); glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, textureSize, textureSize, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, _texture.constData()); + + _networkTextures.resize(_textures.size()); + for (int i = 0; i < _textures.size(); i++) { + const SharedObjectPointer texture = _textures.at(i); + if (texture) { + _networkTextures[i] = Application::getInstance()->getTextureCache()->getTexture( + static_cast(texture.data())->getURL()); + } + } } } // create the buffer objects lazily @@ -780,7 +785,56 @@ void HeightfieldBuffer::render(bool cursor) { glBindTexture(GL_TEXTURE_2D, _heightTextureID); - if (!cursor) { + if (cursor) { + glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); + + } else if (!_textures.isEmpty()) { + DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().bind(); + DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getBaseHeightScaleLocation(), 1.0f / _heightSize); + DefaultMetavoxelRendererImplementation::getBaseHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getBaseColorScaleLocation(), (float)_heightSize / innerSize); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, _colorTextureID); + + glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); + + glDepthFunc(GL_LEQUAL); + glEnable(GL_BLEND); + glBlendFunc(GL_DST_COLOR, GL_ZERO); + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1.0f, -1.0f); + + glBindTexture(GL_TEXTURE_2D, 0); + + if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) { + DefaultMetavoxelRendererImplementation::getShadowLightHeightfieldProgram().bind(); + DefaultMetavoxelRendererImplementation::getShadowLightHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getShadowLightHeightScaleLocation(), 1.0f / _heightSize); + + } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + DefaultMetavoxelRendererImplementation::getCascadedShadowLightHeightfieldProgram().bind(); + DefaultMetavoxelRendererImplementation::getCascadedShadowLightHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getCascadedShadowLightHeightScaleLocation(), 1.0f / _heightSize); + + } else { + DefaultMetavoxelRendererImplementation::getLightHeightfieldProgram().bind(); + DefaultMetavoxelRendererImplementation::getLightHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getBaseHeightScaleLocation(), 1.0f / _heightSize); + } + + glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); + + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().bind(); + + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); + glDepthFunc(GL_LESS); + + glActiveTexture(GL_TEXTURE0); + + } else { int heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation(); int colorScaleLocation = DefaultMetavoxelRendererImplementation::getColorScaleLocation(); ProgramObject* program = &DefaultMetavoxelRendererImplementation::getHeightfieldProgram(); @@ -798,11 +852,9 @@ void HeightfieldBuffer::render(bool cursor) { program->setUniformValue(colorScaleLocation, (float)_heightSize / innerSize); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _colorTextureID); - } - - glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); - - if (!cursor) { + + glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); + glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); } @@ -919,6 +971,68 @@ void DefaultMetavoxelRendererImplementation::init() { _shadowDistancesLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("shadowDistances"); _cascadedShadowMapHeightfieldProgram.release(); + _baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield_base.vert"); + _baseHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_base.frag"); + _baseHeightfieldProgram.link(); + + _baseHeightfieldProgram.bind(); + _baseHeightfieldProgram.setUniformValue("heightMap", 0); + _baseHeightfieldProgram.setUniformValue("diffuseMap", 1); + _baseHeightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); + _baseColorScaleLocation = _heightfieldProgram.uniformLocation("colorScale"); + _baseHeightfieldProgram.release(); + + _splatHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield_splat.vert"); + _splatHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_splat.frag"); + _splatHeightfieldProgram.link(); + + _splatHeightfieldProgram.bind(); + _splatHeightfieldProgram.setUniformValue("heightMap", 0); + _splatHeightfieldProgram.setUniformValue("diffuseMap", 1); + _splatHeightScaleLocation = _splatHeightfieldProgram.uniformLocation("heightScale"); + _splatTextureScaleLocation = _splatHeightfieldProgram.uniformLocation("textureScale"); + _splatHeightfieldProgram.release(); + + _lightHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield_light.vert"); + _lightHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_light.frag"); + _lightHeightfieldProgram.link(); + + _lightHeightfieldProgram.bind(); + _lightHeightfieldProgram.setUniformValue("heightMap", 0); + _lightHeightScaleLocation = _lightHeightfieldProgram.uniformLocation("heightScale"); + _lightHeightfieldProgram.release(); + + _shadowLightHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield_light.vert"); + _shadowLightHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_light_shadow_map.frag"); + _shadowLightHeightfieldProgram.link(); + + _shadowLightHeightfieldProgram.bind(); + _shadowLightHeightfieldProgram.setUniformValue("heightMap", 0); + _shadowLightHeightfieldProgram.setUniformValue("shadowMap", 2); + _shadowLightHeightScaleLocation = _shadowLightHeightfieldProgram.uniformLocation("heightScale"); + _shadowLightHeightfieldProgram.release(); + + _cascadedShadowLightHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + + "shaders/metavoxel_heightfield_light.vert"); + _cascadedShadowLightHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + + "shaders/metavoxel_heightfield_light_cascaded_shadow_map.frag"); + _cascadedShadowLightHeightfieldProgram.link(); + + _cascadedShadowLightHeightfieldProgram.bind(); + _cascadedShadowLightHeightfieldProgram.setUniformValue("heightMap", 0); + _cascadedShadowLightHeightfieldProgram.setUniformValue("shadowMap", 2); + _cascadedShadowLightHeightScaleLocation = _cascadedShadowLightHeightfieldProgram.uniformLocation("heightScale"); + _shadowLightDistancesLocation = _cascadedShadowLightHeightfieldProgram.uniformLocation("shadowDistances"); + _cascadedShadowLightHeightfieldProgram.release(); + _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_heightfield_cursor.vert"); _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + @@ -1019,8 +1133,7 @@ private: HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector& intersections) : MetavoxelVisitor(QVector() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << - AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << - AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), QVector(), lod), + AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector(), lod), _intersections(intersections) { } @@ -1135,50 +1248,6 @@ int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) { } } } - - int textureSize = _buffer->getTextureSize(); - if (textureSize == 0) { - continue; - } - HeightfieldTextureDataPointer texture = info.inputValues.at(2).getInlineValue(); - if (!texture) { - continue; - } - const Box& textureBounds = _buffer->getTextureBounds(); - overlap = textureBounds.getIntersection(overlap); - float textureIncrement = _buffer->getTextureIncrement(); - destX = (overlap.minimum.x - textureBounds.minimum.x) / textureIncrement; - destY = (overlap.minimum.z - textureBounds.minimum.z) / textureIncrement; - destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / textureIncrement); - destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / textureIncrement); - dest = _buffer->getTexture().data() + destY * textureSize + destX; - - const QByteArray& srcTexture = texture->getContents(); - srcSize = glm::sqrt(srcTexture.size()); - srcIncrement = info.size / srcSize; - - if (srcIncrement == textureIncrement) { - // easy case: same resolution - int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; - int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; - - const char* src = srcTexture.constData() + srcY * srcSize + srcX; - for (int y = 0; y < destHeight; y++, src += srcSize, dest += textureSize) { - memcpy(dest, src, destWidth); - } - } else { - // more difficult: different resolutions - float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; - float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; - float srcAdvance = textureIncrement / srcIncrement; - for (int y = 0; y < destHeight; y++, dest += textureSize, srcY += srcAdvance) { - const char* src = srcTexture.constData() + (int)srcY * srcSize; - float lineSrcX = srcX; - for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) { - *lineDest = src[(int)lineSrcX]; - } - } - } } return STOP_RECURSION; } @@ -1233,42 +1302,43 @@ int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) { } HeightfieldTextureDataPointer texture = info.inputValues.at(2).getInlineValue(); - int textureContentsSize = 0; + QByteArray textureContents; + QVector textures; if (texture) { - const QByteArray& textureContents = texture->getContents(); - int textureSize = glm::sqrt(textureContents.size()); - int extendedTextureSize = textureSize + HeightfieldBuffer::SHARED_EDGE; - textureContentsSize = extendedTextureSize * extendedTextureSize; + textureContents = texture->getContents(); + textures = texture->getTextures(); } const HeightfieldBuffer* existingBuffer = static_cast( info.inputValues.at(3).getInlineValue().data()); Box bounds = info.getBounds(); if (existingBuffer && existingBuffer->getHeight().size() == heightContentsSize && - existingBuffer->getColor().size() == colorContentsSize && - existingBuffer->getTexture().size() == textureContentsSize) { + existingBuffer->getColor().size() == colorContentsSize) { // we already have a buffer of the correct resolution addRegion(bounds, existingBuffer->getHeightBounds()); - return STOP_RECURSION; + buffer = new HeightfieldBuffer(info.minimum, info.size, existingBuffer->getHeight(), + existingBuffer->getColor(), textureContents, textures); + + } else { + // we must create a new buffer and update its borders + buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0), + QByteArray(colorContentsSize, 0), textureContents, textures); + const Box& heightBounds = buffer->getHeightBounds(); + addRegion(bounds, heightBounds); + + _intersections.clear(); + _intersections.append(Box(heightBounds.minimum, + glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z))); + _intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z), + glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z))); + _intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z), + heightBounds.maximum)); + _intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z), + glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z))); + + _fetchVisitor.init(buffer); + _data->guide(_fetchVisitor); } - // we must create a new buffer and update its borders - buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0), - QByteArray(colorContentsSize, 0), QByteArray(textureContentsSize, 0)); - const Box& heightBounds = buffer->getHeightBounds(); - addRegion(bounds, heightBounds); - - _intersections.clear(); - _intersections.append(Box(heightBounds.minimum, - glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z))); - _intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z), - glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z))); - _intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z), - heightBounds.maximum)); - _intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z), - glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z))); - - _fetchVisitor.init(buffer); - _data->guide(_fetchVisitor); } info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); return STOP_RECURSION; @@ -1326,7 +1396,7 @@ int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) { return STOP_RECURSION; } HeightfieldBuffer* newBuffer = new HeightfieldBuffer(info.minimum, info.size, - buffer->getHeight(), buffer->getColor(), buffer->getTexture()); + buffer->getHeight(), buffer->getColor(), buffer->getTexture(), buffer->getTextures()); _fetchVisitor.init(newBuffer); _data->guide(_fetchVisitor); info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(newBuffer))); @@ -1514,6 +1584,9 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox ProgramObject* program = &_heightfieldProgram; if (Menu::getInstance()->getShadowsEnabled()) { if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { + _cascadedShadowLightHeightfieldProgram.bind(); + _cascadedShadowLightHeightfieldProgram.setUniform(_shadowLightDistancesLocation, + Application::getInstance()->getShadowDistances()); program = &_cascadedShadowMapHeightfieldProgram; program->bind(); program->setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances()); @@ -1559,6 +1632,19 @@ ProgramObject DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightfi int DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightScaleLocation; int DefaultMetavoxelRendererImplementation::_cascadedShadowMapColorScaleLocation; int DefaultMetavoxelRendererImplementation::_shadowDistancesLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_baseHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_baseHeightScaleLocation; +int DefaultMetavoxelRendererImplementation::_baseColorScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_splatHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_splatHeightScaleLocation; +int DefaultMetavoxelRendererImplementation::_splatTextureScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_lightHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_lightHeightScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_shadowLightHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_shadowLightHeightScaleLocation; +ProgramObject DefaultMetavoxelRendererImplementation::_cascadedShadowLightHeightfieldProgram; +int DefaultMetavoxelRendererImplementation::_cascadedShadowLightHeightScaleLocation; +int DefaultMetavoxelRendererImplementation::_shadowLightDistancesLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram; static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index 206c378fd1..dc2ff8633a 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -140,7 +140,8 @@ public: static const int HEIGHT_EXTENSION; HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, - const QByteArray& color, const QByteArray& texture); + const QByteArray& color, const QByteArray& texture = QByteArray(), + const QVector& textures = QVector()); ~HeightfieldBuffer(); const glm::vec3& getTranslation() const { return _translation; } @@ -148,7 +149,6 @@ public: const Box& getHeightBounds() const { return _heightBounds; } const Box& getColorBounds() const { return _colorBounds; } - const Box& getTextureBounds() const { return _textureBounds; } QByteArray& getHeight() { return _height; } const QByteArray& getHeight() const { return _height; } @@ -159,6 +159,8 @@ public: QByteArray& getTexture() { return _texture; } const QByteArray& getTexture() const { return _texture; } + const QVector& getTextures() const { return _textures; } + QByteArray getUnextendedHeight() const; QByteArray getUnextendedColor() const; @@ -168,9 +170,6 @@ public: int getColorSize() const { return _colorSize; } float getColorIncrement() const { return _colorIncrement; } - int getTextureSize() const { return _textureSize; } - float getTextureIncrement() const { return _textureIncrement; } - virtual void render(bool cursor = false); private: @@ -179,19 +178,18 @@ private: float _scale; Box _heightBounds; Box _colorBounds; - Box _textureBounds; QByteArray _height; QByteArray _color; QByteArray _texture; + QVector _textures; GLuint _heightTextureID; GLuint _colorTextureID; GLuint _textureTextureID; + QVector _networkTextures; int _heightSize; float _heightIncrement; int _colorSize; float _colorIncrement; - int _textureSize; - float _textureIncrement; typedef QPair BufferPair; static QHash _bufferPairs; @@ -244,6 +242,23 @@ public: static int getCascadedShadowMapHeightScaleLocation() { return _cascadedShadowMapHeightScaleLocation; } static int getCascadedShadowMapColorScaleLocation() { return _cascadedShadowMapColorScaleLocation; } + static ProgramObject& getBaseHeightfieldProgram() { return _baseHeightfieldProgram; } + static int getBaseHeightScaleLocation() { return _baseHeightScaleLocation; } + static int getBaseColorScaleLocation() { return _baseColorScaleLocation; } + + static ProgramObject& getSplatHeightfieldProgram() { return _splatHeightfieldProgram; } + static int getSplatHeightScaleLocation() { return _splatHeightScaleLocation; } + static int getSplatTextureScaleLocation() { return _splatTextureScaleLocation; } + + static ProgramObject& getLightHeightfieldProgram() { return _lightHeightfieldProgram; } + static int getLightHeightScaleLocation() { return _lightHeightScaleLocation; } + + static ProgramObject& getShadowLightHeightfieldProgram() { return _shadowLightHeightfieldProgram; } + static int getShadowLightHeightScaleLocation() { return _shadowLightHeightScaleLocation; } + + static ProgramObject& getCascadedShadowLightHeightfieldProgram() { return _cascadedShadowLightHeightfieldProgram; } + static int getCascadedShadowLightHeightScaleLocation() { return _cascadedShadowLightHeightScaleLocation; } + static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; } Q_INVOKABLE DefaultMetavoxelRendererImplementation(); @@ -270,6 +285,24 @@ private: static int _cascadedShadowMapColorScaleLocation; static int _shadowDistancesLocation; + static ProgramObject _baseHeightfieldProgram; + static int _baseHeightScaleLocation; + static int _baseColorScaleLocation; + + static ProgramObject _splatHeightfieldProgram; + static int _splatHeightScaleLocation; + static int _splatTextureScaleLocation; + + static ProgramObject _lightHeightfieldProgram; + static int _lightHeightScaleLocation; + + static ProgramObject _shadowLightHeightfieldProgram; + static int _shadowLightHeightScaleLocation; + + static ProgramObject _cascadedShadowLightHeightfieldProgram; + static int _cascadedShadowLightHeightScaleLocation; + static int _shadowLightDistancesLocation; + static ProgramObject _heightfieldCursorProgram; }; diff --git a/interface/src/renderer/TextureCache.cpp b/interface/src/renderer/TextureCache.cpp index 11c4778c19..ee10d67ee9 100644 --- a/interface/src/renderer/TextureCache.cpp +++ b/interface/src/renderer/TextureCache.cpp @@ -179,15 +179,14 @@ public: const QByteArray& content; }; -QSharedPointer TextureCache::getTexture(const QUrl& url, bool normalMap, - bool dilatable, const QByteArray& content) { +NetworkTexturePointer TextureCache::getTexture(const QUrl& url, bool normalMap, bool dilatable, const QByteArray& content) { if (!dilatable) { TextureExtra extra = { normalMap, content }; return ResourceCache::getResource(url, QUrl(), false, &extra).staticCast(); } - QSharedPointer texture = _dilatableNetworkTextures.value(url); + NetworkTexturePointer texture = _dilatableNetworkTextures.value(url); if (texture.isNull()) { - texture = QSharedPointer(new DilatableNetworkTexture(url, content), &Resource::allReferencesCleared); + texture = NetworkTexturePointer(new DilatableNetworkTexture(url, content), &Resource::allReferencesCleared); texture->setSelf(texture); texture->setCache(this); _dilatableNetworkTextures.insert(url, texture); diff --git a/interface/src/renderer/TextureCache.h b/interface/src/renderer/TextureCache.h index 58f9345c4a..06f724d70d 100644 --- a/interface/src/renderer/TextureCache.h +++ b/interface/src/renderer/TextureCache.h @@ -23,6 +23,8 @@ class QOpenGLFramebufferObject; class NetworkTexture; +typedef QSharedPointer NetworkTexturePointer; + /// Stores cached textures, including render-to-texture targets. class TextureCache : public ResourceCache { Q_OBJECT @@ -47,7 +49,7 @@ public: GLuint getBlueTextureID(); /// Loads a texture from the specified URL. - QSharedPointer getTexture(const QUrl& url, bool normalMap = false, bool dilatable = false, + NetworkTexturePointer getTexture(const QUrl& url, bool normalMap = false, bool dilatable = false, const QByteArray& content = QByteArray()); /// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 2c99caf7d2..3ca509cd95 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -974,7 +974,8 @@ void ImportHeightfieldTool::apply() { data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue( AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer)))); - QByteArray texture(height.size(), 0); + int size = glm::sqrt(height.size()) + HeightfieldBuffer::SHARED_EDGE; + QByteArray texture(size * size, 0); HeightfieldTextureDataPointer texturePointer(new HeightfieldTextureData(texture)); data.setRoot(AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), new MetavoxelNode(AttributeValue( AttributeRegistry::getInstance()->getHeightfieldTextureAttribute(), encodeInline(texturePointer)))); @@ -1049,8 +1050,7 @@ void ImportHeightfieldTool::updatePreview() { columns * HeightfieldData::COLOR_BYTES); } } - buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, - height, color, QByteArray()))); + buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color))); } } } diff --git a/libraries/metavoxels/src/MetavoxelMessages.cpp b/libraries/metavoxels/src/MetavoxelMessages.cpp index 33aea9fcb1..1a8f64d935 100644 --- a/libraries/metavoxels/src/MetavoxelMessages.cpp +++ b/libraries/metavoxels/src/MetavoxelMessages.cpp @@ -593,7 +593,7 @@ int PaintHeightfieldTextureEditVisitor::visit(MetavoxelInfo& info) { } int size = glm::sqrt((float)contents.size()); int highest = size - 1; - float heightScale = size / info.size; + float heightScale = highest / info.size; glm::vec3 center = (_edit.position - info.minimum) * heightScale; float scaledRadius = _edit.radius * heightScale;