parabola/polyvox, fixing some bugs

This commit is contained in:
SamGondelman 2018-07-23 16:41:26 -07:00
parent 763e6465a2
commit 318ef907b8
23 changed files with 257 additions and 177 deletions

View file

@ -618,6 +618,8 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
result.intersects = true;
result.avatarID = avatar->getID();
result.distance = distance;
result.face = face;
result.surfaceNormal = surfaceNormal;
result.extraInfo = extraInfo;
}
}
@ -688,6 +690,8 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
result.intersects = true;
result.avatarID = avatar->getID();
result.parabolicDistance = parabolicDistance;
result.face = face;
result.surfaceNormal = surfaceNormal;
result.extraInfo = extraInfo;
}
}

View file

@ -39,7 +39,7 @@ PickResultPointer ParabolaPick::getOverlayIntersection(const PickParabola& pick)
PickResultPointer ParabolaPick::getAvatarIntersection(const PickParabola& pick) {
ParabolaToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findParabolaIntersectionVector(pick, getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
if (avatarRes.intersects) {
return std::make_shared<ParabolaPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.parabolicDistance, avatarRes.intersection, pick, glm::vec3(NAN), avatarRes.extraInfo);
return std::make_shared<ParabolaPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.parabolicDistance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo);
} else {
return std::make_shared<ParabolaPickResult>(pick.toVariantMap());
}

View file

