Merge branch 'master' of https://github.com/highfidelity/hifi into punk

This commit is contained in:
Sam Gateau 2018-08-21 19:23:33 -07:00
commit 0f6f465e7f
16 changed files with 328 additions and 107 deletions

View file

@ -5261,6 +5261,7 @@ void Application::resetPhysicsReadyInformation() {
_nearbyEntitiesCountAtLastPhysicsCheck = 0;
_nearbyEntitiesStabilityCount = 0;
_physicsEnabled = false;
_octreeProcessor.startEntitySequence();
}
@ -5498,7 +5499,7 @@ void Application::update(float deltaTime) {
// Check for flagged EntityData having arrived.
auto entityTreeRenderer = getEntities();
if (isServerlessMode() ||
(entityTreeRenderer && _octreeProcessor.octreeSequenceIsComplete(entityTreeRenderer->getLastOctreeMessageSequence()) )) {
(_octreeProcessor.isLoadSequenceComplete() )) {
// we've received a new full-scene octree stats packet, or it's been long enough to try again anyway
_lastPhysicsCheckTime = now;
_fullSceneCounterAtLastPhysicsCheck = _fullSceneReceivedCounter;
@ -5507,7 +5508,7 @@ void Application::update(float deltaTime) {
// process octree stats packets are sent in between full sends of a scene (this isn't currently true).
// We keep physics disabled until we've received a full scene and everything near the avatar in that
// scene is ready to compute its collision shape.
if (nearbyEntitiesAreReadyForPhysics() && getMyAvatar()->isReadyForPhysics()) {
if (getMyAvatar()->isReadyForPhysics()) {
_physicsEnabled = true;
getMyAvatar()->updateMotionBehaviorFromMenu();
}
@ -6311,7 +6312,6 @@ void Application::clearDomainOctreeDetails() {
_octreeServerSceneStats.clear();
});
_octreeProcessor.resetCompletionSequenceNumber();
// reset the model renderer
getEntities()->clear();

View file

@ -16,8 +16,11 @@
#include "Application.h"
#include "Menu.h"
#include "SceneScriptingInterface.h"
#include "SafeLanding.h"
OctreePacketProcessor::OctreePacketProcessor() {
OctreePacketProcessor::OctreePacketProcessor():
_safeLanding(new SafeLanding())
{
setObjectName("Octree Packet Processor");
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
@ -26,6 +29,8 @@ OctreePacketProcessor::OctreePacketProcessor() {
packetReceiver.registerDirectListenerForTypes(octreePackets, this, "handleOctreePacket");
}
OctreePacketProcessor::~OctreePacketProcessor() { }
void OctreePacketProcessor::handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode) {
queueReceivedPacket(message, senderNode);
}
@ -107,6 +112,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
auto renderer = qApp->getEntities();
if (renderer) {
renderer->processDatagram(*message, sendingNode);
_safeLanding->noteReceivedsequenceNumber(renderer->getLastOctreeMessageSequence());
}
}
} break;
@ -115,8 +121,7 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
// Read sequence #
OCTREE_PACKET_SEQUENCE completionNumber;
message->readPrimitive(&completionNumber);
_completionSequenceNumber = completionNumber;
_safeLanding->setCompletionSequenceNumbers(0, completionNumber);
} break;
default: {
@ -125,22 +130,10 @@ void OctreePacketProcessor::processPacket(QSharedPointer<ReceivedMessage> messag
}
}
void OctreePacketProcessor::resetCompletionSequenceNumber() {
_completionSequenceNumber = INVALID_SEQUENCE;
void OctreePacketProcessor::startEntitySequence() {
_safeLanding->startEntitySequence(qApp->getEntities());
}
namespace {
template<typename T> bool lessThanWraparound(int a, int b) {
constexpr int MAX_T_VALUE = std::numeric_limits<T>::max();
if (b <= a) {
b += MAX_T_VALUE;
}
return (b - a) < (MAX_T_VALUE / 2);
}
}
bool OctreePacketProcessor::octreeSequenceIsComplete(int sequenceNumber) const {
// If we've received the flagged seq # and the current one is >= it.
return _completionSequenceNumber != INVALID_SEQUENCE &&
!lessThanWraparound<OCTREE_PACKET_SEQUENCE>(sequenceNumber, _completionSequenceNumber);
bool OctreePacketProcessor::isLoadSequenceComplete() const {
return _safeLanding->isLoadSequenceComplete();
}

View file

@ -15,21 +15,22 @@
#include <ReceivedPacketProcessor.h>
#include <ReceivedMessage.h>
class SafeLanding;
/// Handles processing of incoming voxel packets for the interface application. As with other ReceivedPacketProcessor classes
/// the user is responsible for reading inbound packets and adding them to the processing queue by calling queueReceivedPacket()
class OctreePacketProcessor : public ReceivedPacketProcessor {
Q_OBJECT
public:
OctreePacketProcessor();
~OctreePacketProcessor();
bool octreeSequenceIsComplete(int sequenceNumber) const;
void startEntitySequence();
bool isLoadSequenceComplete() const;
signals:
void packetVersionMismatch();
public slots:
void resetCompletionSequenceNumber();
protected:
virtual void processPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer sendingNode) override;
@ -37,8 +38,6 @@ private slots:
void handleOctreePacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
private:
static constexpr int INVALID_SEQUENCE = -1;
std::atomic<int> _completionSequenceNumber { INVALID_SEQUENCE };
std::unique_ptr<SafeLanding> _safeLanding;
};
#endif // hifi_OctreePacketProcessor_h

View file

@ -0,0 +1,172 @@
//
// SafeLanding.cpp
// interface/src/octree
//
// Created by Simon Walton.
// 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 "SafeLanding.h"
#include "EntityTreeRenderer.h"
#include "ModelEntityItem.h"
#include "InterfaceLogging.h"
const int SafeLanding::SEQUENCE_MODULO = std::numeric_limits<OCTREE_PACKET_SEQUENCE>::max() + 1;
namespace {
template<typename T> bool lessThanWraparound(int a, int b) {
constexpr int MAX_T_VALUE = std::numeric_limits<T>::max();
if (b <= a) {
b += MAX_T_VALUE;
}
return (b - a) < (MAX_T_VALUE / 2);
}
}
bool SafeLanding::SequenceLessThan::operator()(const int& a, const int& b) const {
return lessThanWraparound<OCTREE_PACKET_SEQUENCE>(a, b);
}
void SafeLanding::startEntitySequence(QSharedPointer<EntityTreeRenderer> entityTreeRenderer) {
auto entityTree = entityTreeRenderer->getTree();
if (entityTree) {
Locker lock(_lock);
_entityTree = entityTree;
_trackedEntities.clear();
_trackingEntities = true;
connect(std::const_pointer_cast<EntityTree>(_entityTree).get(),
&EntityTree::addingEntity, this, &SafeLanding::addTrackedEntity);
connect(std::const_pointer_cast<EntityTree>(_entityTree).get(),
&EntityTree::deletingEntity, this, &SafeLanding::deleteTrackedEntity);
_sequenceNumbers.clear();
_initialStart = INVALID_SEQUENCE;
_initialEnd = INVALID_SEQUENCE;
EntityTreeRenderer::setEntityLoadingPriorityFunction(&ElevatedPriority);
}
}
void SafeLanding::stopEntitySequence() {
Locker lock(_lock);
_trackingEntities = false;
_initialStart = INVALID_SEQUENCE;
_initialEnd = INVALID_SEQUENCE;
_trackedEntities.clear();
_sequenceNumbers.clear();
}
void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
if (_trackingEntities) {
Locker lock(_lock);
EntityItemPointer entity = _entityTree->findEntityByID(entityID);
if (entity && !entity->getCollisionless()) {
const auto& entityType = entity->getType();
if (entityType == EntityTypes::Model) {
ModelEntityItem * modelEntity = std::dynamic_pointer_cast<ModelEntityItem>(entity).get();
static const std::set<ShapeType> downloadedCollisionTypes
{ SHAPE_TYPE_COMPOUND, SHAPE_TYPE_SIMPLE_COMPOUND, SHAPE_TYPE_STATIC_MESH, SHAPE_TYPE_SIMPLE_HULL };
bool hasAABox;
entity->getAABox(hasAABox);
if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) {
// Only track entities with downloaded collision bodies.
_trackedEntities.emplace(entityID, entity);
qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName();
}
}
}
}
}
void SafeLanding::deleteTrackedEntity(const EntityItemID& entityID) {
Locker lock(_lock);
_trackedEntities.erase(entityID);
}
void SafeLanding::setCompletionSequenceNumbers(int first, int last) {
Locker lock(_lock);
if (_initialStart == INVALID_SEQUENCE) {
_initialStart = first;
_initialEnd = last;
}
}
void SafeLanding::noteReceivedsequenceNumber(int sequenceNumber) {
if (_trackingEntities) {
Locker lock(_lock);
_sequenceNumbers.insert(sequenceNumber);
}
}
bool SafeLanding::isLoadSequenceComplete() {
if (isEntityPhysicsComplete() && isSequenceNumbersComplete()) {
Locker lock(_lock);
_trackedEntities.clear();
_initialStart = INVALID_SEQUENCE;
_initialEnd = INVALID_SEQUENCE;
_entityTree = nullptr;
EntityTreeRenderer::setEntityLoadingPriorityFunction(StandardPriority);
qCDebug(interfaceapp) << "Safe Landing: load sequence complete";
}
return !_trackingEntities;
}
bool SafeLanding::isSequenceNumbersComplete() {
if (_initialStart != INVALID_SEQUENCE) {
Locker lock(_lock);
int sequenceSize = _initialStart <= _initialEnd ? _initialEnd - _initialStart:
_initialEnd + SEQUENCE_MODULO - _initialStart;
auto startIter = _sequenceNumbers.find(_initialStart);
auto endIter = _sequenceNumbers.find(_initialEnd);
if (sequenceSize == 0 ||
(startIter != _sequenceNumbers.end()
&& endIter != _sequenceNumbers.end()
&& distance(startIter, endIter) == sequenceSize) ) {
_trackingEntities = false; // Don't track anything else that comes in.
return true;
}
}
return false;
}
bool SafeLanding::isEntityPhysicsComplete() {
Locker lock(_lock);
for (auto entityMapIter = _trackedEntities.begin(); entityMapIter != _trackedEntities.end(); ++entityMapIter) {
auto entity = entityMapIter->second;
if (!entity->shouldBePhysical() || entity->isReadyToComputeShape()) {
entityMapIter = _trackedEntities.erase(entityMapIter);
if (entityMapIter == _trackedEntities.end()) {
break;
}
}
}
return _trackedEntities.empty();
}
float SafeLanding::ElevatedPriority(const EntityItem& entityItem) {
return entityItem.getCollisionless() ? 0.0f : 10.0f;
}
void SafeLanding::debugDumpSequenceIDs() const {
int p = -1;
qCDebug(interfaceapp) << "Sequence set size:" << _sequenceNumbers.size();
for (auto s: _sequenceNumbers) {
if (p == -1) {
p = s;
qCDebug(interfaceapp) << "First:" << s;
} else {
if (s != p + 1) {
qCDebug(interfaceapp) << "Gap from" << p << "to" << s << "(exclusive)";
p = s;
}
}
}
if (p != -1) {
qCDebug(interfaceapp) << "Last:" << p;
}
}

