From 0c84ddc50364aa42a24ca3f599be24ba81151dcf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 11:33:10 -0800 Subject: [PATCH 01/10] fix indentation --- .../entities/src/EntityScriptingInterface.cpp | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index cd7f1235bb..fa1b53e324 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -285,7 +285,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit desiredProperties = entity->getEntityProperties(params); desiredProperties.setHasProperty(PROP_LOCAL_POSITION); desiredProperties.setHasProperty(PROP_LOCAL_ROTATION); - } + } results = entity->getProperties(desiredProperties); @@ -825,7 +825,7 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::setVoxelSphere no entity with ID" << entityID; + qCDebug(entities) << "EntityScriptingInterface::setVoxels no entity with ID" << entityID; return false; } @@ -887,24 +887,24 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setSphere(center, radius, value); - }); + return polyVoxEntity.setSphere(center, radius, value); + }); } bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) { PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setVoxelInVolume(position, value); - }); + return polyVoxEntity.setVoxelInVolume(position, value); + }); } bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setAll(value); - }); + return polyVoxEntity.setAll(value); + }); } bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, @@ -912,8 +912,8 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3 PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value); - }); + return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value); + }); } bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector& points) { @@ -1020,25 +1020,25 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, auto actionFactory = DependencyManager::get(); bool success = false; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - // create this action even if the entity doesn't have physics info. it will often be the - // case that a script adds an action immediately after an object is created, and the physicsInfo - // is computed asynchronously. - // if (!entity->getPhysicsInfo()) { - // return false; - // } - EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString); - if (actionType == ACTION_TYPE_NONE) { - return false; - } - EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments); - if (!action) { - return false; - } - action->setIsMine(true); - success = entity->addAction(simulation, action); - entity->grabSimulationOwnership(); - return false; // Physics will cause a packet to be sent, so don't send from here. - }); + // create this action even if the entity doesn't have physics info. it will often be the + // case that a script adds an action immediately after an object is created, and the physicsInfo + // is computed asynchronously. + // if (!entity->getPhysicsInfo()) { + // return false; + // } + EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString); + if (actionType == ACTION_TYPE_NONE) { + return false; + } + EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments); + if (!action) { + return false; + } + action->setIsMine(true); + success = entity->addAction(simulation, action); + entity->grabSimulationOwnership(); + return false; // Physics will cause a packet to be sent, so don't send from here. + }); if (success) { return actionID; } @@ -1050,12 +1050,12 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& PROFILE_RANGE(script_entities, __FUNCTION__); return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - bool success = entity->updateAction(simulation, actionID, arguments); - if (success) { - entity->grabSimulationOwnership(); - } - return success; - }); + bool success = entity->updateAction(simulation, actionID, arguments); + if (success) { + entity->grabSimulationOwnership(); + } + return success; + }); } bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& actionID) { @@ -1063,13 +1063,13 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& bool success = false; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - success = entity->removeAction(simulation, actionID); - if (success) { - // reduce from grab to poke - entity->pokeSimulationOwnership(); - } - return false; // Physics will cause a packet to be sent, so don't send from here. - }); + success = entity->removeAction(simulation, actionID); + if (success) { + // reduce from grab to poke + entity->pokeSimulationOwnership(); + } + return false; // Physics will cause a packet to be sent, so don't send from here. + }); return success; } @@ -1078,10 +1078,10 @@ QVector EntityScriptingInterface::getActionIDs(const QUuid& entityID) { QVector result; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - QList actionIDs = entity->getActionIDs(); - result = QVector::fromList(actionIDs); - return false; // don't send an edit packet - }); + QList actionIDs = entity->getActionIDs(); + result = QVector::fromList(actionIDs); + return false; // don't send an edit packet + }); return result; } @@ -1090,9 +1090,9 @@ QVariantMap EntityScriptingInterface::getActionArguments(const QUuid& entityID, QVariantMap result; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - result = entity->getActionArguments(actionID); - return false; // don't send an edit packet - }); + result = entity->getActionArguments(actionID); + return false; // don't send an edit packet + }); return result; } From 76c873ce81ef1865b49e44257c43eb3d54149c4c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 11:34:48 -0800 Subject: [PATCH 02/10] don't compute polyvox shapes if they are collisionless --- .../src/RenderablePolyVoxEntityItem.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 7646f0a454..5fe2844176 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -501,6 +501,9 @@ PolyVox::RaycastResult RenderablePolyVoxEntityItem::doRayCast(glm::vec4 originIn // virtual ShapeType RenderablePolyVoxEntityItem::getShapeType() const { + if (_collisionless) { + return SHAPE_TYPE_NONE; + } return SHAPE_TYPE_COMPOUND; } @@ -512,6 +515,11 @@ void RenderablePolyVoxEntityItem::updateRegistrationPoint(const glm::vec3& value } bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { + ShapeType shapeType = getShapeType(); + if (shapeType == SHAPE_TYPE_NONE) { + return true; + } + // we determine if we are ready to compute the physics shape by actually doing so. // if _voxelDataDirty or _volDataDirty is set, don't do this yet -- wait for their // threads to finish before creating the collision shape. @@ -524,6 +532,12 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { } void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { + ShapeType shapeType = getShapeType(); + if (shapeType == SHAPE_TYPE_NONE) { + info.setParams(getShapeType(), 0.5f * getDimensions()); + return; + } + // the shape was actually computed in isReadyToComputeShape. Just hand it off, here. withWriteLock([&] { info = _shapeInfo; @@ -736,7 +750,7 @@ glm::vec3 RenderablePolyVoxEntityItem::localCoordsToVoxelCoords(glm::vec3& local void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { // This controls how many individual voxels are in the entity. This is unrelated to - // the dimentions of the entity -- it defines the size of the arrays that hold voxel values. + // the dimentions of the entity -- it defines the sizes of the arrays that hold voxel values. // In addition to setting the number of voxels, this is used in a few places for its // side-effect of allocating _volData to be the correct size. withWriteLock([&] { From 0e4b0332dd7f6a6833f92a1bb0ec93bfde211d18 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 11:35:27 -0800 Subject: [PATCH 03/10] avoid a rare crash --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4f4f3bf67f..55a7221f5d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -944,7 +944,10 @@ void EntityTreeRenderer::entityScriptChanging(const EntityItemID& entityID, cons void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const bool reload, const bool unloadFirst) { if (_tree && !_shuttingDown) { EntityItemPointer entity = getTree()->findEntityByEntityItemID(entityID); - bool shouldLoad = entity && entity->shouldPreloadScript() && _entitiesScriptEngine; + if (!entity) { + return; + } + bool shouldLoad = entity->shouldPreloadScript() && _entitiesScriptEngine; QString scriptUrl = entity->getScript(); if ((unloadFirst && shouldLoad) || scriptUrl.isEmpty()) { _entitiesScriptEngine->unloadEntityScript(entityID); From 1e81edbaea7199e3d1cc6ac22167152f3fd4ba45 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 15:32:08 -0800 Subject: [PATCH 04/10] make a copy of volData before computing the visual mesh --- .../src/RenderablePolyVoxEntityItem.cpp | 67 +++++++++++-------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5fe2844176..340f8f7d4b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef _WIN32 #pragma warning(pop) #endif @@ -1128,36 +1129,48 @@ void RenderablePolyVoxEntityItem::getMesh() { // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; + PolyVox::SimpleVolume* volData = nullptr; + entity->withReadLock([&] { - PolyVox::SimpleVolume* volData = entity->getVolData(); - switch (voxelSurfaceStyle) { - case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - } + PolyVox::SimpleVolume* entityVolData = entity->getVolData(); + PolyVox::Region region = entityVolData->getEnclosingRegion(); + volData = new PolyVox::SimpleVolume(region); + volData->setBorderValue(255); + PolyVox::VolumeResampler, + PolyVox::SimpleVolume> copier = + PolyVox::VolumeResampler, + PolyVox::SimpleVolume>(entityVolData, region, volData, region); + copier.execute(); }); + switch (voxelSurfaceStyle) { + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + } + delete volData; + // convert PolyVox mesh to a Sam mesh const std::vector& vecIndices = polyVoxMesh.getIndices(); auto indexBuffer = std::make_shared(vecIndices.size() * sizeof(uint32_t), From 7a31a99e3c488c62665679d1adff26e3928594e7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 21:13:20 -0800 Subject: [PATCH 05/10] back out previous experiment --- .../src/RenderablePolyVoxEntityItem.cpp | 67 ++++++++----------- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 2 +- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 340f8f7d4b..5fe2844176 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #ifdef _WIN32 #pragma warning(pop) #endif @@ -1129,48 +1128,36 @@ void RenderablePolyVoxEntityItem::getMesh() { // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; - PolyVox::SimpleVolume* volData = nullptr; - entity->withReadLock([&] { - PolyVox::SimpleVolume* entityVolData = entity->getVolData(); - PolyVox::Region region = entityVolData->getEnclosingRegion(); - volData = new PolyVox::SimpleVolume(region); - volData->setBorderValue(255); - PolyVox::VolumeResampler, - PolyVox::SimpleVolume> copier = - PolyVox::VolumeResampler, - PolyVox::SimpleVolume>(entityVolData, region, volData, region); - copier.execute(); + PolyVox::SimpleVolume* volData = entity->getVolData(); + switch (voxelSurfaceStyle) { + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + } }); - switch (voxelSurfaceStyle) { - case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - } - delete volData; - // convert PolyVox mesh to a Sam mesh const std::vector& vecIndices = polyVoxMesh.getIndices(); auto indexBuffer = std::make_shared(vecIndices.size() * sizeof(uint32_t), diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 42f3ece9cd..6d503a208a 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -545,7 +545,7 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { // HACK: when interface is launched and steam vr is NOT running, openvr will return bad HMD poses for a few frames // To workaround this, filter out any hmd poses that are obviously bad, i.e. beneath the floor. if (isBadPose(&nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking)) { - qDebug() << "WARNING: ignoring bad hmd pose from openvr"; + // qDebug() << "WARNING: ignoring bad hmd pose from openvr"; // use the last known good HMD pose nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking = _lastGoodHMDPose; From 422b0bb952df78b51a59166e66ef3ef2f52d4a8e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 21:14:13 -0800 Subject: [PATCH 06/10] don't set _dirtyFlags if polyvox is collisionless --- .../entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5fe2844176..47ef598502 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1188,7 +1188,9 @@ void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) { // this catches the payload from getMesh bool neighborsNeedUpdate; withWriteLock([&] { - _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; + if (!_collisionless) { + _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; + } _mesh = mesh; _meshDirty = true; _meshInitialized = true; From 6227db9fc0032c2cf6e29610bd46f6d562daf99a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 26 Feb 2017 08:30:29 -0800 Subject: [PATCH 07/10] optimize RenderablePolyVoxEntityItem::setSphere --- .../src/RenderablePolyVoxEntityItem.cpp | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 47ef598502..3ea58f7550 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -365,12 +365,28 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r } glm::mat4 vtwMatrix = voxelToWorldMatrix(); + glm::mat4 wtvMatrix = glm::inverse(vtwMatrix); - // This three-level for loop iterates over every voxel in the volume + glm::vec3 dimensions = getDimensions(); + glm::vec3 voxelSize = dimensions / _voxelVolumeSize; + float smallestDimensionSize = voxelSize.x; + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y); + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.z); + + glm::vec3 maxRadiusInVoxelCoords = glm::vec3(radiusWorldCoords / smallestDimensionSize); + glm::vec3 centerInVoxelCoords = wtvMatrix * glm::vec4(centerWorldCoords, 1.0f); + + glm::vec3 low = glm::floor(centerInVoxelCoords - maxRadiusInVoxelCoords); + glm::vec3 high = glm::ceil(centerInVoxelCoords + maxRadiusInVoxelCoords); + + glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize); + glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize); + + // This three-level for loop iterates over every voxel in the volume that might be in the sphere withWriteLock([&] { - for (int z = 0; z < _voxelVolumeSize.z; z++) { - for (int y = 0; y < _voxelVolumeSize.y; y++) { - for (int x = 0; x < _voxelVolumeSize.x; x++) { + for (int z = lowI.z; z < highI.z; z++) { + for (int y = lowI.y; y < highI.y; y++) { + for (int x = lowI.x; x < highI.x; x++) { // Store our current position as a vector... glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates // convert to world coordinates From 542cb7ab85aa61558fa50b0feb130f56a11b4842 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 26 Feb 2017 09:03:34 -0800 Subject: [PATCH 08/10] optimize RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket --- .../src/RenderablePolyVoxEntityItem.cpp | 42 ++++++++++++++----- .../src/RenderablePolyVoxEntityItem.h | 3 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 3ea58f7550..d3023c573a 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -266,6 +266,35 @@ void RenderablePolyVoxEntityItem::forEachVoxelValue(quint16 voxelXSize, quint16 }); } +QByteArray RenderablePolyVoxEntityItem::volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const { + int totalSize = voxelXSize * voxelYSize * voxelZSize; + QByteArray result = QByteArray(totalSize, '\0'); + int index = 0; + int lowX = 0; + int lowY = 0; + int lowZ = 0; + + withReadLock([&] { + if (isEdged(_voxelSurfaceStyle)) { + lowX++; + lowY++; + lowZ++; + voxelXSize++; + voxelYSize++; + voxelYSize++; + } + + for (int z = lowZ; z < voxelZSize; z++) { + for (int y = lowY; y < voxelYSize; y++) { + for (int x = lowX; x < voxelXSize; x++) { + result[index++] = _volData->getVoxelAt(x, y, z); + } + } + } + }); + + return result; +} bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { bool result = false; @@ -837,7 +866,7 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { } -uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(int x, int y, int z) { +uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(int x, int y, int z) const { if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) { return 0; } @@ -979,17 +1008,8 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() { EntityTreePointer tree = element ? element->getTree() : nullptr; QtConcurrent::run([voxelXSize, voxelYSize, voxelZSize, entity, tree] { - int rawSize = voxelXSize * voxelYSize * voxelZSize; - QByteArray uncompressedData = QByteArray(rawSize, '\0'); - auto polyVoxEntity = std::static_pointer_cast(entity); - polyVoxEntity->forEachVoxelValue(voxelXSize, voxelYSize, voxelZSize, [&] (int x, int y, int z, uint8_t uVoxelValue) { - int uncompressedIndex = - z * voxelYSize * voxelXSize + - y * voxelXSize + - x; - uncompressedData[uncompressedIndex] = uVoxelValue; - }); + QByteArray uncompressedData = polyVoxEntity->volDataToArray(voxelXSize, voxelYSize, voxelZSize); QByteArray newVoxelData; QDataStream writer(&newVoxelData, QIODevice::WriteOnly | QIODevice::Truncate); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ee4c3b318f..278f658a46 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -128,12 +128,13 @@ public: void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize); void forEachVoxelValue(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize, std::function thunk); + QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const; void setMesh(model::MeshPointer mesh); void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume* getVolData() { return _volData; } - uint8_t getVoxelInternal(int x, int y, int z); + uint8_t getVoxelInternal(int x, int y, int z) const; bool setVoxelInternal(int x, int y, int z, uint8_t toValue); void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; }); } From 88c850afa233882d2cb68effd43822502707e755 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 26 Feb 2017 12:56:17 -0800 Subject: [PATCH 09/10] voxel-paint paints with capsules rather than spheres --- .../src/RenderablePolyVoxEntityItem.cpp | 53 +++++++++++++++++++ .../src/RenderablePolyVoxEntityItem.h | 2 + .../entities/src/EntityScriptingInterface.cpp | 18 +++++++ .../entities/src/EntityScriptingInterface.h | 6 +++ libraries/entities/src/PolyVoxEntityItem.h | 2 + libraries/shared/src/GeometryUtil.cpp | 27 ++++++++++ libraries/shared/src/GeometryUtil.h | 3 ++ 7 files changed, 111 insertions(+) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index d3023c573a..a5b4896d45 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -437,6 +437,59 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r return result; } +bool RenderablePolyVoxEntityItem::setCapsule(glm::vec3 startWorldCoords, glm::vec3 endWorldCoords, + float radiusWorldCoords, uint8_t toValue) { + bool result = false; + if (_locked) { + return result; + } + + glm::mat4 vtwMatrix = voxelToWorldMatrix(); + glm::mat4 wtvMatrix = glm::inverse(vtwMatrix); + + glm::vec3 dimensions = getDimensions(); + glm::vec3 voxelSize = dimensions / _voxelVolumeSize; + float smallestDimensionSize = voxelSize.x; + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y); + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.z); + + glm::vec3 maxRadiusInVoxelCoords = glm::vec3(radiusWorldCoords / smallestDimensionSize); + + glm::vec3 startInVoxelCoords = wtvMatrix * glm::vec4(startWorldCoords, 1.0f); + glm::vec3 endInVoxelCoords = wtvMatrix * glm::vec4(endWorldCoords, 1.0f); + + glm::vec3 low = glm::min(glm::floor(startInVoxelCoords - maxRadiusInVoxelCoords), + glm::floor(endInVoxelCoords - maxRadiusInVoxelCoords)); + glm::vec3 high = glm::max(glm::ceil(startInVoxelCoords + maxRadiusInVoxelCoords), + glm::ceil(endInVoxelCoords + maxRadiusInVoxelCoords)); + + glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize); + glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize); + + // This three-level for loop iterates over every voxel in the volume that might be in the capsule + withWriteLock([&] { + for (int z = lowI.z; z < highI.z; z++) { + for (int y = lowI.y; y < highI.y; y++) { + for (int x = lowI.x; x < highI.x; x++) { + // Store our current position as a vector... + glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates + // convert to world coordinates + glm::vec3 worldPos = glm::vec3(vtwMatrix * pos); + if (pointInCapsule(worldPos, startWorldCoords, endWorldCoords, radiusWorldCoords)) { + result |= setVoxelInternal(x, y, z, toValue); + } + } + } + } + }); + + if (result) { + compressVolumeDataAndSendEditPacket(); + } + return result; +} + + class RaycastFunctor { public: diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 278f658a46..45842c2fb9 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -94,6 +94,8 @@ public: // coords are in world-space virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) override; + virtual bool setCapsule(glm::vec3 startWorldCoords, glm::vec3 endWorldCoords, + float radiusWorldCoords, uint8_t toValue) override; virtual bool setAll(uint8_t toValue) override; virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) override; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index fa1b53e324..eb634568f0 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -891,6 +891,16 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c }); } +bool EntityScriptingInterface::setVoxelCapsule(QUuid entityID, + const glm::vec3& start, const glm::vec3& end, + float radius, int value) { + PROFILE_RANGE(script_entities, __FUNCTION__); + + return setVoxels(entityID, [start, end, radius, value](PolyVoxEntityItem& polyVoxEntity) { + return polyVoxEntity.setCapsule(start, end, radius, value); + }); +} + bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) { PROFILE_RANGE(script_entities, __FUNCTION__); @@ -1524,3 +1534,11 @@ QObject* EntityScriptingInterface::getWebViewRoot(const QUuid& entityID) { return nullptr; } } + +// TODO move this someplace that makes more sense... +bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, + const glm::vec3& start, const glm::vec3& end, float radius) { + glm::vec3 penetration; + AABox aaBox(low, dimensions); + return aaBox.findCapsulePenetration(start, end, radius, penetration); +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 0353fa08a8..e9f0637830 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -223,6 +223,8 @@ public slots: Q_INVOKABLE bool getDrawZoneBoundaries() const; Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); + Q_INVOKABLE bool setVoxelCapsule(QUuid entityID, const glm::vec3& start, const glm::vec3& end, float radius, int value); + Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, @@ -287,6 +289,10 @@ public slots: Q_INVOKABLE QObject* getWebViewRoot(const QUuid& entityID); + Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, + const glm::vec3& start, const glm::vec3& end, float radius); + + signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 4f478c8bf7..910d8eff88 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -86,6 +86,8 @@ class PolyVoxEntityItem : public EntityItem { // coords are in world-space virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; } + virtual bool setCapsule(glm::vec3 startWorldCoords, glm::vec3 endWorldCoords, + float radiusWorldCoords, uint8_t toValue) { return false; } virtual bool setAll(uint8_t toValue) { return false; } virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value) { return false; } diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 92fe138021..c137ebd438 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -205,6 +205,33 @@ bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& directi return true; } +bool pointInSphere(const glm::vec3& origin, const glm::vec3& center, float radius) { + glm::vec3 relativeOrigin = origin - center; + float c = glm::dot(relativeOrigin, relativeOrigin) - radius * radius; + return c <= 0.0f; +} + + +bool pointInCapsule(const glm::vec3& origin, const glm::vec3& start, const glm::vec3& end, float radius) { + glm::vec3 relativeOrigin = origin - start; + glm::vec3 relativeEnd = end - start; + float capsuleLength = glm::length(relativeEnd); + relativeEnd /= capsuleLength; + float originProjection = glm::dot(relativeEnd, relativeOrigin); + glm::vec3 constant = relativeOrigin - relativeEnd * originProjection; + float c = glm::dot(constant, constant) - radius * radius; + if (c < 0.0f) { // starts inside cylinder + if (originProjection < 0.0f) { // below start + return pointInSphere(origin, start, radius); + } else if (originProjection > capsuleLength) { // above end + return pointInSphere(origin, end, radius); + } else { // between start and end + return true; + } + } + return false; +} + bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& start, const glm::vec3& end, float radius, float& distance) { if (start == end) { diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index 1c951ca09a..2fdc1aa25f 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -73,6 +73,9 @@ glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& center, float radius, float& distance); +bool pointInSphere(const glm::vec3& origin, const glm::vec3& center, float radius); +bool pointInCapsule(const glm::vec3& origin, const glm::vec3& start, const glm::vec3& end, float radius); + bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& start, const glm::vec3& end, float radius, float& distance); From 6b230bad1453b025c2438cebcea875580187f8d0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Feb 2017 20:56:25 -0800 Subject: [PATCH 10/10] oops --- libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index a5b4896d45..7359a548fc 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -281,7 +281,7 @@ QByteArray RenderablePolyVoxEntityItem::volDataToArray(quint16 voxelXSize, quint lowZ++; voxelXSize++; voxelYSize++; - voxelYSize++; + voxelZSize++; } for (int z = lowZ; z < voxelZSize; z++) {