@ -156,7 +156,6 @@ void ParabolaPointer::RenderState::editParabola(const glm::vec3& color, float al
item.setIsVisibleInSecondaryCamera(isVisibleInSecondaryCamera);
item.setEnabled(enabled);
item.updateKey();
item.updateUniformBuffer();
});
scene->enqueueTransaction(transaction);
}
@ -182,7 +181,6 @@ void ParabolaPointer::RenderState::update(const glm::vec3& origin, const glm::ve
item.setAcceleration(acceleration);
item.setParabolicDistance(parabolicDistance);
item.setWidth(width);
item.updateUniformBuffer();
});
scene->enqueueTransaction(transaction);
}
@ -293,7 +291,6 @@ ParabolaPointer::RenderState::ParabolaRenderItem::ParabolaRenderItem(const glm::
setAlpha(alpha);
setWidth(width);
updateKey();
updateUniformBuffer();
}
void ParabolaPointer::RenderState::ParabolaRenderItem::setVisible(bool visible) {
@ -302,12 +299,16 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::setVisible(bool visible)
} else {
_key = render::ItemKey::Builder(_key).withInvisible();
}
_visible = visible;
}
void ParabolaPointer::RenderState::ParabolaRenderItem::updateKey() {
auto builder = _parabolaData.color.a < 1.0f ? render::ItemKey::Builder::transparentShape() : render::ItemKey::Builder::opaqueShape();
// FIXME: There's no way to designate a render item as non-shadow-reciever, and since a parabola's bounding box covers the entire domain,
// it seems to block all shadows. I think this is a bug with shadows.
//auto builder = _parabolaData.color.a < 1.0f ? render::ItemKey::Builder::transparentShape() : render::ItemKey::Builder::opaqueShape();
auto builder = render::ItemKey::Builder::transparentShape();
if (_enabled) {
if (_enabled && _visible) {
builder.withVisible();
} else {
builder.withInvisible();
@ -358,6 +359,10 @@ const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::get
}
void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args) {
if (!_visible) {
return;
}
gpu::Batch& batch = *(args->_batch);
Transform transform;
@ -366,12 +371,17 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args)
batch.setPipeline(getParabolaPipeline());
const int MAX_SECTIONS = 100;
if (glm::length2(_parabolaData.acceleration) < EPSILON) {
_parabolaData.numSections = 1;
} else {
_parabolaData.numSections = glm::clamp((int)(_parabolaData.parabolicDistance + 1) * 10, 1, MAX_SECTIONS);
}
updateUniformBuffer();
batch.setUniformBuffer(0, _uniformBuffer);
// TODO: variable number of sections, depending on ? (acceleration?, parabolicDistance?)
const int NUM_SECTIONS = 25; // must match value in parabola.slv
// We draw 2 * n + 2 vertices for a triangle strip
batch.draw(gpu::TRIANGLE_STRIP, 2 * NUM_SECTIONS + 2, 0);
batch.draw(gpu::TRIANGLE_STRIP, 2 * _parabolaData.numSections + 2, 0);
}
namespace render {

View file

@ -57,6 +57,7 @@ public:
glm::vec3 _origin { 0.0f };
bool _isVisibleInSecondaryCamera { DEFAULT_PARABOLA_ISVISIBLEINSECONDARYCAMERA };
bool _visible { false };
bool _enabled { false };
struct ParabolaData {
@ -65,6 +66,8 @@ public:
vec3 acceleration { 0.0f };
float width { DEFAULT_PARABOLA_WIDTH };
vec4 color { vec4(DEFAULT_PARABOLA_COLOR)};
int numSections { 0 };
ivec3 spare;
};
ParabolaData _parabolaData;

View file

@ -113,13 +113,12 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick
const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f);
endVec = pos + rot * (dim * (DEFAULT_REGISTRATION_POINT - registrationPoint));
glm::vec3 direction = endVec - origin;
float distance = glm::distance(origin, endVec);
distance = glm::distance(origin, endVec);
glm::vec3 normalizedDirection = glm::normalize(direction);
type = _lockEndObject.isOverlay ? IntersectionType::OVERLAY : IntersectionType::ENTITY;
id = _lockEndObject.id;
intersection = endVec;
distance = distance;
surfaceNormal = -normalizedDirection;
setVisualPickResultInternal(visualPickResult, type, id, intersection, distance, surfaceNormal);
} else if (type != IntersectionType::NONE && _lockEnd) {
@ -134,7 +133,6 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick
glm::vec3 direction = endVec - origin;
distance = glm::distance(origin, endVec);
glm::vec3 normalizedDirection = glm::normalize(direction);
type = type;
intersection = endVec;
surfaceNormal = -normalizedDirection;
setVisualPickResultInternal(visualPickResult, type, id, intersection, distance, surfaceNormal);

View file

@ -79,11 +79,11 @@ public:
void updateVisuals(const PickResultPointer& prevRayPickResult) override;
protected:
PointerTriggers _triggers;
float _pathLength { 0.0f };
RenderStateMap _renderStates;
DefaultRenderStateMap _defaultRenderStates;
std::string _currentRenderState { "" };
PointerTriggers _triggers;
float _pathLength { 0.0f };
bool _faceAvatar;
bool _followNormal;
bool _centerEndY;

View file

@ -39,7 +39,7 @@ PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) {
PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) {
RayToAvatarIntersectionResult avatarRes = DependencyManager::get<AvatarManager>()->findRayIntersectionVector(pick, getIncludeItemsAs<EntityItemID>(), getIgnoreItemsAs<EntityItemID>());
if (avatarRes.intersects) {
return std::make_shared<RayPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, glm::vec3(NAN), avatarRes.extraInfo);
return std::make_shared<RayPickResult>(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo);
} else {
return std::make_shared<RayPickResult>(pick.toVariantMap());
}

View file

@ -622,75 +622,37 @@ ParabolaToOverlayIntersectionResult Overlays::findParabolaIntersectionVector(con
}
QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) {
auto obj = engine->newObject();
QScriptValue obj = engine->newObject();
obj.setProperty("intersects", value.intersects);
obj.setProperty("overlayID", OverlayIDtoScriptValue(engine, value.overlayID));
QScriptValue overlayIDValue = quuidToScriptValue(engine, value.overlayID);
obj.setProperty("overlayID", overlayIDValue);
obj.setProperty("distance", value.distance);
obj.setProperty("face", boxFaceToString(value.face));
QString faceName = "";
// handle BoxFace
switch (value.face) {
case MIN_X_FACE:
faceName = "MIN_X_FACE";
break;
case MAX_X_FACE:
faceName = "MAX_X_FACE";
break;
case MIN_Y_FACE:
faceName = "MIN_Y_FACE";
break;
case MAX_Y_FACE:
faceName = "MAX_Y_FACE";
break;
case MIN_Z_FACE:
faceName = "MIN_Z_FACE";
break;
case MAX_Z_FACE:
faceName = "MAX_Z_FACE";
break;
default:
case UNKNOWN_FACE:
faceName = "UNKNOWN_FACE";
break;
}
obj.setProperty("face", faceName);
auto intersection = vec3toScriptValue(engine, value.intersection);
QScriptValue intersection = vec3toScriptValue(engine, value.intersection);
obj.setProperty("intersection", intersection);
QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal);
obj.setProperty("surfaceNormal", surfaceNormal);
obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo));
return obj;
}
void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar, RayToOverlayIntersectionResult& value) {
QVariantMap object = objectVar.toVariant().toMap();
value.intersects = object["intersects"].toBool();
value.overlayID = OverlayID(QUuid(object["overlayID"].toString()));
value.distance = object["distance"].toFloat();
void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, RayToOverlayIntersectionResult& value) {
value.intersects = object.property("intersects").toVariant().toBool();
QScriptValue overlayIDValue = object.property("overlayID");
quuidFromScriptValue(overlayIDValue, value.overlayID);
value.distance = object.property("distance").toVariant().toFloat();
value.face = boxFaceFromString(object.property("face").toVariant().toString());
QString faceName = object["face"].toString();
if (faceName == "MIN_X_FACE") {
value.face = MIN_X_FACE;
} else if (faceName == "MAX_X_FACE") {
value.face = MAX_X_FACE;
} else if (faceName == "MIN_Y_FACE") {
value.face = MIN_Y_FACE;
} else if (faceName == "MAX_Y_FACE") {
value.face = MAX_Y_FACE;
} else if (faceName == "MIN_Z_FACE") {
value.face = MIN_Z_FACE;
} else if (faceName == "MAX_Z_FACE") {
value.face = MAX_Z_FACE;
} else {
value.face = UNKNOWN_FACE;
};
auto intersection = object["intersection"];
QScriptValue intersection = object.property("intersection");
if (intersection.isValid()) {
bool valid;
auto newIntersection = vec3FromVariant(intersection, valid);
if (valid) {
value.intersection = newIntersection;
}
vec3FromScriptValue(intersection, value.intersection);
}
value.extraInfo = object["extraInfo"].toMap();
QScriptValue surfaceNormal = object.property("surfaceNormal");
if (surfaceNormal.isValid()) {
vec3FromScriptValue(surfaceNormal, value.surfaceNormal);
}
value.extraInfo = object.property("extraInfo").toVariant().toMap();
}
bool Overlays::isLoaded(OverlayID id) {

View file

@ -59,7 +59,7 @@ class RayToOverlayIntersectionResult {
public:
bool intersects { false };
OverlayID overlayID { UNKNOWN_OVERLAY_ID };
float distance { 0 };
float distance { 0.0f };
BoxFace face { UNKNOWN_FACE };
glm::vec3 surfaceNormal;
glm::vec3 intersection;
@ -73,8 +73,8 @@ class ParabolaToOverlayIntersectionResult {
public:
bool intersects { false };
OverlayID overlayID { UNKNOWN_OVERLAY_ID };
float distance { 0 };
float parabolicDistance { 0 };
float distance { 0.0f };
float parabolicDistance { 0.0f };
BoxFace face { UNKNOWN_FACE };
glm::vec3 surfaceNormal;
glm::vec3 intersection;

View file

@ -2555,15 +2555,18 @@ glm::mat4 AvatarData::getControllerRightHandMatrix() const {
return _controllerRightHandMatrixCache.get();
}
QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& value) {
QScriptValue obj = engine->newObject();
obj.setProperty("intersects", value.intersects);
QScriptValue avatarIDValue = quuidToScriptValue(engine, value.avatarID);
obj.setProperty("avatarID", avatarIDValue);
obj.setProperty("distance", value.distance);
obj.setProperty("face", boxFaceToString(value.face));
QScriptValue intersection = vec3toScriptValue(engine, value.intersection);
obj.setProperty("intersection", intersection);
QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal);
obj.setProperty("surfaceNormal", surfaceNormal);
obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo));
return obj;
}
@ -2573,10 +2576,16 @@ void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, Ra
QScriptValue avatarIDValue = object.property("avatarID");
quuidFromScriptValue(avatarIDValue, value.avatarID);
value.distance = object.property("distance").toVariant().toFloat();
value.face = boxFaceFromString(object.property("face").toVariant().toString());
QScriptValue intersection = object.property("intersection");
if (intersection.isValid()) {
vec3FromScriptValue(intersection, value.intersection);
}
QScriptValue surfaceNormal = object.property("surfaceNormal");
if (surfaceNormal.isValid()) {
vec3FromScriptValue(surfaceNormal, value.surfaceNormal);
}
value.extraInfo = object.property("extraInfo").toVariant().toMap();
}