View file

@ -0,0 +1,65 @@
//
// SafeLanding.h
// interface/src/octree
//
// Created by Simon Walton.
// 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
//
// Controller for logic to wait for local collision bodies before enabling physics.
#ifndef hifi_SafeLanding_h
#define hifi_SafeLanding_h
#include <QtCore/QObject>
#include <QtCore/QSharedPointer>
#include "EntityItem.h"
class EntityTreeRenderer;
class EntityItemID;
class SafeLanding : public QObject {
public:
void startEntitySequence(QSharedPointer<EntityTreeRenderer> entityTreeRenderer);
void stopEntitySequence();
void setCompletionSequenceNumbers(int first, int last);
void noteReceivedsequenceNumber(int sequenceNumber);
bool isLoadSequenceComplete();
private slots:
void addTrackedEntity(const EntityItemID& entityID);
void deleteTrackedEntity(const EntityItemID& entityID);
private:
bool isSequenceNumbersComplete();
void debugDumpSequenceIDs() const;
bool isEntityPhysicsComplete();
std::mutex _lock;
using Locker = std::lock_guard<std::mutex>;
bool _trackingEntities { false };
EntityTreePointer _entityTree;
using EntityMap = std::map<EntityItemID, EntityItemPointer>;
EntityMap _trackedEntities;
static constexpr int INVALID_SEQUENCE = -1;
int _initialStart { INVALID_SEQUENCE };
int _initialEnd { INVALID_SEQUENCE };
struct SequenceLessThan {
bool operator()(const int& a, const int& b) const;
};
std::set<int, SequenceLessThan> _sequenceNumbers;
static float ElevatedPriority(const EntityItem& entityItem);
static float StandardPriority(const EntityItem&) { return 0.0f; }
static const int SEQUENCE_MODULO;
};
#endif // hifi_SafeLanding_h

