mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 11:28:03 +02:00
use QHash, not QVector, for Octree content query
This commit is contained in:
parent
e120697a9b
commit
faf31f268e
4 changed files with 53 additions and 68 deletions
|
@ -29,11 +29,12 @@ void VoxelShapeManager::stepForward(float deltaTime) {
|
||||||
if (simulation) {
|
if (simulation) {
|
||||||
glm::vec3 simulationOrigin = simulation->getTranslation();
|
glm::vec3 simulationOrigin = simulation->getTranslation();
|
||||||
if (glm::distance2(_lastSimulationTranslation, simulationOrigin) > EPSILON) {
|
if (glm::distance2(_lastSimulationTranslation, simulationOrigin) > EPSILON) {
|
||||||
int numVoxels = _voxels.size();
|
VoxelPool::const_iterator voxelItr = _voxels.constBegin();
|
||||||
for (int i = 0; i < numVoxels; ++i) {
|
while (voxelItr != _voxels.constEnd()) {
|
||||||
// the shape's position is stored in the simulation-frame
|
// the shape's position is stored in the simulation-frame
|
||||||
glm::vec3 cubeCenter = _voxels[i]._cube.calcCenter();
|
const VoxelInfo& voxel = voxelItr.value();
|
||||||
_voxels[i]._shape->setTranslation(cubeCenter - simulationOrigin);
|
voxel._shape->setTranslation(voxel._cube.calcCenter() - simulationOrigin);
|
||||||
|
++voxelItr;
|
||||||
}
|
}
|
||||||
_lastSimulationTranslation = simulationOrigin;
|
_lastSimulationTranslation = simulationOrigin;
|
||||||
}
|
}
|
||||||
|
@ -44,9 +45,10 @@ void VoxelShapeManager::buildShapes() {
|
||||||
// the shapes are owned by the elements of _voxels,
|
// the shapes are owned by the elements of _voxels,
|
||||||
// so _shapes is constructed by harvesting them from _voxels
|
// so _shapes is constructed by harvesting them from _voxels
|
||||||
_shapes.clear();
|
_shapes.clear();
|
||||||
int numVoxels = _voxels.size();
|
VoxelPool::const_iterator voxelItr = _voxels.constBegin();
|
||||||
for (int i = 0; i < numVoxels; ++i) {
|
while (voxelItr != _voxels.constEnd()) {
|
||||||
_shapes.push_back(_voxels[i]._shape);
|
_shapes.push_back(voxelItr.value()._shape);
|
||||||
|
++voxelItr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,72 +62,38 @@ void VoxelShapeManager::updateVoxels(CubeList& cubes) {
|
||||||
if (!simulation) {
|
if (!simulation) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// sort incoming cubes
|
|
||||||
qSort(cubes);
|
|
||||||
|
|
||||||
// Some of the cubes are new, others already exist, and some old voxels no longer exist.
|
int numChanges = 0;
|
||||||
// Since both lists are sorted we walk them simultaneously looking for matches.
|
VoxelPool::iterator voxelItr = _voxels.begin();
|
||||||
QVector<int> cubesToAdd;
|
while (voxelItr != _voxels.end()) {
|
||||||
QVector<int> voxelsToRemove;
|
// look for this voxel in cubes
|
||||||
int numCubes = cubes.size();
|
CubeList::iterator cubeItr = cubes.find(voxelItr.key());
|
||||||
int numVoxels = _voxels.size();
|
if (cubeItr == cubes.end()) {
|
||||||
int j = 0;
|
// did not find it --> remove the voxel
|
||||||
for (int i = 0; i < numCubes; ++i) {
|
simulation->removeShape(voxelItr.value()._shape);
|
||||||
while (j < numVoxels && _voxels[j]._cube < cubes[i]) {
|
voxelItr = _voxels.erase(voxelItr);
|
||||||
// remove non-matching voxels not found in cubes
|
++numChanges;
|
||||||
voxelsToRemove.push_back(j++);
|
|
||||||
}
|
|
||||||
if (j < numVoxels) {
|
|
||||||
if (glm::distance2(cubes[i].getCorner(), _voxels[j]._cube.getCorner()) < EPSILON) {
|
|
||||||
if (cubes[i].getScale() != _voxels[j]._cube.getScale()) {
|
|
||||||
// the voxel changed scale so we replace
|
|
||||||
voxelsToRemove.push_back(j++);
|
|
||||||
cubesToAdd.push_back(i);
|
|
||||||
} else {
|
|
||||||
// the voxel already exists
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// the voxel doesn't exist yet
|
|
||||||
cubesToAdd.push_back(i);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// all existing voxels have already been processed, so this one is new
|
// found it --> remove the cube
|
||||||
cubesToAdd.push_back(i);
|
cubes.erase(cubeItr);
|
||||||
|
voxelItr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (j < numVoxels) {
|
|
||||||
// remove non-matching voxels at the end
|
|
||||||
voxelsToRemove.push_back(j++);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove voxels identified as old, from back to front
|
// add remaining cubes to _voxels
|
||||||
for (int i = voxelsToRemove.size() - 1; i >= 0; --i) {
|
|
||||||
int k = voxelsToRemove[i];
|
|
||||||
simulation->removeShape(_voxels[k]._shape);
|
|
||||||
if (k < numVoxels - 1) {
|
|
||||||
// copy the last voxel into this spot
|
|
||||||
_voxels[k] = _voxels[numVoxels - 1];
|
|
||||||
}
|
|
||||||
_voxels.pop_back();
|
|
||||||
--numVoxels;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add new voxels
|
|
||||||
glm::vec3 simulationOrigin = simulation->getTranslation();
|
glm::vec3 simulationOrigin = simulation->getTranslation();
|
||||||
for (int i = 0; i < cubesToAdd.size(); ++i) {
|
CubeList::const_iterator cubeItr = cubes.constBegin();
|
||||||
const AACube& cube = cubes[cubesToAdd[i]];
|
while (cubeItr != cubes.constEnd()) {
|
||||||
// NOTE: shape's position is in simulation frame
|
AACube cube = cubeItr.value();
|
||||||
AACubeShape* shape = new AACubeShape(cube.getScale(), cube.calcCenter() - simulationOrigin);
|
AACubeShape* shape = new AACubeShape(cube.getScale(), cube.calcCenter() - simulationOrigin);
|
||||||
shape->setEntity(this);
|
shape->setEntity(this);
|
||||||
VoxelInfo voxel = { cube, shape };
|
VoxelInfo voxel = {cube, shape };
|
||||||
_voxels.push_back(voxel);
|
_voxels.insert(cubeItr.key(), voxel);
|
||||||
++numVoxels;
|
++numChanges;
|
||||||
|
++cubeItr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cubesToAdd.size() > 0 || voxelsToRemove.size() > 0) {
|
if (numChanges > 0) {
|
||||||
// keep _voxels sorted
|
|
||||||
qSort(_voxels);
|
|
||||||
buildShapes();
|
buildShapes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifndef hifi_VoxelShapeManager_h
|
#ifndef hifi_VoxelShapeManager_h
|
||||||
#define hifi_VoxelShapeManager_h
|
#define hifi_VoxelShapeManager_h
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
#include <AACube.h>
|
#include <AACube.h>
|
||||||
#include <PhysicsEntity.h>
|
#include <PhysicsEntity.h>
|
||||||
#include <Octree.h>
|
#include <Octree.h>
|
||||||
|
@ -22,11 +24,12 @@ class AACubeShape;
|
||||||
|
|
||||||
class VoxelInfo{
|
class VoxelInfo{
|
||||||
public:
|
public:
|
||||||
bool operator<(const VoxelInfo& otherVoxel) const { return _cube < otherVoxel._cube; }
|
|
||||||
AACube _cube;
|
AACube _cube;
|
||||||
AACubeShape* _shape;
|
AACubeShape* _shape;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef QHash<quint64, VoxelInfo> VoxelPool;
|
||||||
|
|
||||||
class VoxelShapeManager : public PhysicsEntity {
|
class VoxelShapeManager : public PhysicsEntity {
|
||||||
public:
|
public:
|
||||||
VoxelShapeManager();
|
VoxelShapeManager();
|
||||||
|
@ -42,7 +45,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
glm::vec3 _lastSimulationTranslation;
|
glm::vec3 _lastSimulationTranslation;
|
||||||
QVector<VoxelInfo> _voxels;
|
VoxelPool _voxels;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_VoxelShapeManager_h
|
#endif // hifi_VoxelShapeManager_h
|
||||||
|
|
|
@ -793,6 +793,19 @@ bool findShapeCollisionsOp(OctreeElement* element, void* extraData) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint64 cubeListHashKey(const glm::vec3& point) {
|
||||||
|
// NOTE: TREE_SCALE = 16384 (15 bits) and multiplier is 1024 (11 bits),
|
||||||
|
// so each component (26 bits) uses more than its alloted 21 bits.
|
||||||
|
// however we don't expect to span huge cubes so it is ok if we wrap
|
||||||
|
// (every 2^21 / 2^10 = 2048 meters).
|
||||||
|
const uint BITS_PER_COMPONENT = 21;
|
||||||
|
const quint64 MAX_SCALED_COMPONENT = 2097152; // 2^21
|
||||||
|
const float RESOLUTION_PER_METER = 1024.0f; // 2^10
|
||||||
|
return (quint64)(point.x * RESOLUTION_PER_METER) % MAX_SCALED_COMPONENT +
|
||||||
|
(((quint64)(point.y * RESOLUTION_PER_METER)) % MAX_SCALED_COMPONENT << BITS_PER_COMPONENT) +
|
||||||
|
(((quint64)(point.z * RESOLUTION_PER_METER)) % MAX_SCALED_COMPONENT << 2 * BITS_PER_COMPONENT);
|
||||||
|
}
|
||||||
|
|
||||||
bool findContentInCubeOp(OctreeElement* element, void* extraData) {
|
bool findContentInCubeOp(OctreeElement* element, void* extraData) {
|
||||||
ContentArgs* args = static_cast<ContentArgs*>(extraData);
|
ContentArgs* args = static_cast<ContentArgs*>(extraData);
|
||||||
|
|
||||||
|
@ -806,7 +819,8 @@ bool findContentInCubeOp(OctreeElement* element, void* extraData) {
|
||||||
return true; // recurse on children
|
return true; // recurse on children
|
||||||
}
|
}
|
||||||
if (element->hasContent()) {
|
if (element->hasContent()) {
|
||||||
args->cubes->push_back(cube);
|
// NOTE: the voxel's center is unique so we use it as the input for the key
|
||||||
|
args->cubes->insert(cubeListHashKey(cube.calcCenter()), cube);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -33,9 +33,9 @@ class Shape;
|
||||||
|
|
||||||
#include <CollisionInfo.h>
|
#include <CollisionInfo.h>
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
#include <QVector>
|
|
||||||
|
|
||||||
/// derive from this class to use the Octree::recurseTreeWithOperator() method
|
/// derive from this class to use the Octree::recurseTreeWithOperator() method
|
||||||
class RecurseOctreeOperator {
|
class RecurseOctreeOperator {
|
||||||
|
@ -48,7 +48,7 @@ public:
|
||||||
// Callback function, for recuseTreeWithOperation
|
// Callback function, for recuseTreeWithOperation
|
||||||
typedef bool (*RecurseOctreeOperation)(OctreeElement* element, void* extraData);
|
typedef bool (*RecurseOctreeOperation)(OctreeElement* element, void* extraData);
|
||||||
typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
|
typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
|
||||||
typedef QVector<AACube> CubeList;
|
typedef QHash<quint64, AACube> CubeList;
|
||||||
|
|
||||||
const bool NO_EXISTS_BITS = false;
|
const bool NO_EXISTS_BITS = false;
|
||||||
const bool WANT_EXISTS_BITS = true;
|
const bool WANT_EXISTS_BITS = true;
|
||||||
|
|
Loading…
Reference in a new issue