View file

@ -1527,7 +1527,9 @@ public:
bool intersects { false };
QUuid avatarID;
float distance { 0.0f };
BoxFace face;
glm::vec3 intersection;
glm::vec3 surfaceNormal;
QVariantMap extraInfo;
};
Q_DECLARE_METATYPE(RayToAvatarIntersectionResult)
@ -1540,7 +1542,9 @@ public:
QUuid avatarID;
float distance { 0.0f };
float parabolicDistance { 0.0f };
BoxFace face;
glm::vec3 intersection;
glm::vec3 surfaceNormal;
QVariantMap extraInfo;
};

View file

@ -567,8 +567,7 @@ public:
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element,
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const
{
QVariantMap& extraInfo, bool precisionPicking) const {
// TODO -- correctly pick against marching-cube generated meshes
if (!precisionPicking) {
// just intersect with bounding box
@ -614,6 +613,87 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
return hit;
}
bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
const glm::vec3& acceleration, OctreeElementPointer& element,
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const {
// TODO -- correctly pick against marching-cube generated meshes
if (!precisionPicking) {
// just intersect with bounding box
return true;
}
glm::mat4 wtvMatrix = worldToVoxelMatrix();
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
glm::vec4 velocityInVoxel = wtvMatrix * glm::vec4(velocity, 0.0f);
glm::vec4 accelerationInVoxel = wtvMatrix * glm::vec4(acceleration, 0.0f);
// find the first intersection with the voxel bounding box (slightly enlarged so we can catch voxels that touch the sides)
bool success;
glm::vec3 center = getCenterPosition(success);
glm::vec3 dimensions = getScaledDimensions();
const float FIRST_BOX_HALF_SCALE = 0.51f;
AABox voxelBox1(wtvMatrix * vec4(center - FIRST_BOX_HALF_SCALE * dimensions, 1.0f),
wtvMatrix * vec4(2.0f * FIRST_BOX_HALF_SCALE * dimensions, 0.0f));
bool hit1;
float parabolicDistance1;
// If we're starting inside the box, our first point is originInVoxel
if (voxelBox1.contains(originInVoxel)) {
parabolicDistance1 = 0.0f;
hit1 = true;
} else {
BoxFace face1;
glm::vec3 surfaceNormal1;
hit1 = voxelBox1.findParabolaIntersection(glm::vec3(originInVoxel), glm::vec3(velocityInVoxel), glm::vec3(accelerationInVoxel),
parabolicDistance1, face1, surfaceNormal1);
}
if (hit1) {
// find the second intersection, which should be with the inside of the box (use a slightly large box again)
const float SECOND_BOX_HALF_SCALE = 0.52f;
AABox voxelBox2(wtvMatrix * vec4(center - SECOND_BOX_HALF_SCALE * dimensions, 1.0f),
wtvMatrix * vec4(2.0f * SECOND_BOX_HALF_SCALE * dimensions, 0.0f));
glm::vec4 originInVoxel2 = originInVoxel + velocityInVoxel * parabolicDistance1 + 0.5f * accelerationInVoxel * parabolicDistance1 * parabolicDistance1;
glm::vec4 velocityInVoxel2 = velocityInVoxel + accelerationInVoxel * parabolicDistance1;
glm::vec4 accelerationInVoxel2 = accelerationInVoxel;
float parabolicDistance2;
BoxFace face2;
glm::vec3 surfaceNormal2;
// this should always be true
if (voxelBox2.findParabolaIntersection(glm::vec3(originInVoxel2), glm::vec3(velocityInVoxel2), glm::vec3(accelerationInVoxel2),
parabolicDistance2, face2, surfaceNormal2)) {
const int MAX_SECTIONS = 15;
PolyVox::RaycastResult raycastResult = PolyVox::RaycastResults::Completed;
glm::vec4 result = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
glm::vec4 segmentStartVoxel = originInVoxel2;
for (int i = 0; i < MAX_SECTIONS; i++) {
float t = parabolicDistance2 * ((float)(i + 1)) / ((float)MAX_SECTIONS);
glm::vec4 segmentEndVoxel = originInVoxel2 + velocityInVoxel2 * t + 0.5f * accelerationInVoxel2 * t * t;
raycastResult = doRayCast(segmentStartVoxel, segmentEndVoxel, result);
if (raycastResult != PolyVox::RaycastResults::Completed) {
// We hit something!
break;
}
segmentStartVoxel = segmentEndVoxel;
}
if (raycastResult == PolyVox::RaycastResults::Completed) {
// the parabola completed its path -- nothing was hit.
return false;
}
glm::vec3 result3 = glm::vec3(result);
AABox voxelBox;
voxelBox += result3 - Vectors::HALF;
voxelBox += result3 + Vectors::HALF;
return voxelBox.findParabolaIntersection(glm::vec3(originInVoxel), glm::vec3(velocityInVoxel), glm::vec3(accelerationInVoxel),
parabolicDistance, face, surfaceNormal);
}
}
return false;
}
PolyVox::RaycastResult RenderablePolyVoxEntityItem::doRayCast(glm::vec4 originInVoxel,
glm::vec4 farInVoxel,

View file

@ -53,9 +53,13 @@ public:
virtual bool supportsDetailedIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
OctreeElementPointer& element, float& distance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const vec3& accleration,
OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const override;
virtual void setVoxelData(const QByteArray& voxelData) override;
virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) override;

View file

@ -1050,65 +1050,16 @@ bool EntityScriptingInterface::getDrawZoneBoundaries() const {
}
QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& value) {
PROFILE_RANGE(script_entities, __FUNCTION__);
QScriptValue obj = engine->newObject();
obj.setProperty("intersects", value.intersects);
obj.setProperty("accurate", value.accurate);
QScriptValue entityItemValue = EntityItemIDtoScriptValue(engine, value.entityID);
obj.setProperty("entityID", entityItemValue);
obj.setProperty("distance", value.distance);
QString faceName = "";
// handle BoxFace
/**jsdoc
* <p>A <code>BoxFace</code> specifies the face of an axis-aligned (AA) box.
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"MIN_X_FACE"</code></td><td>The minimum x-axis face.</td></tr>
* <tr><td><code>"MAX_X_FACE"</code></td><td>The maximum x-axis face.</td></tr>
* <tr><td><code>"MIN_Y_FACE"</code></td><td>The minimum y-axis face.</td></tr>
* <tr><td><code>"MAX_Y_FACE"</code></td><td>The maximum y-axis face.</td></tr>
* <tr><td><code>"MIN_Z_FACE"</code></td><td>The minimum z-axis face.</td></tr>
* <tr><td><code>"MAX_Z_FACE"</code></td><td>The maximum z-axis face.</td></tr>
* <tr><td><code>"UNKNOWN_FACE"</code></td><td>Unknown value.</td></tr>
* </tbody>
* </table>
* @typedef {string} BoxFace
*/
// FIXME: Move enum to string function to BoxBase.cpp.
switch (value.face) {
case MIN_X_FACE:
faceName = "MIN_X_FACE";
break;
case MAX_X_FACE:
faceName = "MAX_X_FACE";
break;
case MIN_Y_FACE:
faceName = "MIN_Y_FACE";
break;
case MAX_Y_FACE:
faceName = "MAX_Y_FACE";
break;
case MIN_Z_FACE:
faceName = "MIN_Z_FACE";
break;
case MAX_Z_FACE:
faceName = "MAX_Z_FACE";
break;
case UNKNOWN_FACE:
faceName = "UNKNOWN_FACE";
break;
}
obj.setProperty("face", faceName);
obj.setProperty("face", boxFaceToString(value.face));
QScriptValue intersection = vec3toScriptValue(engine, value.intersection);
obj.setProperty("intersection", intersection);
QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal);
obj.setProperty("surfaceNormal", surfaceNormal);
obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo));
@ -1116,29 +1067,13 @@ QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, c
}
void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& value) {
PROFILE_RANGE(script_entities, __FUNCTION__);
value.intersects = object.property("intersects").toVariant().toBool();
value.accurate = object.property("accurate").toVariant().toBool();
QScriptValue entityIDValue = object.property("entityID");
// EntityItemIDfromScriptValue(entityIDValue, value.entityID);
quuidFromScriptValue(entityIDValue, value.entityID);
value.distance = object.property("distance").toVariant().toFloat();
value.face = boxFaceFromString(object.property("face").toVariant().toString());
QString faceName = object.property("face").toVariant().toString();
if (faceName == "MIN_X_FACE") {
value.face = MIN_X_FACE;
} else if (faceName == "MAX_X_FACE") {
value.face = MAX_X_FACE;
} else if (faceName == "MIN_Y_FACE") {
value.face = MIN_Y_FACE;
} else if (faceName == "MAX_Y_FACE") {
value.face = MAX_Y_FACE;
} else if (faceName == "MIN_Z_FACE") {
value.face = MIN_Z_FACE;
} else {
value.face = MAX_Z_FACE;
};
QScriptValue intersection = object.property("intersection");
if (intersection.isValid()) {
vec3FromScriptValue(intersection, value.intersection);

View file

@ -80,9 +80,7 @@ public:
glm::vec3 surfaceNormal;
QVariantMap extraInfo;
};
Q_DECLARE_METATYPE(RayToEntityIntersectionResult)
QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& results);
void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& results);