View file

@ -12,9 +12,33 @@
#include <glm/gtx/transform.hpp>
#include "PhysicsCollisionGroups.h"
#include "ScriptEngineLogging.h"
#include "UUIDHasher.h"
PickResultPointer CollisionPickResult::compareAndProcessNewResult(const PickResultPointer& newRes) {
const std::shared_ptr<CollisionPickResult> newCollisionResult = std::static_pointer_cast<CollisionPickResult>(newRes);
if (entityIntersections.size()) {
entityIntersections.insert(entityIntersections.cend(), newCollisionResult->entityIntersections.begin(), newCollisionResult->entityIntersections.end());
} else {
entityIntersections = newCollisionResult->entityIntersections;
}
if (avatarIntersections.size()) {
avatarIntersections.insert(avatarIntersections.cend(), newCollisionResult->avatarIntersections.begin(), newCollisionResult->avatarIntersections.end());
} else {
avatarIntersections = newCollisionResult->avatarIntersections;
}
intersects = entityIntersections.size() || avatarIntersections.size();
if (newCollisionResult->loadState == LOAD_STATE_NOT_LOADED || loadState == LOAD_STATE_UNKNOWN) {
loadState = (LoadState)newCollisionResult->loadState;
}
return std::make_shared<CollisionPickResult>(*this);
}
void buildObjectIntersectionsMap(IntersectionType intersectionType, const std::vector<ContactTestResult>& objectIntersections, std::unordered_map<QUuid, QVariantMap>& intersections, std::unordered_map<QUuid, QVariantList>& collisionPointPairs) {
for (auto& objectIntersection : objectIntersections) {
auto at = intersections.find(objectIntersection.foundID);
@ -308,20 +332,27 @@ CollisionRegion CollisionPick::getMathematicalPick() const {
return _mathPick;
}
const std::vector<ContactTestResult> CollisionPick::filterIntersections(const std::vector<ContactTestResult>& intersections) const {
std::vector<ContactTestResult> filteredIntersections;
void CollisionPick::filterIntersections(std::vector<ContactTestResult>& intersections) const {
const QVector<QUuid>& ignoreItems = getIgnoreItems();
const QVector<QUuid>& includeItems = getIncludeItems();
bool isWhitelist = includeItems.size();
for (const auto& intersection : intersections) {
bool isWhitelist = !includeItems.empty();
if (!isWhitelist && ignoreItems.empty()) {
return;
}
std::vector<ContactTestResult> filteredIntersections;
int n = (int)intersections.size();
for (int i = 0; i < n; i++) {
auto& intersection = intersections[i];
const QUuid& id = intersection.foundID;
if (!ignoreItems.contains(id) && (!isWhitelist || includeItems.contains(id))) {
filteredIntersections.push_back(intersection);
}
}
return filteredIntersections;
intersections = filteredIntersections;
}
PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pick) {
@ -330,7 +361,8 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
}
const auto& entityIntersections = filterIntersections(_physicsEngine->getCollidingInRegion(MOTIONSTATE_TYPE_ENTITY, *pick.shapeInfo, pick.transform));
auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform);
filterIntersections(entityIntersections);
return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_LOADED, entityIntersections, std::vector<ContactTestResult>());
}
@ -343,8 +375,9 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi
// Cannot compute result
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
}
const auto& avatarIntersections = filterIntersections(_physicsEngine->getCollidingInRegion(MOTIONSTATE_TYPE_AVATAR, *pick.shapeInfo, pick.transform));
auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform);
filterIntersections(avatarIntersections);
return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_LOADED, std::vector<ContactTestResult>(), avatarIntersections);
}

