Simpler rendering.

This commit is contained in:
Andrzej Kapolka 2014-07-28 16:18:16 -07:00
parent 4f5448f529
commit e05884d4a3
4 changed files with 108 additions and 123 deletions

View file

@ -90,8 +90,8 @@ public:
SpannerRenderVisitor::SpannerRenderVisitor() :
SpannerVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannersAttribute(),
QVector<AttributePointer>() << AttributeRegistry::getInstance()->getSpannerMaskAttribute(),
QVector<AttributePointer>(), QVector<AttributePointer>(), Application::getInstance()->getMetavoxels()->getLOD(),
QVector<AttributePointer>(), QVector<AttributePointer>(), QVector<AttributePointer>(),
Application::getInstance()->getMetavoxels()->getLOD(),
encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())) {
}
@ -239,53 +239,22 @@ void MetavoxelSystemClient::sendDatagram(const QByteArray& data) {
Application::getInstance()->getBandwidthMeter()->outputStream(BandwidthMeter::METAVOXELS).updateValue(data.size());
}
PointBuffer::PointBuffer(const QVector<BufferPointVectorPair>& levelPoints) :
_levelPoints(levelPoints) {
PointBuffer::PointBuffer(const BufferPointVector& points) :
_points(points) {
}
void PointBuffer::render(int level) {
void PointBuffer::render() {
// initalize buffer, etc. on first render
if (!_buffer.isCreated()) {
_offsets.append(0);
_lastLeafCount = 0;
int totalPoints = 0;
foreach (const BufferPointVectorPair& pair, _levelPoints) {
_offsets.append(totalPoints += ((_lastLeafCount += pair.first.size()) + pair.second.size()));
}
_buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
_buffer.create();
_buffer.bind();
_buffer.allocate(totalPoints * sizeof(BufferPoint));
int offset = 0;
for (int i = 0; i < _levelPoints.size(); i++) {
// write the internal nodes from the current level
const BufferPointVector& internal = _levelPoints.at(i).second;
int length = internal.size() * sizeof(BufferPoint);
_buffer.write(offset, internal.constData(), length);
offset += length;
// and the leaves from the top down
for (int j = 0; j <= i; j++) {
const BufferPointVector& leaves = _levelPoints.at(j).first;
length = leaves.size() * sizeof(BufferPoint);
_buffer.write(offset, leaves.constData(), length);
offset += length;
}
}
_levelPoints.clear();
_pointCount = _points.size();
_buffer.allocate(_points.constData(), _pointCount * sizeof(BufferPoint));
_points.clear();
_buffer.release();
}
int first, count;
int nextLevel = level + 1;
if (nextLevel >= _offsets.size()) {
first = _offsets.last() - _lastLeafCount;
count = _lastLeafCount;
} else {
first = _offsets.at(level);
count = _offsets.at(nextLevel) - first;
}
if (count == 0) {
if (_pointCount == 0) {
return;
}
_buffer.bind();
@ -295,7 +264,7 @@ void PointBuffer::render(int level) {
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(BufferPoint), &point->color);
glNormalPointer(GL_BYTE, sizeof(BufferPoint), &point->normal);
glDrawArrays(GL_POINTS, first, count);
glDrawArrays(GL_POINTS, 0, _pointCount);
_buffer.release();
}
@ -304,23 +273,18 @@ PointBufferAttribute::PointBufferAttribute() :
InlineAttribute<PointBufferPointer>("pointBuffer") {
}
MetavoxelNode* PointBufferAttribute::createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const {
return new MetavoxelNode(value, original);
}
bool PointBufferAttribute::merge(void*& parent, void* children[], bool postRead) const {
for (int i = 0; i < MERGE_COUNT; i++) {
if (decodeInline<PointBufferPointer>(children[i])) {
PointBufferPointer firstChild = decodeInline<PointBufferPointer>(children[0]);
for (int i = 1; i < MERGE_COUNT; i++) {
if (firstChild != decodeInline<PointBufferPointer>(children[i])) {
*(PointBufferPointer*)&parent = _defaultValue;
return false;
}
}
*(PointBufferPointer*)&parent = firstChild;
return true;
}
AttributeValue PointBufferAttribute::inherit(const AttributeValue& parentValue) const {
return AttributeValue(parentValue.getAttribute());
}
void PointMetavoxelRendererImplementation::init() {
if (!_program.isLinked()) {
_program.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert");
@ -340,12 +304,14 @@ public:
PointAugmentVisitor(const MetavoxelLOD& lod);
virtual void prepare(MetavoxelData* data);
virtual int visit(MetavoxelInfo& info);
virtual bool postVisit(MetavoxelInfo& info);
private:
QVector<BufferPointVectorPair> _depthPoints;
BufferPointVector _points;
float _pointLeafSize;
};
PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) :
@ -356,48 +322,61 @@ PointAugmentVisitor::PointAugmentVisitor(const MetavoxelLOD& lod) :
const int ALPHA_RENDER_THRESHOLD = 0;
void PointAugmentVisitor::prepare(MetavoxelData* data) {
MetavoxelVisitor::prepare(data);
const float MAX_POINT_LEAF_SIZE = 64.0f;
_pointLeafSize = qMin(data->getSize(), MAX_POINT_LEAF_SIZE);
}
int PointAugmentVisitor::visit(MetavoxelInfo& info) {
if (_depth >= _depthPoints.size()) {
_depthPoints.resize(_depth + 1);
if (!info.isLeaf) {
return (info.size > _pointLeafSize) ? DEFAULT_ORDER : (DEFAULT_ORDER | ALL_NODES_REST);
}
QRgb color = info.inputValues.at(0).getInlineValue<QRgb>();
quint8 alpha = qAlpha(color);
if (alpha <= ALPHA_RENDER_THRESHOLD) {
return info.isLeaf ? STOP_RECURSION : (DEFAULT_ORDER | ALL_NODES);
if (alpha > ALPHA_RENDER_THRESHOLD) {
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) },
{ quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } };
_points.append(point);
}
QRgb normal = info.inputValues.at(1).getInlineValue<QRgb>();
BufferPoint point = { glm::vec4(info.minimum + glm::vec3(info.size, info.size, info.size) * 0.5f, info.size),
{ quint8(qRed(color)), quint8(qGreen(color)), quint8(qBlue(color)) },
{ quint8(qRed(normal)), quint8(qGreen(normal)), quint8(qBlue(normal)) } };
if (info.isLeaf) {
_depthPoints[_depth].first.append(point);
return STOP_RECURSION;
if (info.size >= _pointLeafSize) {
BufferPointVector swapPoints;
_points.swap(swapPoints);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer(
new PointBuffer(swapPoints))));
}
_depthPoints[_depth].second.append(point);
return DEFAULT_ORDER | ALL_NODES;
return STOP_RECURSION;
}
bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) {
if (_depth != 0) {
if (info.size != _pointLeafSize) {
return false;
}
int lastDepth = _depthPoints.size();
QVector<BufferPointVectorPair> levelPoints(lastDepth - _depth);
for (int i = 0; i < levelPoints.size(); i++) {
BufferPointVectorPair& levelPair = levelPoints[i];
BufferPointVectorPair& depthPair = _depthPoints[_depth + i];
levelPair.first.swap(depthPair.first);
levelPair.second.swap(depthPair.second);
}
BufferPointVector swapPoints;
_points.swap(swapPoints);
info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(PointBufferPointer(
new PointBuffer(levelPoints))));
new PointBuffer(swapPoints))));
return true;
}
void PointMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous,
MetavoxelInfo& info, const MetavoxelLOD& lod) {
// copy the previous buffers
MetavoxelData expandedPrevious = previous;
while (expandedPrevious.getSize() < data.getSize()) {
expandedPrevious.expand();
}
const AttributePointer& pointBufferAttribute = Application::getInstance()->getMetavoxels()->getPointBufferAttribute();
MetavoxelNode* root = expandedPrevious.getRoot(pointBufferAttribute);
if (root) {
data.setRoot(pointBufferAttribute, root);
root->incrementReferenceCount();
}
PointAugmentVisitor visitor(lod);
data.guideToDifferent(previous, visitor, &info);
data.guideToDifferent(expandedPrevious, visitor);
}
class PointRenderVisitor : public MetavoxelVisitor {
@ -421,7 +400,7 @@ PointRenderVisitor::PointRenderVisitor(const MetavoxelLOD& lod) :
int PointRenderVisitor::visit(MetavoxelInfo& info) {
PointBufferPointer buffer = info.inputValues.at(0).getInlineValue<PointBufferPointer>();
if (buffer) {
buffer->render(1000);
buffer->render();
}
return info.isLeaf ? STOP_RECURSION : _order;
}
@ -450,7 +429,7 @@ void PointMetavoxelRendererImplementation::render(MetavoxelData& data, Metavoxel
glDisable(GL_BLEND);
PointRenderVisitor visitor(lod);
data.guide(visitor, &info);
data.guide(visitor);
glEnable(GL_BLEND);

View file

@ -23,12 +23,8 @@
#include "renderer/ProgramObject.h"
class BufferPoint;
class Model;
typedef QVector<BufferPoint> BufferPointVector;
typedef QPair<BufferPointVector, BufferPointVector> BufferPointVectorPair;
/// Renders a metavoxel tree.
class MetavoxelSystem : public MetavoxelClientManager {
Q_OBJECT
@ -66,6 +62,8 @@ public:
quint8 normal[3];
};
typedef QVector<BufferPoint> BufferPointVector;
Q_DECLARE_METATYPE(BufferPointVector)
/// A client session associated with a single server.
@ -94,20 +92,19 @@ private:
QReadWriteLock _augmentedDataLock;
};
/// Contains the information necessary to render a group of points at variable detail levels.
/// Contains the information necessary to render a group of points.
class PointBuffer : public QSharedData {
public:
PointBuffer(const QVector<BufferPointVectorPair>& levelPoints);
PointBuffer(const BufferPointVector& points);
void render(int level);
void render();
private:
QVector<BufferPointVectorPair> _levelPoints;
BufferPointVector _points;
QOpenGLBuffer _buffer;
QVector<int> _offsets;
int _lastLeafCount;
int _pointCount;
};
typedef QExplicitlySharedDataPointer<PointBuffer> PointBufferPointer;
@ -120,9 +117,7 @@ public:
Q_INVOKABLE PointBufferAttribute();
virtual MetavoxelNode* createMetavoxelNode(const AttributeValue& value, const MetavoxelNode* original) const;
virtual bool merge(void*& parent, void* children[], bool postRead = false) const;
virtual AttributeValue inherit(const AttributeValue& parentValue) const;
};
/// Renders metavoxels as points.