View file

@ -97,7 +97,7 @@ class PolyLineEntityItem : public EntityItem {
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const { return false; }
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
// disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain
virtual void setRegistrationPoint(const glm::vec3& value) override {}; // FIXME: this is suspicious!

View file

@ -50,7 +50,7 @@ class PolyVoxEntityItem : public EntityItem {
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
BoxFace& face, glm::vec3& surfaceNormal,
QVariantMap& extraInfo, bool precisionPicking) const { return false; }
QVariantMap& extraInfo, bool precisionPicking) const override { return false; }
virtual void debugDump() const override;

View file

@ -516,9 +516,9 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
face = triangleSetFace;
bestModelTriangle = triangleSetTriangle;
bestWorldTriangle = triangleSetTriangle * meshToWorldMatrix;
glm::vec3 worldIntersectionPoint = meshFrameOrigin + meshFrameVelocity * triangleSetDistance +
glm::vec3 meshIntersectionPoint = meshFrameOrigin + meshFrameVelocity * triangleSetDistance +
0.5f * meshFrameAcceleration * triangleSetDistance * triangleSetDistance;
glm::vec3 meshIntersectionPoint = origin + velocity * triangleSetDistance +
glm::vec3 worldIntersectionPoint = origin + velocity * triangleSetDistance +
0.5f * acceleration * triangleSetDistance * triangleSetDistance;
extraInfo["worldIntersectionPoint"] = vec3toVariant(worldIntersectionPoint);
extraInfo["meshIntersectionPoint"] = vec3toVariant(meshIntersectionPoint);