View file

@ -49,23 +49,7 @@ public:
bool doesIntersect() const override { return intersects; }
bool checkOrFilterAgainstMaxDistance(float maxDistance) override { return true; }
PickResultPointer compareAndProcessNewResult(const PickResultPointer& newRes) override {
const std::shared_ptr<CollisionPickResult> newCollisionResult = std::static_pointer_cast<CollisionPickResult>(newRes);
for (ContactTestResult& entityIntersection : newCollisionResult->entityIntersections) {
entityIntersections.push_back(entityIntersection);
}
for (ContactTestResult& avatarIntersection : newCollisionResult->avatarIntersections) {
avatarIntersections.push_back(avatarIntersection);
}
intersects = entityIntersections.size() || avatarIntersections.size();
if (newCollisionResult->loadState == LOAD_STATE_NOT_LOADED || loadState == LOAD_STATE_UNKNOWN) {
loadState = (LoadState)newCollisionResult->loadState;
}
return std::make_shared<CollisionPickResult>(*this);
}
PickResultPointer compareAndProcessNewResult(const PickResultPointer& newRes) override;
};
class CollisionPick : public Pick<CollisionRegion> {
@ -92,7 +76,7 @@ protected:
// Returns true if pick.shapeInfo is valid. Otherwise, attempts to get the shapeInfo ready for use.
bool isShapeInfoReady();
void computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource);
const std::vector<ContactTestResult> filterIntersections(const std::vector<ContactTestResult>& intersections) const;
void filterIntersections(std::vector<ContactTestResult>& intersections) const;
CollisionRegion _mathPick;
PhysicsEnginePointer _physicsEngine;

View file

@ -642,6 +642,14 @@ bool EntityTreeRenderer::applyLayeredZones() {
}
void EntityTreeRenderer::processEraseMessage(ReceivedMessage& message, const SharedNodePointer& sourceNode) {
OCTREE_PACKET_FLAGS flags;
message.readPrimitive(&flags);
OCTREE_PACKET_SEQUENCE sequence;
message.readPrimitive(&sequence);
_lastOctreeMessageSequence = sequence;
message.seek(0);
std::static_pointer_cast<EntityTree>(_tree)->processEraseMessage(message, sourceNode);
}

View file

@ -212,6 +212,8 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader::
glprogram = ::gl::buildProgram(shaderGLObjects);
if (!::gl::linkProgram(glprogram, compilationLogs[version].message)) {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str();
compilationLogs[version].compiled = false;
glDeleteProgram(glprogram);
glprogram = 0;
return nullptr;
@ -254,7 +256,7 @@ GLint GLBackend::getRealUniformLocation(GLint location) const {
// uniforms. If someone is requesting a uniform that isn't in the remapping structure
// that's a bug from the calling code, because it means that location wasn't in the
// reflection
qWarning() << "Unexpected location requested for shader";
qWarning() << "Unexpected location requested for shader: #" << location;
return INVALID_UNIFORM_INDEX;
}
return itr->second;

View file

@ -28,24 +28,6 @@
#include "PhysicsLogging.h"
static bool flipNormalsMyAvatarVsBackfacingTriangles( btManifoldPoint& cp,
const btCollisionObjectWrapper* colObj0Wrap, int partId0, int index0,
const btCollisionObjectWrapper* colObj1Wrap, int partId1, int index1) {
if (colObj1Wrap->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE) {
auto triShape = static_cast<const btTriangleShape*>(colObj1Wrap->getCollisionShape());
const btVector3* v = triShape->m_vertices1;
btVector3 faceNormal = colObj1Wrap->getWorldTransform().getBasis() * btCross(v[1] - v[0], v[2] - v[0]);
float nDotF = btDot(faceNormal, cp.m_normalWorldOnB);
if (nDotF <= 0.0f) {
faceNormal.normalize();
// flip the contact normal to be aligned with the face normal
cp.m_normalWorldOnB += -2.0f * nDotF * faceNormal;
}
}
// return value is currently ignored but to be future-proof: return false when not modifying friction
return false;
}
PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
_originOffset(offset),
_myAvatarController(nullptr) {
@ -88,9 +70,6 @@ void PhysicsEngine::init() {
// in order for its broadphase collision queries to work correctly. Look at how we use
// _activeStaticBodies to track and update the Aabb's of moved static objects.
_dynamicsWorld->setForceUpdateAllAabbs(false);
// register contact filter to help MyAvatar pass through backfacing triangles
gContactAddedCallback = flipNormalsMyAvatarVsBackfacingTriangles;
}
}
@ -864,9 +843,8 @@ void PhysicsEngine::setShowBulletConstraintLimits(bool value) {
}
struct AllContactsCallback : public btCollisionWorld::ContactResultCallback {
AllContactsCallback(MotionStateType desiredObjectType, const ShapeInfo& shapeInfo, const Transform& transform, btCollisionObject* myAvatarCollisionObject) :
AllContactsCallback(int32_t mask, int32_t group, const ShapeInfo& shapeInfo, const Transform& transform, btCollisionObject* myAvatarCollisionObject) :
btCollisionWorld::ContactResultCallback(),
desiredObjectType(desiredObjectType),
collisionObject(),
contacts(),
myAvatarCollisionObject(myAvatarCollisionObject) {
@ -879,21 +857,19 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback {
bulletTransform.setRotation(glmToBullet(transform.getRotation()));
collisionObject.setWorldTransform(bulletTransform);
m_collisionFilterMask = mask;
m_collisionFilterGroup = group;
}
~AllContactsCallback() {
ObjectMotionState::getShapeManager()->releaseShape(collisionObject.getCollisionShape());
}
MotionStateType desiredObjectType;
btCollisionObject collisionObject;
std::vector<ContactTestResult> contacts;
btCollisionObject* myAvatarCollisionObject;
bool needsCollision(btBroadphaseProxy* proxy) const override {
return true;
}
btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0, int partId0, int index0, const btCollisionObjectWrapper* colObj1, int partId1, int index1) override {
const btCollisionObject* otherBody;
btVector3 penetrationPoint;
@ -909,7 +885,7 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback {
}
// TODO: Give MyAvatar a motion state so we don't have to do this
if (desiredObjectType == MOTIONSTATE_TYPE_AVATAR && myAvatarCollisionObject && myAvatarCollisionObject == otherBody) {
if ((m_collisionFilterMask & BULLET_COLLISION_GROUP_MY_AVATAR) && myAvatarCollisionObject && myAvatarCollisionObject == otherBody) {
contacts.emplace_back(Physics::getSessionUUID(), bulletToGLM(penetrationPoint), bulletToGLM(otherPenetrationPoint));
return 0;
}
@ -921,7 +897,7 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback {
const btMotionState* motionStateCandidate = collisionCandidate->getMotionState();
const ObjectMotionState* candidate = dynamic_cast<const ObjectMotionState*>(motionStateCandidate);
if (!candidate || candidate->getType() != desiredObjectType) {
if (!candidate) {
return 0;
}
@ -937,14 +913,14 @@ protected:
}
};
const std::vector<ContactTestResult> PhysicsEngine::getCollidingInRegion(MotionStateType desiredObjectType, const ShapeInfo& regionShapeInfo, const Transform& regionTransform) const {
std::vector<ContactTestResult> PhysicsEngine::contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group) const {
// TODO: Give MyAvatar a motion state so we don't have to do this
btCollisionObject* myAvatarCollisionObject = nullptr;
if (desiredObjectType == MOTIONSTATE_TYPE_AVATAR && _myAvatarController) {
if ((mask & USER_COLLISION_GROUP_MY_AVATAR) && _myAvatarController) {
myAvatarCollisionObject = _myAvatarController->getCollisionObject();
}
auto contactCallback = AllContactsCallback(desiredObjectType, regionShapeInfo, regionTransform, myAvatarCollisionObject);
auto contactCallback = AllContactsCallback((int32_t)mask, (int32_t)group, regionShapeInfo, regionTransform, myAvatarCollisionObject);
_dynamicsWorld->contactTest(&contactCallback.collisionObject, contactCallback);
return contactCallback.contacts;

View file

@ -125,8 +125,9 @@ public:
void setShowBulletConstraints(bool value);
void setShowBulletConstraintLimits(bool value);
// Function for getting colliding ObjectMotionStates in the world of specified type
const std::vector<ContactTestResult> getCollidingInRegion(MotionStateType desiredObjectType, const ShapeInfo& regionShapeInfo, const Transform& regionTransform) const;
// Function for getting colliding objects in the world of specified type
// See PhysicsCollisionGroups.h for mask flags.
std::vector<ContactTestResult> contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC) const;
private:
QList<EntityDynamicPointer> removeDynamicsForBody(btRigidBody* body);

View file

@ -496,10 +496,6 @@ void RenderDeferredSetup::run(const render::RenderContextPointer& renderContext,
batch.setPipeline(program);
}
// Adjust the texcoordTransform in the case we are rendeirng a sub region(mini mirror)
auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), args->_viewport);
batch._glUniform4fv(ru::Uniform::TexcoordTransform, 1, reinterpret_cast< const float* >(&textureFrameTransform));
// Setup the global lighting
deferredLightingEffect->setupKeyLightBatch(args, batch);
@ -560,23 +556,18 @@ void RenderDeferredLocals::run(const render::RenderContextPointer& renderContext
batch.setViewportTransform(viewport);
batch.setStateScissorRect(viewport);
auto textureFrameTransform = gpu::Framebuffer::evalSubregionTexcoordTransformCoefficients(deferredFramebuffer->getFrameSize(), viewport);
auto& lightIndices = lightClusters->_visibleLightIndices;
if (!lightIndices.empty() && lightIndices[0] > 0) {
deferredLightingEffect->setupLocalLightsBatch(batch, lightClusters);
// Local light pipeline
batch.setPipeline(deferredLightingEffect->_localLight);
batch._glUniform4fv(ru::Uniform::TexcoordTransform, 1, reinterpret_cast<const float*>(&textureFrameTransform));
batch.draw(gpu::TRIANGLE_STRIP, 4);
// Draw outline as well ?
if (lightingModel->isShowLightContourEnabled()) {
batch.setPipeline(deferredLightingEffect->_localLightOutline);
batch._glUniform4fv(ru::Uniform::TexcoordTransform, 1, reinterpret_cast<const float*>(&textureFrameTransform));
batch.draw(gpu::TRIANGLE_STRIP, 4);
}

View file

@ -282,6 +282,7 @@ void Model::reset() {
const FBXGeometry& geometry = getFBXGeometry();
_rig.reset(geometry);
emit rigReset();
emit rigReady();
}
}

View file

@ -16,8 +16,6 @@
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
layout(location=RENDER_UTILS_UNIFORM_LIGHT_TEXCOORD_TRANSFORM) uniform vec4 texcoordFrameTransform;
void main(void) {
const float depth = 1.0;
const vec4 UNIT_QUAD[4] = vec4[4](
@ -30,8 +28,5 @@ void main(void) {
_texCoord01.xy = (pos.xy + 1.0) * 0.5;
_texCoord01.xy *= texcoordFrameTransform.zw;
_texCoord01.xy += texcoordFrameTransform.xy;
gl_Position = pos;
}

View file

@ -104,6 +104,7 @@ const uint16_t ENTITY_COLLISION_MASK_DEFAULT =
USER_COLLISION_GROUP_OTHER_AVATAR;
const uint16_t USER_COLLISION_MASK_AVATARS = USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR;
const uint16_t USER_COLLISION_MASK_ENTITIES = USER_COLLISION_GROUP_STATIC | USER_COLLISION_GROUP_DYNAMIC | USER_COLLISION_GROUP_KINEMATIC;
const int32_t NUM_USER_COLLISION_GROUPS = 5;

View file

@ -110,7 +110,7 @@ Script.include("/~/system/libraries/controllers.js");
SEAT: 'seat' // The current target is a seat
};
var speed = 12.0;
var speed = 9.3;
var accelerationAxis = {x: 0.0, y: -5.0, z: 0.0};
function Teleporter(hand) {