voxel-paint paints with capsules rather than spheres

This commit is contained in:
Seth Alves 2017-02-26 12:56:17 -08:00
parent 542cb7ab85
commit 88c850afa2
7 changed files with 111 additions and 0 deletions

View file

@ -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:

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -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; }

View file

@ -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) {

View file

@ -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);