View file

@ -18,6 +18,8 @@ layout(std140) uniform parabolaData {
vec3 acceleration;
float width;
vec4 color;
int numSections;
ivec3 spare;
};
out vec4 _color;
@ -25,8 +27,7 @@ out vec4 _color;
void main(void) {
_color = color;
const int NUM_SECTIONS = 25; // must match value in ParabolaPointer.cpp
float t = parabolicDistance * (floor(gl_VertexID / 2) / float(NUM_SECTIONS));
float t = parabolicDistance * (floor(gl_VertexID / 2) / float(numSections));
vec4 pos = vec4(velocity * t + 0.5 * acceleration * t * t, 1);
const float EPSILON = 0.00001;

View file

@ -0,0 +1,46 @@
//
// Created by Sam Gondelman on 7/20/18
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "BoxBase.h"
QString boxFaceToString(BoxFace face) {
switch (face) {
case MIN_X_FACE:
return "MIN_X_FACE";
case MAX_X_FACE:
return "MAX_X_FACE";
case MIN_Y_FACE:
return "MIN_Y_FACE";
case MAX_Y_FACE:
return "MAX_Y_FACE";
case MIN_Z_FACE:
return "MIN_Z_FACE";
case MAX_Z_FACE:
return "MAX_Z_FACE";
default:
return "UNKNOWN_FACE";
}
}
BoxFace boxFaceFromString(const QString& face) {
if (face == "MIN_X_FACE") {
return MIN_X_FACE;
} else if (face == "MAX_X_FACE") {
return MAX_X_FACE;
} else if (face == "MIN_Y_FACE") {
return MIN_Y_FACE;
} else if (face == "MAX_Y_FACE") {
return MAX_Y_FACE;
} else if (face == "MIN_Z_FACE") {
return MIN_Z_FACE;
} else if (face == "MAX_Z_FACE") {
return MAX_Z_FACE;
} else {
return UNKNOWN_FACE;
}
}

View file

@ -16,7 +16,26 @@
#define hifi_BoxBase_h
#include <glm/glm.hpp>
#include <QString>
/**jsdoc
* <p>A <code>BoxFace</code> specifies the face of an axis-aligned (AA) box.
* <table>
* <thead>
* <tr><th>Value</th><th>Description</th></tr>
* </thead>
* <tbody>
* <tr><td><code>"MIN_X_FACE"</code></td><td>The minimum x-axis face.</td></tr>
* <tr><td><code>"MAX_X_FACE"</code></td><td>The maximum x-axis face.</td></tr>
* <tr><td><code>"MIN_Y_FACE"</code></td><td>The minimum y-axis face.</td></tr>
* <tr><td><code>"MAX_Y_FACE"</code></td><td>The maximum y-axis face.</td></tr>
* <tr><td><code>"MIN_Z_FACE"</code></td><td>The minimum z-axis face.</td></tr>
* <tr><td><code>"MAX_Z_FACE"</code></td><td>The maximum z-axis face.</td></tr>
* <tr><td><code>"UNKNOWN_FACE"</code></td><td>Unknown value.</td></tr>
* </tbody>
* </table>
* @typedef {string} BoxFace
*/
enum BoxFace {
MIN_X_FACE,
MAX_X_FACE,
@ -27,6 +46,9 @@ enum BoxFace {
UNKNOWN_FACE
};
QString boxFaceToString(BoxFace face);
BoxFace boxFaceFromString(const QString& face);
enum BoxVertex {
BOTTOM_LEFT_NEAR = 0,
BOTTOM_RIGHT_NEAR = 1,

View file

@ -952,7 +952,7 @@ void checkPossibleParabolicIntersectionWithTriangle(float t, float& minDistance,
bool findParabolaTriangleIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& parabolicDistance, bool allowBackface) {
glm::vec3 normal = glm::cross(v2 - v1, v0 - v1);
glm::vec3 normal = glm::normalize(glm::cross(v2 - v1, v0 - v1));
// We transform the parabola and triangle so that the triangle is in the plane z = 0, with v0 at the origin
glm::quat inverseRot;
@ -1092,7 +1092,7 @@ inline float parabolaVelocityAtT(float velocity, float acceleration, float t) {
bool findParabolaAABoxIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
const glm::vec3& corner, const glm::vec3& scale, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal) {
float minDistance = FLT_MAX;
BoxFace minFace;
BoxFace minFace = UNKNOWN_FACE;
glm::vec3 minNormal;
glm::vec2 possibleDistances;
float a, b, c;
@ -1720,8 +1720,8 @@ unsigned int solveP3(float* x, float a, float b, float c) {
a /= 3.0f;
q = -2.0f * sqrtf(q);
x[0] = q * cosf(t / 3.0f) - a;
x[1] = q * cosf((t + 2.0f * M_PI) / 3.0f) - a;
x[2] = q * cosf((t - 2.0f * M_PI) / 3.0f) - a;
x[1] = q * cosf((t + 2.0f * (float)M_PI) / 3.0f) - a;
x[2] = q * cosf((t - 2.0f * (float)M_PI) / 3.0f) - a;
return 3;
} else {
A = -powf(fabsf(r) + sqrtf(r2 - q3), 1.0f / 3.0f);
@ -1755,27 +1755,27 @@ bool solve_quartic(float a, float b, float c, float d, glm::vec4& roots) {
y = px3[0];
if (iZeroes != 1) {
if (fabs(px3[1]) > fabs(y)) {
if (fabsf(px3[1]) > fabsf(y)) {
y = px3[1];
}
if (fabs(px3[2]) > fabs(y)) {
if (fabsf(px3[2]) > fabsf(y)) {
y = px3[2];
}
}
D = y * y - 4.0f * d;
if (fabs(D) < EPSILON) {
if (fabsf(D) < EPSILON) {
q1 = q2 = 0.5f * y;
D = a * a - 4.0f * (b - y);
if (fabs(D) < EPSILON) {
if (fabsf(D) < EPSILON) {
p1 = p2 = 0.5f * a;
} else {
sqD = sqrt(D);
sqD = sqrtf(D);
p1 = 0.5f * (a + sqD);
p2 = 0.5f * (a - sqD);
}
} else {
sqD = sqrt(D);
sqD = sqrtf(D);
q1 = 0.5f * (y + sqD);
q2 = 0.5f * (y - sqD);
p1 = (a * q1 - c) / (q1 - q2);
@ -1786,10 +1786,10 @@ bool solve_quartic(float a, float b, float c, float d, glm::vec4& roots) {
D = p1 * p1 - 4.0f * q1;
if (D < 0.0f) {
x1.real(-0.5f * p1);
x1.imag(0.5f * sqrt(-D));
x1.imag(0.5f * sqrtf(-D));
x2 = std::conj(x1);
} else {
sqD = sqrt(D);
sqD = sqrtf(D);
x1.real(0.5f * (-p1 + sqD));
x2.real(0.5f * (-p1 - sqD));
}
@ -1797,10 +1797,10 @@ bool solve_quartic(float a, float b, float c, float d, glm::vec4& roots) {
D = p2 * p2 - 4.0f * q2;
if (D < 0.0f) {
x3.real(-0.5f * p2);
x3.imag(0.5f * sqrt(-D));
x3.imag(0.5f * sqrtf(-D));
x4 = std::conj(x3);
} else {
sqD = sqrt(D);
sqD = sqrtf(D);
x3.real(0.5f * (-p2 + sqD));
x4.real(0.5f * (-p2 - sqD));
}

View file

@ -100,7 +100,7 @@ Script.include("/~/system/libraries/controllers.js");
{name: "teleport", path: teleportPath, end: teleportEnd},
{name: "seat", path: seatPath, end: seatEnd}];
var DEFAULT_DISTANCE = 10;
var DEFAULT_DISTANCE = 4.0;
var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}];
var coolInTimeout = null;
@ -151,7 +151,8 @@ Script.include("/~/system/libraries/controllers.js");
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates,
defaultRenderStates: teleportDefaultRenderStates
defaultRenderStates: teleportDefaultRenderStates,
maxDistance: 4.0
});
this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, {
joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand",
@ -163,7 +164,8 @@ Script.include("/~/system/libraries/controllers.js");
speed: speed,
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates
renderStates: teleportRenderStates,
maxDistance: 4.0
});
this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, {
joint: "Avatar",
@ -176,7 +178,8 @@ Script.include("/~/system/libraries/controllers.js");
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates,
defaultRenderStates: teleportDefaultRenderStates
defaultRenderStates: teleportDefaultRenderStates,
maxDistance: 4.0
});
this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, {
joint: "Avatar",
@ -188,7 +191,8 @@ Script.include("/~/system/libraries/controllers.js");
speed: speed,
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates
renderStates: teleportRenderStates,
maxDistance: 4.0
});
this.cleanup = function() {
@ -430,7 +434,7 @@ Script.include("/~/system/libraries/controllers.js");
}
var surfaceNormal = result.surfaceNormal;
var angle = Math.abs(Math.acos(Vec3.dot(surfaceNormal, Quat.getUp(MyAvatar.orientation)))) * (180.0 / Math.PI);
var angle = Math.acos(Vec3.dot(surfaceNormal, Quat.getUp(MyAvatar.orientation))) * (180.0 / Math.PI);
if (angle > MAX_ANGLE_FROM_UP_TO_TELEPORT ||
Vec3.distance(MyAvatar.position, result.intersection) <= TELEPORT_CANCEL_RANGE * MyAvatar.sensorToWorldScale) {