mirror of
https://github.com/overte-org/overte.git
synced 2025-04-10 17:22:25 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into punk
This commit is contained in:
commit
0f6f465e7f
16 changed files with 328 additions and 107 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
172
interface/src/octree/SafeLanding.cpp
Normal file
172
interface/src/octree/SafeLanding.cpp
Normal 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;
|
||||
}
|
||||
}
|
65
interface/src/octree/SafeLanding.h
Normal file
65
interface/src/octree/SafeLanding.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -282,6 +282,7 @@ void Model::reset() {
|
|||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
_rig.reset(geometry);
|
||||
emit rigReset();
|
||||
emit rigReady();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue