From f8afdba92216fe46080f2c4b72ec5d37e7d023a5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 4 Aug 2014 16:56:30 -0700 Subject: [PATCH 1/4] Allow configurable block sizes, merging children with different resolutions. --- interface/src/ui/MetavoxelEditor.cpp | 32 +++++--- interface/src/ui/MetavoxelEditor.h | 5 +- .../metavoxels/src/AttributeRegistry.cpp | 79 ++++++++++++++----- 3 files changed, 81 insertions(+), 35 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index cf4fd0bba9..096798e77e 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -930,6 +930,13 @@ void HeightfieldTool::render() { ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : HeightfieldTool(editor, "Import Heightfield") { + _form->addRow("Block Size:", _blockSize = new QSpinBox()); + _blockSize->setPrefix("2^"); + _blockSize->setMinimum(1); + _blockSize->setValue(5); + + connect(_blockSize, static_cast(&QSpinBox::valueChanged), this, + &ImportHeightfieldTool::updatePreview); _form->addRow("Height:", _height = new QPushButton()); connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); _form->addRow("Color:", _color = new QPushButton()); @@ -989,23 +996,22 @@ void ImportHeightfieldTool::selectColorFile() { updatePreview(); } -const int BLOCK_SIZE = 32; -const int BLOCK_ADVANCEMENT = BLOCK_SIZE - 1; - void ImportHeightfieldTool::updatePreview() { QVector buffers; if (_heightImage.width() > 0 && _heightImage.height() > 0) { float z = 0.0f; - for (int i = 0; i < _heightImage.height(); i += BLOCK_ADVANCEMENT, z++) { + int blockSize = pow(2.0, _blockSize->value()); + int blockAdvancement = blockSize - 1; + for (int i = 0; i < _heightImage.height(); i += blockAdvancement, z++) { float x = 0.0f; - for (int j = 0; j < _heightImage.width(); j += BLOCK_ADVANCEMENT, x++) { - QByteArray height(BLOCK_SIZE * BLOCK_SIZE, 0); - int rows = qMin(BLOCK_SIZE, _heightImage.height() - i); - int columns = qMin(BLOCK_SIZE, _heightImage.width() - j); + for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) { + QByteArray height(blockSize * blockSize, 0); + int rows = qMin(blockSize, _heightImage.height() - i); + int columns = qMin(blockSize, _heightImage.width() - j); const int BYTES_PER_COLOR = 3; for (int y = 0; y < rows; y++) { uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR; - char* dest = height.data() + y * BLOCK_SIZE; + char* dest = height.data() + y * blockSize; for (int x = 0; x < columns; x++) { *dest++ = *src; src += BYTES_PER_COLOR; @@ -1014,11 +1020,11 @@ void ImportHeightfieldTool::updatePreview() { QByteArray color; if (!_colorImage.isNull()) { - color = QByteArray(BLOCK_SIZE * BLOCK_SIZE * BYTES_PER_COLOR, 0); - rows = qMax(0, qMin(BLOCK_SIZE, _colorImage.height() - i)); - columns = qMax(0, qMin(BLOCK_SIZE, _colorImage.width() - j)); + color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0); + rows = qMax(0, qMin(blockSize, _colorImage.height() - i)); + columns = qMax(0, qMin(blockSize, _colorImage.width() - j)); for (int y = 0; y < rows; y++) { - memcpy(color.data() + y * BLOCK_SIZE * BYTES_PER_COLOR, + memcpy(color.data() + y * blockSize * BYTES_PER_COLOR, _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); } } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index abb1450f40..cc30896c49 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -267,10 +267,11 @@ private slots: void selectHeightFile(); void selectColorFile(); - + void updatePreview(); + private: - void updatePreview(); + QSpinBox* _blockSize; QPushButton* _height; QPushButton* _color; diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 7219e9da41..40b6195ada 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -559,9 +559,6 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) } const QByteArray& childContents = child->getContents(); int childSize = glm::sqrt((float)childContents.size()); - if (childSize != size) { - continue; // TODO: handle differently-sized children - } const int INDEX_MASK = 1; int xIndex = i & INDEX_MASK; const int Y_SHIFT = 1; @@ -576,13 +573,33 @@ bool HeightfieldAttribute::merge(void*& parent, void* children[], bool postRead) char* dest = contents.data() + (zIndex * halfSize * size) + (xIndex * halfSize); uchar* src = (uchar*)childContents.data(); int childSizePlusOne = childSize + 1; - for (int z = 0; z < halfSize; z++) { - for (char* end = dest + halfSize; dest != end; src += 2) { - int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])); - *dest++ = (max == 0) ? 0 : (yOffset + (max >> 1)); + if (childSize == size) { + // simple case: one destination value for four child values + for (int z = 0; z < halfSize; z++) { + for (char* end = dest + halfSize; dest != end; src += 2) { + int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])); + *dest++ = (max == 0) ? 0 : (yOffset + (max >> 1)); + } + dest += halfSize; + src += childSize; + } + } else { + // more complex: N destination values for four child values + int halfChildSize = childSize / 2; + int destPerSrc = size / childSize; + for (int z = 0; z < halfChildSize; z++) { + for (uchar* end = src + childSize; src != end; src += 2) { + int max = qMax(qMax(src[0], src[1]), qMax(src[childSize], src[childSizePlusOne])); + memset(dest, (max == 0) ? 0 : (yOffset + (max >> 1)), destPerSrc); + dest += destPerSrc; + } + dest += halfSize; + for (int j = 1; j < destPerSrc; j++) { + memcpy(dest, dest - size, halfSize); + dest += size; + } + src += childSize; } - dest += halfSize; - src += childSize; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); @@ -638,9 +655,6 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post } const QByteArray& childContents = child->getContents(); int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL); - if (childSize != size) { - continue; // TODO: handle differently-sized children - } const int INDEX_MASK = 1; int xIndex = i & INDEX_MASK; const int Y_SHIFT = 1; @@ -653,7 +667,8 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL; uchar* src = (uchar*)childContents.data(); int childStride = childSize * BYTES_PER_PIXEL; - int halfStride = halfSize * BYTES_PER_PIXEL; + int stride = size * BYTES_PER_PIXEL; + int halfStride = stride / 2; int childStep = 2 * BYTES_PER_PIXEL; int redOffset3 = childStride + BYTES_PER_PIXEL; int greenOffset1 = BYTES_PER_PIXEL + 1; @@ -662,14 +677,38 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post int blueOffset1 = BYTES_PER_PIXEL + 2; int blueOffset2 = childStride + 2; int blueOffset3 = childStride + BYTES_PER_PIXEL + 2; - for (int z = 0; z < halfSize; z++) { - for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { - *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; - *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; - *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; + if (childSize == size) { + // simple case: one destination value for four child values + for (int z = 0; z < halfSize; z++) { + for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { + *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; + *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; + *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; + } + dest += halfStride; + src += childStride; + } + } else { + // more complex: N destination values for four child values + int halfChildSize = childSize / 2; + int destPerSrc = size / childSize; + for (int z = 0; z < halfChildSize; z++) { + for (uchar* end = src + childSize * BYTES_PER_PIXEL; src != end; src += childStep) { + *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; + *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; + *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; + for (int j = 1; j < destPerSrc; j++) { + memcpy(dest, dest - BYTES_PER_PIXEL, BYTES_PER_PIXEL); + dest += BYTES_PER_PIXEL; + } + } + dest += halfStride; + for (int j = 1; j < destPerSrc; j++) { + memcpy(dest, dest - stride, halfStride); + dest += stride; + } + src += childStride; } - dest += halfStride; - src += childStride; } } *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(new HeightfieldData(contents)); From c42fc15999aa853f08a4bfc7178e0ea3be8ca2a1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Aug 2014 11:13:15 -0700 Subject: [PATCH 2/4] Use back face culling on the heightfields. --- interface/src/MetavoxelSystem.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 666a3336ac..7aa6bc4080 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -359,9 +359,9 @@ void HeightfieldBuffer::render() { int nextLineIndex = (i + 1) * sizeWithSkirt; for (int j = 0; j < rows; j++) { *index++ = lineIndex + j; - *index++ = lineIndex + j + 1; - *index++ = nextLineIndex + j + 1; *index++ = nextLineIndex + j; + *index++ = nextLineIndex + j + 1; + *index++ = lineIndex + j + 1; } } @@ -405,6 +405,7 @@ QHash HeightfieldBuffer::_bufferPairs; void HeightfieldPreview::render(const glm::vec3& translation, float scale) const { glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_EQUAL, 0.0f); @@ -431,6 +432,7 @@ void HeightfieldPreview::render(const glm::vec3& translation, float scale) const glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); glEnable(GL_BLEND); } @@ -737,6 +739,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox _pointProgram.release(); + glEnable(GL_CULL_FACE); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_EQUAL, 0.0f); @@ -756,6 +759,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox glDisableClientState(GL_VERTEX_ARRAY); glDisable(GL_ALPHA_TEST); + glDisable(GL_CULL_FACE); glEnable(GL_BLEND); } From 96302ca271bdf0c66d29e29756b2db4d9f99e1b4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Aug 2014 14:10:39 -0700 Subject: [PATCH 3/4] Provide for custom expansion according to attribute, tweak spanner attribute. --- .../metavoxels/src/AttributeRegistry.cpp | 47 +++++++++++++++++++ libraries/metavoxels/src/AttributeRegistry.h | 6 +++ libraries/metavoxels/src/MetavoxelData.cpp | 30 +++--------- libraries/metavoxels/src/MetavoxelData.h | 2 + 4 files changed, 61 insertions(+), 24 deletions(-) diff --git a/libraries/metavoxels/src/AttributeRegistry.cpp b/libraries/metavoxels/src/AttributeRegistry.cpp index 40b6195ada..9f656ef5d3 100644 --- a/libraries/metavoxels/src/AttributeRegistry.cpp +++ b/libraries/metavoxels/src/AttributeRegistry.cpp @@ -242,6 +242,30 @@ bool Attribute::metavoxelRootsEqual(const MetavoxelNode& firstRoot, const Metavo return firstRoot.deepEquals(this, secondRoot, minimum, size, lod); } +MetavoxelNode* Attribute::expandMetavoxelRoot(const MetavoxelNode& root) { + AttributePointer attribute(this); + MetavoxelNode* newParent = new MetavoxelNode(attribute); + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + MetavoxelNode* newChild = new MetavoxelNode(attribute); + newParent->setChild(i, newChild); + int index = MetavoxelNode::getOppositeChildIndex(i); + if (root.isLeaf()) { + newChild->setChild(index, new MetavoxelNode(root.getAttributeValue(attribute))); + } else { + MetavoxelNode* grandchild = root.getChild(i); + grandchild->incrementReferenceCount(); + newChild->setChild(index, grandchild); + } + for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) { + MetavoxelNode* newGrandchild = new MetavoxelNode(attribute); + newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild); + } + newChild->mergeChildren(attribute); + } + newParent->mergeChildren(attribute); + return newParent; +} + FloatAttribute::FloatAttribute(const QString& name, float defaultValue) : SimpleInlineAttribute(name, defaultValue) { } @@ -809,6 +833,29 @@ bool SharedObjectSetAttribute::deepEqual(void* first, void* second) const { return setsEqual(decodeInline(first), decodeInline(second)); } +MetavoxelNode* SharedObjectSetAttribute::expandMetavoxelRoot(const MetavoxelNode& root) { + AttributePointer attribute(this); + MetavoxelNode* newParent = new MetavoxelNode(attribute); + for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { + MetavoxelNode* newChild = new MetavoxelNode(root.getAttributeValue(attribute)); + newParent->setChild(i, newChild); + if (root.isLeaf()) { + continue; + } + MetavoxelNode* grandchild = root.getChild(i); + grandchild->incrementReferenceCount(); + int index = MetavoxelNode::getOppositeChildIndex(i); + newChild->setChild(index, grandchild); + for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) { + MetavoxelNode* newGrandchild = new MetavoxelNode(attribute); + newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild); + } + newChild->mergeChildren(attribute); + } + newParent->mergeChildren(attribute); + return newParent; +} + bool SharedObjectSetAttribute::merge(void*& parent, void* children[], bool postRead) const { for (int i = 0; i < MERGE_COUNT; i++) { if (!decodeInline(children[i]).isEmpty()) { diff --git a/libraries/metavoxels/src/AttributeRegistry.h b/libraries/metavoxels/src/AttributeRegistry.h index 767ebf6527..5d973341ad 100644 --- a/libraries/metavoxels/src/AttributeRegistry.h +++ b/libraries/metavoxels/src/AttributeRegistry.h @@ -238,6 +238,10 @@ public: virtual bool metavoxelRootsEqual(const MetavoxelNode& firstRoot, const MetavoxelNode& secondRoot, const glm::vec3& minimum, float size, const MetavoxelLOD& lod); + /// Expands the specified root, doubling its size in each dimension. + /// \return a new node representing the result + virtual MetavoxelNode* expandMetavoxelRoot(const MetavoxelNode& root); + /// Merges the value of a parent and its children. /// \param postRead whether or not the merge is happening after a read /// \return whether or not the children and parent values are all equal @@ -511,6 +515,8 @@ public: virtual bool deepEqual(void* first, void* second) const; + virtual MetavoxelNode* expandMetavoxelRoot(const MetavoxelNode& root); + virtual bool merge(void*& parent, void* children[], bool postRead = false) const; virtual AttributeValue inherit(const AttributeValue& parentValue) const; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index a0b1f1efb0..3607441461 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -512,33 +512,11 @@ void MetavoxelData::set(const glm::vec3& minimum, const MetavoxelData& data, boo } } -static int getOppositeIndex(int index) { - return index ^ MAXIMUM_FLAG_MASK; -} - void MetavoxelData::expand() { for (QHash::iterator it = _roots.begin(); it != _roots.end(); it++) { - MetavoxelNode* newParent = new MetavoxelNode(it.key()); - for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) { - MetavoxelNode* newChild = new MetavoxelNode(it.key()); - newParent->setChild(i, newChild); - int index = getOppositeIndex(i); - if (it.value()->isLeaf()) { - newChild->setChild(index, new MetavoxelNode(it.value()->getAttributeValue(it.key()))); - } else { - MetavoxelNode* grandchild = it.value()->getChild(i); - grandchild->incrementReferenceCount(); - newChild->setChild(index, grandchild); - } - for (int j = 1; j < MetavoxelNode::CHILD_COUNT; j++) { - MetavoxelNode* newGrandchild = new MetavoxelNode(it.key()); - newChild->setChild((index + j) % MetavoxelNode::CHILD_COUNT, newGrandchild); - } - newChild->mergeChildren(it.key()); - } - newParent->mergeChildren(it.key()); + MetavoxelNode* newNode = it.key()->expandMetavoxelRoot(*it.value()); it.value()->decrementReferenceCount(it.key()); - it.value() = newParent; + it.value() = newNode; } _size *= 2.0f; } @@ -823,6 +801,10 @@ void MetavoxelStreamState::setMinimum(const glm::vec3& lastMinimum, int index) { minimum = getNextMinimum(lastMinimum, size, index); } +int MetavoxelNode::getOppositeChildIndex(int index) { + return index ^ MAXIMUM_FLAG_MASK; +} + MetavoxelNode::MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren) : _referenceCount(1) { diff --git a/libraries/metavoxels/src/MetavoxelData.h b/libraries/metavoxels/src/MetavoxelData.h index 24eb09763c..9e5b2f04d1 100644 --- a/libraries/metavoxels/src/MetavoxelData.h +++ b/libraries/metavoxels/src/MetavoxelData.h @@ -197,6 +197,8 @@ public: static const int CHILD_COUNT = 8; + static int getOppositeChildIndex(int index); + MetavoxelNode(const AttributeValue& attributeValue, const MetavoxelNode* copyChildren = NULL); MetavoxelNode(const AttributePointer& attribute, const MetavoxelNode* copy); From 4696832ec6e072eb0d1b1e3eb79734e3322afd98 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 5 Aug 2014 15:13:50 -0700 Subject: [PATCH 4/4] Compute heightfield normals from adjacent values in vertex shader. --- .../resources/shaders/metavoxel_heightfield.vert | 12 ++++++++++-- interface/src/MetavoxelSystem.cpp | 5 +++++ interface/src/MetavoxelSystem.h | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/interface/resources/shaders/metavoxel_heightfield.vert b/interface/resources/shaders/metavoxel_heightfield.vert index 3cf43e87cd..cc4f68e9e0 100644 --- a/interface/resources/shaders/metavoxel_heightfield.vert +++ b/interface/resources/shaders/metavoxel_heightfield.vert @@ -14,18 +14,26 @@ // the height texture uniform sampler2D heightMap; +// the distance between height points in texture space +uniform float heightScale; + // the interpolated normal varying vec4 normal; void main(void) { // transform and store the normal for interpolation - normal = normalize(gl_ModelViewMatrix * vec4(0.0, 1.0, 0.0, 0.0)); + 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)); // pass along the texture coordinates gl_TexCoord[0] = gl_MultiTexCoord0; // add the height to the position - float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; + float height = texture2D(heightMap, heightCoord).r; gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); // the zero height should be invisible diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7aa6bc4080..f66d71070a 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -388,6 +388,9 @@ void HeightfieldBuffer::render() { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _colorTextureID); + DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( + DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); + glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); glBindTexture(GL_TEXTURE_2D, 0); @@ -470,6 +473,7 @@ void DefaultMetavoxelRendererImplementation::init() { _heightfieldProgram.bind(); _heightfieldProgram.setUniformValue("heightMap", 0); _heightfieldProgram.setUniformValue("diffuseMap", 1); + _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); _heightfieldProgram.release(); } } @@ -766,6 +770,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; int DefaultMetavoxelRendererImplementation::_pointScaleLocation; ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; +int DefaultMetavoxelRendererImplementation::_heightScaleLocation; 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 abcc929156..e7ee0d2c18 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -191,6 +191,7 @@ public: static void init(); static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } + static int getHeightScaleLocation() { return _heightScaleLocation; } Q_INVOKABLE DefaultMetavoxelRendererImplementation(); @@ -204,6 +205,7 @@ private: static int _pointScaleLocation; static ProgramObject _heightfieldProgram; + static int _heightScaleLocation; }; /// Base class for spanner renderers; provides clipping.