View file

@ -81,7 +81,7 @@ Box MetavoxelData::getBounds() const {
return Box(glm::vec3(-halfSize, -halfSize, -halfSize), glm::vec3(halfSize, halfSize, halfSize));
}
void MetavoxelData::guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start) {
void MetavoxelData::guide(MetavoxelVisitor& visitor) {
// let the visitor know we're about to begin a tour
visitor.prepare(this);
@ -128,7 +128,7 @@ void MetavoxelData::guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start)
visitor.releaseVisitation();
}
void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start) {
void MetavoxelData::guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor) {
// if the other data is smaller, we need to expand it to compare
const MetavoxelData* expandedOther = &other;
if (_size > other._size) {
@ -1249,6 +1249,7 @@ const int MetavoxelVisitor::DEFAULT_ORDER = encodeOrder(0, 1, 2, 3, 4, 5, 6, 7);
const int MetavoxelVisitor::STOP_RECURSION = 0;
const int MetavoxelVisitor::SHORT_CIRCUIT = -1;
const int MetavoxelVisitor::ALL_NODES = 1 << 24;
const int MetavoxelVisitor::ALL_NODES_REST = 1 << 25;
MetavoxelVisitor::MetavoxelVisitor(const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs, const MetavoxelLOD& lod) :
@ -1428,32 +1429,7 @@ bool MetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) {
DefaultMetavoxelGuide::DefaultMetavoxelGuide() {
}
bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
// save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute
float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) *
visitation.visitor->getLOD().threshold;
visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier());
visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves();
int encodedOrder = visitation.visitor->visit(visitation.info);
if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) {
return false;
}
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& value = visitation.info.outputValues[i];
if (!value.getAttribute()) {
continue;
}
MetavoxelNode*& node = visitation.outputNodes[i];
if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) {
// "set" to same value; disregard
value = AttributeValue();
} else {
node = value.getAttribute()->createMetavoxelNode(value, node);
}
}
if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
return true;
}
static inline bool defaultGuideToChildren(MetavoxelVisitation& visitation, float lodBase, int encodedOrder) {
MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation();
nextVisitation.info.size = visitation.info.size * 0.5f;
for (int i = 0; i < MetavoxelNode::CHILD_COUNT; i++) {
@ -1546,6 +1522,35 @@ bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
return true;
}
bool DefaultMetavoxelGuide::guide(MetavoxelVisitation& visitation) {
// save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute
float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) *
visitation.visitor->getLOD().threshold;
visitation.info.isLODLeaf = (visitation.info.size < lodBase * visitation.visitor->getMinimumLODThresholdMultiplier());
visitation.info.isLeaf = visitation.info.isLODLeaf || visitation.allInputNodesLeaves();
int encodedOrder = visitation.visitor->visit(visitation.info);
if (encodedOrder == MetavoxelVisitor::SHORT_CIRCUIT) {
return false;
}
for (int i = 0; i < visitation.outputNodes.size(); i++) {
OwnedAttributeValue& value = visitation.info.outputValues[i];
if (!value.getAttribute()) {
continue;
}
MetavoxelNode*& node = visitation.outputNodes[i];
if (node && node->isLeaf() && value.getAttribute()->equal(value.getValue(), node->getAttributeValue())) {
// "set" to same value; disregard
value = AttributeValue();
} else {
node = value.getAttribute()->createMetavoxelNode(value, node);
}
}
if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
return true;
}
return (encodedOrder == MetavoxelVisitor::STOP_RECURSION || defaultGuideToChildren(visitation, lodBase, encodedOrder));
}
bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) {
// save the core of the LOD calculation; we'll reuse it to determine whether to subdivide each attribute
float lodBase = glm::distance(visitation.visitor->getLOD().position, visitation.info.getCenter()) *
@ -1572,6 +1577,9 @@ bool DefaultMetavoxelGuide::guideToDifferent(MetavoxelVisitation& visitation) {
if (encodedOrder == MetavoxelVisitor::STOP_RECURSION) {
return true;
}
if (encodedOrder & MetavoxelVisitor::ALL_NODES_REST) {
return defaultGuideToChildren(visitation, lodBase, encodedOrder);
}
bool onlyVisitDifferent = !(encodedOrder & MetavoxelVisitor::ALL_NODES);
MetavoxelVisitation& nextVisitation = visitation.visitor->acquireVisitation();
nextVisitation.compareNodes.resize(visitation.compareNodes.size());

View file

@ -81,12 +81,10 @@ public:
Box getBounds() const;
/// Applies the specified visitor to the contained voxels.
/// \param start the location at which to start, or NULL for the root
void guide(MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL);
void guide(MetavoxelVisitor& visitor);
/// Guides the specified visitor to the voxels that differ from those of the specified other.
/// \param start the location at which to start, or NULL for the root
void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor, const MetavoxelInfo* start = NULL);
void guideToDifferent(const MetavoxelData& other, MetavoxelVisitor& visitor);
/// Inserts a spanner into the specified attribute layer.
void insert(const AttributePointer& attribute, const SharedObjectPointer& object);
@ -296,9 +294,14 @@ public:
/// A special "order" that short-circuits the tour.
static const int SHORT_CIRCUIT;
/// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones).
/// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for
/// just this level.
static const int ALL_NODES;
/// A flag combined with an order that instructs us to return to visiting all nodes (rather than the different ones) for
/// this level and all beneath it.
static const int ALL_NODES_REST;
MetavoxelVisitor(const QVector<AttributePointer>& inputs,
const QVector<AttributePointer>& outputs = QVector<AttributePointer>(),
const MetavoxelLOD& lod = MetavoxelLOD());