From 96a40bd673f41f0dfc114e1cc29e5aa714a70050 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 29 May 2015 18:50:26 -0700 Subject: [PATCH] basic collisions with cubic polyvoxes --- examples/voxels.js | 4 +- .../src/RenderablePolyVoxEntityItem.cpp | 159 ++++++++++++++++-- .../src/RenderablePolyVoxEntityItem.h | 13 +- .../entities/src/EntityScriptingInterface.cpp | 37 ++++ .../entities/src/EntityScriptingInterface.h | 1 + libraries/entities/src/PolyVoxEntityItem.cpp | 5 + libraries/entities/src/PolyVoxEntityItem.h | 4 +- libraries/shared/src/ShapeInfo.h | 3 +- 8 files changed, 201 insertions(+), 25 deletions(-) diff --git a/examples/voxels.js b/examples/voxels.js index e274f1c4cc..351e723a5b 100644 --- a/examples/voxels.js +++ b/examples/voxels.js @@ -15,9 +15,9 @@ function mousePressEvent(event) { for (var i = 0; i < ids.length; i++) { var id = ids[i]; if (controlHeld) { - Entities.setVoxelSphere(id, intersection.intersection, 1.2, 0); + Entities.setVoxelSphere(id, intersection.intersection, 0.5, 0); } else { - Entities.setVoxelSphere(id, intersection.intersection, 1.2, 255); + Entities.setVoxelSphere(id, intersection.intersection, 0.5, 255); } } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 977a6511c8..9e6d512dc3 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -38,12 +38,22 @@ EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entit return EntityItemPointer(new RenderablePolyVoxEntityItem(entityID, properties)); } +RenderablePolyVoxEntityItem::RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, + const EntityItemProperties& properties) : + PolyVoxEntityItem(entityItemID, properties) { + setVoxelVolumeSize(_voxelVolumeSize); + + model::Mesh* mesh = new model::Mesh(); + model::MeshPointer meshPtr(mesh); + _modelGeometry.setMesh(meshPtr); +} + + RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() { delete _volData; } void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { - if (_volData && voxelVolumeSize == _voxelVolumeSize) { return; } @@ -83,12 +93,32 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { return translation * rotation * centerToCorner; } + +glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { + glm::vec3 scale = _dimensions / _voxelVolumeSize; // meters / voxel-units + glm::mat4 scaled = glm::scale(glm::mat4(), scale); + glm::mat4 centerToCorner = glm::translate(scaled, _voxelVolumeSize / -2.0f); + return centerToCorner; +} + glm::mat4 RenderablePolyVoxEntityItem::worldToVoxelMatrix() const { glm::mat4 worldToModelMatrix = glm::inverse(voxelToWorldMatrix()); return worldToModelMatrix; } +void RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { + // XXX a volume that is all "on" has no mesh. make a different call for this nearly-all code: + for (int z = 1; z < _volData->getDepth() - 1; z++) { + for (int y = 1; y < _volData->getHeight() - 1; y++) { + for (int x = 1; x < _volData->getWidth() - 1; x++) { + _volData->setVoxelAt(x, y, z, toValue); + } + } + } + compressVolumeData(); +} + void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue) { // This three-level for loop iterates over every voxel in the volume for (int z = 0; z < _volData->getDepth(); z++) { @@ -106,7 +136,6 @@ void RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi } } compressVolumeData(); - _needsModelReload = true; } void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) { @@ -119,11 +148,6 @@ void RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r } void RenderablePolyVoxEntityItem::getModel() { - if (!_volData) { - // this will cause the allocation of _volData - setVoxelVolumeSize(_voxelVolumeSize); - } - // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; @@ -143,24 +167,25 @@ void RenderablePolyVoxEntityItem::getModel() { } // convert PolyVox mesh to a Sam mesh - model::Mesh* mesh = new model::Mesh(); - model::MeshPointer meshPtr(mesh); + auto mesh = _modelGeometry.getMesh(); const std::vector& vecIndices = polyVoxMesh.getIndices(); auto indexBuffer = new gpu::Buffer(vecIndices.size() * sizeof(uint32_t), (gpu::Byte*)vecIndices.data()); auto indexBufferPtr = gpu::BufferPointer(indexBuffer); - mesh->setIndexBuffer(gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW))); + auto indexBufferView = new gpu::BufferView(indexBufferPtr, gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::RAW)); + mesh->setIndexBuffer(*indexBufferView); const std::vector& vecVertices = polyVoxMesh.getVertices(); auto vertexBuffer = new gpu::Buffer(vecVertices.size() * sizeof(PolyVox::PositionMaterialNormal), (gpu::Byte*)vecVertices.data()); auto vertexBufferPtr = gpu::BufferPointer(vertexBuffer); - mesh->setVertexBuffer(gpu::BufferView(vertexBufferPtr, - 0, - vertexBufferPtr->getSize() - sizeof(float) * 3, - sizeof(PolyVox::PositionMaterialNormal), - gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW))); + auto vertexBufferView = new gpu::BufferView(vertexBufferPtr, + 0, + vertexBufferPtr->getSize() - sizeof(float) * 3, + sizeof(PolyVox::PositionMaterialNormal), + gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RAW)); + mesh->setVertexBuffer(*vertexBufferView); mesh->addAttribute(gpu::Stream::NORMAL, gpu::BufferView(vertexBufferPtr, sizeof(float) * 3, @@ -176,7 +201,6 @@ void RenderablePolyVoxEntityItem::getModel() { qDebug() << "---- vecIndices.size() =" << vecIndices.size(); qDebug() << "---- vecVertices.size() =" << vecVertices.size(); - _modelGeometry.setMesh(meshPtr); _needsModelReload = false; } @@ -310,6 +334,9 @@ void RenderablePolyVoxEntityItem::compressVolumeData() { // revert decompressVolumeData(); } + + _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; + _needsModelReload = true; } @@ -329,8 +356,104 @@ void RenderablePolyVoxEntityItem::decompressVolumeData() { } } - _needsModelReload = true; - qDebug() << "--------------- voxel decompress ---------------"; qDebug() << "raw-size =" << rawSize << " compressed-size =" << _voxelData.size(); + + _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; + _needsModelReload = true; + getModel(); +} + +bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { + qDebug() << "RenderablePolyVoxEntityItem::isReadyToComputeShape" << (!_needsModelReload); + + if (_needsModelReload) { + return false; + } + + for (int z = 0; z < _volData->getDepth(); z++) { + for (int y = 0; y < _volData->getHeight(); y++) { + for (int x = 0; x < _volData->getWidth(); x++) { + if (_volData->getVoxelAt(x, y, z) > 0) { + return true; + } + } + } + } + + return false; +} + +void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { + qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo"; + ShapeType type = getShapeType(); + if (type != SHAPE_TYPE_COMPOUND) { + qDebug() << "RenderablePolyVoxEntityItem::computeShapeInfo NOT COMPOUND"; + PolyVoxEntityItem::computeShapeInfo(info); + info.setParams(type, 0.5f * getDimensions()); + } else { + _points.clear(); + unsigned int i = 0; + + glm::mat4 wToM = voxelToLocalMatrix(); + + AABox box; + + for (int z = 0; z < _volData->getDepth(); z++) { + for (int y = 0; y < _volData->getHeight(); y++) { + for (int x = 0; x < _volData->getWidth(); x++) { + if (_volData->getVoxelAt(x, y, z) > 0) { + QVector pointsInPart; + + float offL = -0.5f; + float offH = 0.5f; + + // XXX I don't really understand why this make it line up. + // float offL = -1.0f; + // float offH = 0.0f; + + + glm::vec3 p000 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offL, 1.0f)); + glm::vec3 p001 = glm::vec3(wToM * glm::vec4(x + offL, y + offL, z + offH, 1.0f)); + glm::vec3 p010 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offL, 1.0f)); + glm::vec3 p011 = glm::vec3(wToM * glm::vec4(x + offL, y + offH, z + offH, 1.0f)); + glm::vec3 p100 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offL, 1.0f)); + glm::vec3 p101 = glm::vec3(wToM * glm::vec4(x + offH, y + offL, z + offH, 1.0f)); + glm::vec3 p110 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offL, 1.0f)); + glm::vec3 p111 = glm::vec3(wToM * glm::vec4(x + offH, y + offH, z + offH, 1.0f)); + + box += p000; + box += p001; + box += p010; + box += p011; + box += p100; + box += p101; + box += p110; + box += p111; + + pointsInPart << p000; + pointsInPart << p001; + pointsInPart << p010; + pointsInPart << p011; + pointsInPart << p100; + pointsInPart << p101; + pointsInPart << p110; + pointsInPart << p111; + + // add next convex hull + QVector newMeshPoints; + _points << newMeshPoints; + // add points to the new convex hull + _points[i++] << pointsInPart; + } + } + } + } + + + glm::vec3 collisionModelDimensions = box.getDimensions(); + QByteArray b64 = _voxelData.toBase64(); + info.setParams(type, collisionModelDimensions, QString(b64)); + info.setConvexHulls(_points); + } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index b04b32996b..9623fab4f9 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -21,8 +21,7 @@ class RenderablePolyVoxEntityItem : public PolyVoxEntityItem { public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); - RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - PolyVoxEntityItem(entityItemID, properties) { } + RenderablePolyVoxEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); virtual ~RenderablePolyVoxEntityItem(); @@ -47,14 +46,22 @@ public: virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize); glm::mat4 voxelToWorldMatrix() const; + glm::mat4 voxelToLocalMatrix() const; glm::mat4 worldToVoxelMatrix() const; + + virtual bool isReadyToComputeShape(); + virtual void computeShapeInfo(ShapeInfo& info); + + // coords are in voxel-volume space virtual void setSphereInVolume(glm::vec3 center, float radius, uint8_t toValue); // coords are in world-space virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue); + virtual void setAll(uint8_t toValue); + private: void compressVolumeData(); void decompressVolumeData(); @@ -62,6 +69,8 @@ private: PolyVox::SimpleVolume* _volData = nullptr; model::Geometry _modelGeometry; bool _needsModelReload = true; + + QVector> _points; // XXX }; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 579ec2a984..fe77e0799c 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -420,3 +420,40 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c queueEntityMessage(PacketTypeEntityEdit, entityID, properties); return true; } + + +bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { + if (!_entityTree) { + return false; + } + + EntityItemPointer entity = static_cast(_entityTree->findEntityByEntityItemID(entityID)); + if (!entity) { + qCDebug(entities) << "EntityScriptingInterface::setVoxelSphere no entity with ID" << entityID; + return false; + } + + EntityTypes::EntityType entityType = entity->getType(); + if (entityType != EntityTypes::PolyVox) { + return false; + } + + auto now = usecTimestampNow(); + + PolyVoxEntityItem* polyVoxEntity = static_cast(entity.get()); + _entityTree->lockForWrite(); + polyVoxEntity->setAll(value); + entity->setLastEdited(now); + entity->setLastBroadcast(now); + _entityTree->unlock(); + + _entityTree->lockForRead(); + EntityItemProperties properties = entity->getProperties(); + _entityTree->unlock(); + + properties.setVoxelDataDirty(); + properties.setLastEdited(now); + + queueEntityMessage(PacketTypeEntityEdit, entityID, properties); + return true; +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 6c2dc06579..421875feef 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -118,6 +118,7 @@ public slots: Q_INVOKABLE bool getSendPhysicsUpdates() const; Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); + Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE void dumpTree() const; diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index a46fdb2682..fd552f2a20 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -115,3 +115,8 @@ void PolyVoxEntityItem::debugDump() const { qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } + +// virtual +ShapeType PolyVoxEntityItem::getShapeType() const { + return SHAPE_TYPE_COMPOUND; +} diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 53675e6efa..472e72ead0 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -51,7 +51,7 @@ class PolyVoxEntityItem : public EntityItem { _color[BLUE_INDEX] = value.blue; } - virtual ShapeType getShapeType() const { return SHAPE_TYPE_POLYVOX; } + virtual ShapeType getShapeType() const; // never have a ray intersection pick a PolyVoxEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } @@ -88,6 +88,8 @@ class PolyVoxEntityItem : public EntityItem { // coords are in world-space virtual void setSphere(glm::vec3 center, float radius, uint8_t toValue) {} + virtual void setAll(uint8_t toValue) {} + protected: rgbColor _color; glm::vec3 _voxelVolumeSize; // this is always 3 bytes diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index e2a77fbba2..a3fbe55f36 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -35,8 +35,7 @@ enum ShapeType { SHAPE_TYPE_CYLINDER_X, SHAPE_TYPE_CYLINDER_Y, SHAPE_TYPE_CYLINDER_Z, - SHAPE_TYPE_LINE, - SHAPE_TYPE_POLYVOX + SHAPE_TYPE_LINE }; class ShapeInfo {