merge with master

This commit is contained in:
SamGondelman 2018-08-27 15:45:17 -07:00
commit 0c8a4cc81e
62 changed files with 1450 additions and 614 deletions

View file

@ -463,19 +463,15 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
limitedNodeList->eachNodeBreakable([nodeConnection, username, &existingNodeID](const SharedNodePointer& node){ limitedNodeList->eachNodeBreakable([nodeConnection, username, &existingNodeID](const SharedNodePointer& node){
if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) { if (node->getPublicSocket() == nodeConnection.publicSockAddr && node->getLocalSocket() == nodeConnection.localSockAddr) {
// we have a node that already has these exact sockets - this can occur if a node // we have a node that already has these exact sockets
// is failing to connect to the domain // this can occur if a node is failing to connect to the domain
// we'll re-use the existing node ID // remove the old node before adding the new node
// as long as the user hasn't changed their username (by logging in or logging out)
auto existingNodeData = static_cast<DomainServerNodeData*>(node->getLinkedData());
if (existingNodeData->getUsername() == username) {
qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID(); qDebug() << "Deleting existing connection from same sockaddr: " << node->getUUID();
existingNodeID = node->getUUID(); existingNodeID = node->getUUID();
return false; return false;
} }
}
return true; return true;
}); });

View file

@ -60,6 +60,9 @@ Item {
StatText { StatText {
text: "Game Rate: " + root.gameLoopRate text: "Game Rate: " + root.gameLoopRate
} }
StatText {
text: "Physics Object Count: " + root.physicsObjectCount
}
StatText { StatText {
visible: root.expanded visible: root.expanded
text: root.gameUpdateStats text: root.gameUpdateStats

View file

@ -1095,6 +1095,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
// Set File Logger Session UUID // Set File Logger Session UUID
auto avatarManager = DependencyManager::get<AvatarManager>(); auto avatarManager = DependencyManager::get<AvatarManager>();
auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr;
if (avatarManager) {
workload::SpacePointer space = getEntities()->getWorkloadSpace();
avatarManager->setSpace(space);
}
auto accountManager = DependencyManager::get<AccountManager>(); auto accountManager = DependencyManager::get<AccountManager>();
_logger->setSessionID(accountManager->getSessionID()); _logger->setSessionID(accountManager->getSessionID());
@ -2542,11 +2546,15 @@ void Application::cleanupBeforeQuit() {
Application::~Application() { Application::~Application() {
// remove avatars from physics engine // remove avatars from physics engine
DependencyManager::get<AvatarManager>()->clearOtherAvatars(); auto avatarManager = DependencyManager::get<AvatarManager>();
VectorOfMotionStates motionStates; avatarManager->clearOtherAvatars();
DependencyManager::get<AvatarManager>()->getObjectsToRemoveFromPhysics(motionStates);
_physicsEngine->removeObjects(motionStates); PhysicsEngine::Transaction transaction;
DependencyManager::get<AvatarManager>()->deleteAllAvatars(); avatarManager->buildPhysicsTransaction(transaction);
_physicsEngine->processTransaction(transaction);
avatarManager->handleProcessedPhysicsTransaction(transaction);
avatarManager->deleteAllAvatars();
_physicsEngine->setCharacterController(nullptr); _physicsEngine->setCharacterController(nullptr);
@ -5708,12 +5716,10 @@ void Application::update(float deltaTime) {
t1 = std::chrono::high_resolution_clock::now(); t1 = std::chrono::high_resolution_clock::now();
avatarManager->getObjectsToRemoveFromPhysics(motionStates); PhysicsEngine::Transaction transaction;
_physicsEngine->removeObjects(motionStates); avatarManager->buildPhysicsTransaction(transaction);
avatarManager->getObjectsToAddToPhysics(motionStates); _physicsEngine->processTransaction(transaction);
_physicsEngine->addObjects(motionStates); avatarManager->handleProcessedPhysicsTransaction(transaction);
avatarManager->getObjectsToChange(motionStates);
_physicsEngine->changeObjects(motionStates);
myAvatar->prepareForPhysicsSimulation(); myAvatar->prepareForPhysicsSimulation();
_physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) { _physicsEngine->forEachDynamic([&](EntityDynamicPointer dynamic) {
@ -6184,6 +6190,10 @@ bool Application::isHMDMode() const {
return getActiveDisplayPlugin()->isHmd(); return getActiveDisplayPlugin()->isHmd();
} }
float Application::getNumCollisionObjects() const {
return _physicsEngine ? _physicsEngine->getNumCollisionObjects() : 0;
}
float Application::getTargetRenderFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); } float Application::getTargetRenderFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); }
QRect Application::getDesirableApplicationGeometry() const { QRect Application::getDesirableApplicationGeometry() const {

View file

@ -207,6 +207,7 @@ public:
size_t getRenderFrameCount() const { return _renderFrameCount; } size_t getRenderFrameCount() const { return _renderFrameCount; }
float getRenderLoopRate() const { return _renderLoopCounter.rate(); } float getRenderLoopRate() const { return _renderLoopCounter.rate(); }
float getNumCollisionObjects() const;
float getTargetRenderFrameRate() const; // frames/second float getTargetRenderFrameRate() const; // frames/second
float getFieldOfView() { return _fieldOfView.get(); } float getFieldOfView() { return _fieldOfView.get(); }

View file

@ -452,6 +452,9 @@ Menu::Menu() {
}); });
} }
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ComputeBlendshapes, 0, true,
DependencyManager::get<ModelBlender>().data(), SLOT(setComputeBlendshapes(bool)));
// Developer > Assets >>> // Developer > Assets >>>
// Menu item is not currently needed but code should be kept in case it proves useful again at some stage. // Menu item is not currently needed but code should be kept in case it proves useful again at some stage.
//#define WANT_ASSET_MIGRATION //#define WANT_ASSET_MIGRATION

View file

@ -222,6 +222,7 @@ namespace MenuOption {
const QString NotificationSoundsSnapshot = "play_notification_sounds_snapshot"; const QString NotificationSoundsSnapshot = "play_notification_sounds_snapshot";
const QString NotificationSoundsTablet = "play_notification_sounds_tablet"; const QString NotificationSoundsTablet = "play_notification_sounds_tablet";
const QString ForceCoarsePicking = "Force Coarse Picking"; const QString ForceCoarsePicking = "Force Coarse Picking";
const QString ComputeBlendshapes = "Compute Blendshapes";
} }
#endif // hifi_Menu_h #endif // hifi_Menu_h

View file

@ -44,7 +44,6 @@
#include "InterfaceLogging.h" #include "InterfaceLogging.h"
#include "Menu.h" #include "Menu.h"
#include "MyAvatar.h" #include "MyAvatar.h"
#include "OtherAvatar.h"
#include "SceneScriptingInterface.h" #include "SceneScriptingInterface.h"
// 50 times per second - target is 45hz, but this helps account for any small deviations // 50 times per second - target is 45hz, but this helps account for any small deviations
@ -81,8 +80,25 @@ AvatarManager::AvatarManager(QObject* parent) :
}); });
} }
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
AvatarSharedPointer avatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer);
const auto otherAvatar = std::static_pointer_cast<OtherAvatar>(avatar);
if (otherAvatar && _space) {
std::unique_lock<std::mutex> lock(_spaceLock);
auto spaceIndex = _space->allocateID();
otherAvatar->setSpaceIndex(spaceIndex);
workload::Sphere sphere(otherAvatar->getWorldPosition(), otherAvatar->getBoundingRadius());
workload::Transaction transaction;
SpatiallyNestablePointer nestable = std::static_pointer_cast<SpatiallyNestable>(otherAvatar);
transaction.reset(spaceIndex, sphere, workload::Owner(nestable));
_space->enqueueTransaction(transaction);
}
return avatar;
}
AvatarManager::~AvatarManager() { AvatarManager::~AvatarManager() {
assert(_motionStates.empty()); assert(_avatarsToChangeInPhysics.empty());
} }
void AvatarManager::init() { void AvatarManager::init() {
@ -104,6 +120,11 @@ void AvatarManager::init() {
} }
} }
void AvatarManager::setSpace(workload::SpacePointer& space ) {
assert(!_space);
_space = space;
}
void AvatarManager::updateMyAvatar(float deltaTime) { void AvatarManager::updateMyAvatar(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()"); PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
@ -192,20 +213,20 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
uint64_t updateExpiry = startTime + UPDATE_BUDGET; uint64_t updateExpiry = startTime + UPDATE_BUDGET;
int numAvatarsUpdated = 0; int numAvatarsUpdated = 0;
int numAVatarsNotUpdated = 0; int numAVatarsNotUpdated = 0;
bool physicsEnabled = qApp->isPhysicsEnabled();
render::Transaction transaction; render::Transaction renderTransaction;
workload::Transaction workloadTransaction;
while (!sortedAvatars.empty()) { while (!sortedAvatars.empty()) {
const SortableAvatar& sortData = sortedAvatars.top(); const SortableAvatar& sortData = sortedAvatars.top();
const auto avatar = std::static_pointer_cast<Avatar>(sortData.getAvatar()); const auto avatar = std::static_pointer_cast<OtherAvatar>(sortData.getAvatar());
const auto otherAvatar = std::static_pointer_cast<OtherAvatar>(sortData.getAvatar());
// TODO: to help us scale to more avatars it would be nice to not have to poll orb state here
// if the geometry is loaded then turn off the orb // if the geometry is loaded then turn off the orb
if (avatar->getSkeletonModel()->isLoaded()) { if (avatar->getSkeletonModel()->isLoaded()) {
// remove the orb if it is there // remove the orb if it is there
otherAvatar->removeOrb(); avatar->removeOrb();
} else { } else {
otherAvatar->updateOrbPosition(); avatar->updateOrbPosition();
} }
bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID()); bool ignoring = DependencyManager::get<NodeList>()->isPersonalMutingNode(avatar->getID());
@ -218,18 +239,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
if (_shouldRender) { if (_shouldRender) {
avatar->ensureInScene(avatar, qApp->getMain3DScene()); avatar->ensureInScene(avatar, qApp->getMain3DScene());
} }
if (physicsEnabled && !avatar->isInPhysicsSimulation()) {
ShapeInfo shapeInfo;
avatar->computeShapeInfo(shapeInfo);
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
if (shape) {
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
motionState->setMass(avatar->computeMass());
avatar->setPhysicsCallback([=] (uint32_t flags) { motionState->addDirtyFlags(flags); });
_motionStates.insert(avatar.get(), motionState);
_motionStatesToAddToPhysics.insert(motionState);
}
}
avatar->animateScaleChanges(deltaTime); avatar->animateScaleChanges(deltaTime);
const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY; const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY;
@ -241,15 +250,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
numAvatarsUpdated++; numAvatarsUpdated++;
} }
avatar->simulate(deltaTime, inView); avatar->simulate(deltaTime, inView);
avatar->updateRenderItem(transaction); avatar->updateRenderItem(renderTransaction);
avatar->updateSpaceProxy(workloadTransaction);
avatar->setLastRenderUpdateTime(startTime); avatar->setLastRenderUpdateTime(startTime);
} else { } else {
// we've spent our full time budget --> bail on the rest of the avatar updates // we've spent our full time budget --> bail on the rest of the avatar updates
// --> more avatars may freeze until their priority trickles up // --> more avatars may freeze until their priority trickles up
// --> some scale or fade animations may glitch // --> some scale animations may glitch
// --> some avatar velocity measurements may be a little off // --> some avatar velocity measurements may be a little off
// no time simulate, but we take the time to count how many were tragically missed // no time to simulate, but we take the time to count how many were tragically missed
bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD; bool inView = sortData.getPriority() > OUT_OF_VIEW_THRESHOLD;
if (!inView) { if (!inView) {
break; break;
@ -273,8 +283,16 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
} }
if (_shouldRender) { if (_shouldRender) {
qApp->getMain3DScene()->enqueueTransaction(transaction); qApp->getMain3DScene()->enqueueTransaction(renderTransaction);
} }
if (!_spaceProxiesToDelete.empty() && _space) {
std::unique_lock<std::mutex> lock(_spaceLock);
workloadTransaction.remove(_spaceProxiesToDelete);
_spaceProxiesToDelete.clear();
}
_space->enqueueTransaction(workloadTransaction);
_numAvatarsUpdated = numAvatarsUpdated; _numAvatarsUpdated = numAvatarsUpdated;
_numAvatarsNotUpdated = numAVatarsNotUpdated; _numAvatarsNotUpdated = numAVatarsNotUpdated;
@ -341,41 +359,86 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
QReadLocker locker(&_hashLock); QReadLocker locker(&_hashLock);
QVector<AvatarSharedPointer>::iterator avatarItr = _avatarsToFade.begin(); QVector<AvatarSharedPointer>::iterator avatarItr = _avatarsToFade.begin();
const render::ScenePointer& scene = qApp->getMain3DScene(); const render::ScenePointer& scene = qApp->getMain3DScene();
render::Transaction transaction;
while (avatarItr != _avatarsToFade.end()) { while (avatarItr != _avatarsToFade.end()) {
auto avatar = std::static_pointer_cast<Avatar>(*avatarItr); auto avatar = std::static_pointer_cast<Avatar>(*avatarItr);
avatar->updateFadingStatus(scene); avatar->updateFadingStatus(scene);
if (!avatar->isFading()) { if (!avatar->isFading()) {
// fading to zero is such a rare event we push a unique transaction for each // fading to zero is such a rare event we push a unique transaction for each
if (avatar->isInScene()) { if (avatar->isInScene()) {
render::Transaction transaction;
avatar->removeFromScene(*avatarItr, scene, transaction); avatar->removeFromScene(*avatarItr, scene, transaction);
scene->enqueueTransaction(transaction);
} }
avatarItr = _avatarsToFade.erase(avatarItr); avatarItr = _avatarsToFade.erase(avatarItr);
} else { } else {
++avatarItr; ++avatarItr;
} }
} }
scene->enqueueTransaction(transaction);
} }
AvatarSharedPointer AvatarManager::newSharedAvatar() { AvatarSharedPointer AvatarManager::newSharedAvatar() {
return AvatarSharedPointer(new OtherAvatar(qApp->thread()), [](OtherAvatar* ptr) { ptr->deleteLater(); }); return AvatarSharedPointer(new OtherAvatar(qApp->thread()), [](OtherAvatar* ptr) { ptr->deleteLater(); });
} }
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { void AvatarManager::queuePhysicsChange(const OtherAvatarPointer& avatar) {
AvatarHashMap::handleRemovedAvatar(removedAvatar, removalReason); _avatarsToChangeInPhysics.insert(avatar);
// remove from physics
auto avatar = std::static_pointer_cast<Avatar>(removedAvatar);
avatar->setPhysicsCallback(nullptr);
AvatarMotionStateMap::iterator itr = _motionStates.find(avatar.get());
if (itr != _motionStates.end()) {
AvatarMotionState* motionState = *itr;
_motionStatesToAddToPhysics.remove(motionState);
_motionStatesToRemoveFromPhysics.push_back(motionState);
_motionStates.erase(itr);
} }
void AvatarManager::buildPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
SetOfOtherAvatars failedShapeBuilds;
for (auto avatar : _avatarsToChangeInPhysics) {
bool isInPhysics = avatar->isInPhysicsSimulation();
if (isInPhysics != avatar->shouldBeInPhysicsSimulation()) {
if (isInPhysics) {
transaction.objectsToRemove.push_back(avatar->_motionState);
avatar->_motionState = nullptr;
} else {
ShapeInfo shapeInfo;
avatar->computeShapeInfo(shapeInfo);
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
if (shape) {
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
motionState->setMass(avatar->computeMass());
avatar->_motionState = motionState;
transaction.objectsToAdd.push_back(motionState);
} else {
failedShapeBuilds.insert(avatar);
}
}
} else if (isInPhysics) {
transaction.objectsToChange.push_back(avatar->_motionState);
}
}
_avatarsToChangeInPhysics.swap(failedShapeBuilds);
}
void AvatarManager::handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction) {
// things on objectsToChange correspond to failed changes
// so we push them back onto _avatarsToChangeInPhysics
for (auto object : transaction.objectsToChange) {
AvatarMotionState* motionState = static_cast<AvatarMotionState*>(object);
assert(motionState);
assert(motionState->_avatar);
_avatarsToChangeInPhysics.insert(motionState->_avatar);
}
// things on objectsToRemove are ready for delete
for (auto object : transaction.objectsToRemove) {
delete object;
}
transaction.clear();
}
void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) {
auto avatar = std::static_pointer_cast<OtherAvatar>(removedAvatar);
{
std::unique_lock<std::mutex> lock(_spaceLock);
_spaceProxiesToDelete.push_back(avatar->getSpaceIndex());
}
AvatarHashMap::handleRemovedAvatar(avatar, removalReason);
avatar->die();
queuePhysicsChange(avatar);
if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) { if (removalReason == KillAvatarReason::TheirAvatarEnteredYourBubble) {
emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius(); emit DependencyManager::get<UsersScriptingInterface>()->enteredIgnoreRadius();
} else if (removalReason == KillAvatarReason::AvatarDisconnected) { } else if (removalReason == KillAvatarReason::AvatarDisconnected) {
@ -410,48 +473,15 @@ void AvatarManager::clearOtherAvatars() {
} }
void AvatarManager::deleteAllAvatars() { void AvatarManager::deleteAllAvatars() {
assert(_motionStates.empty()); // should have called clearOtherAvatars() before getting here assert(_avatarsToChangeInPhysics.empty());
deleteMotionStates();
QReadLocker locker(&_hashLock); QReadLocker locker(&_hashLock);
AvatarHash::iterator avatarIterator = _avatarHash.begin(); AvatarHash::iterator avatarIterator = _avatarHash.begin();
while (avatarIterator != _avatarHash.end()) { while (avatarIterator != _avatarHash.end()) {
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value()); auto avatar = std::static_pointer_cast<OtherAvatar>(avatarIterator.value());
avatarIterator = _avatarHash.erase(avatarIterator); avatarIterator = _avatarHash.erase(avatarIterator);
avatar->die(); avatar->die();
} assert(!avatar->_motionState);
}
void AvatarManager::deleteMotionStates() {
// delete motionstates that were removed from physics last frame
for (auto state : _motionStatesToDelete) {
delete state;
}
_motionStatesToDelete.clear();
}
void AvatarManager::getObjectsToRemoveFromPhysics(VectorOfMotionStates& result) {
deleteMotionStates();
result = _motionStatesToRemoveFromPhysics;
_motionStatesToDelete.swap(_motionStatesToRemoveFromPhysics);
}
void AvatarManager::getObjectsToAddToPhysics(VectorOfMotionStates& result) {
result.clear();
for (auto motionState : _motionStatesToAddToPhysics) {
result.push_back(motionState);
}
_motionStatesToAddToPhysics.clear();
}
void AvatarManager::getObjectsToChange(VectorOfMotionStates& result) {
result.clear();
AvatarMotionStateMap::iterator motionStateItr = _motionStates.begin();
while (motionStateItr != _motionStates.end()) {
if ((*motionStateItr)->getIncomingDirtyFlags() != 0) {
result.push_back(*motionStateItr);
}
++motionStateItr;
} }
} }
@ -598,7 +628,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
} }
if (sortedAvatars.size() > 1) { if (sortedAvatars.size() > 1) {
static auto comparator = [](const SortedAvatar& left, const SortedAvatar& right) { return left.first > right.first; }; static auto comparator = [](const SortedAvatar& left, const SortedAvatar& right) { return left.first < right.first; };
std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator); std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator);
} }
@ -691,7 +721,7 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector
} }
if (sortedAvatars.size() > 1) { if (sortedAvatars.size() > 1) {
static auto comparator = [](const SortedAvatar& left, const SortedAvatar& right) { return left.first > right.first; }; static auto comparator = [](const SortedAvatar& left, const SortedAvatar& right) { return left.first < right.first; };
std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator); std::sort(sortedAvatars.begin(), sortedAvatars.end(), comparator);
} }

View file

@ -12,6 +12,8 @@
#ifndef hifi_AvatarManager_h #ifndef hifi_AvatarManager_h
#define hifi_AvatarManager_h #define hifi_AvatarManager_h
#include <set>
#include <QtCore/QHash> #include <QtCore/QHash>
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QSharedPointer> #include <QtCore/QSharedPointer>
@ -23,9 +25,11 @@
#include <shared/RateCounter.h> #include <shared/RateCounter.h>
#include <avatars-renderer/ScriptAvatar.h> #include <avatars-renderer/ScriptAvatar.h>
#include <AudioInjector.h> #include <AudioInjector.h>
#include <workload/Space.h>
#include "AvatarMotionState.h" #include "AvatarMotionState.h"
#include "MyAvatar.h" #include "MyAvatar.h"
#include "OtherAvatar.h"
using SortedAvatar = std::pair<float, std::shared_ptr<Avatar>>; using SortedAvatar = std::pair<float, std::shared_ptr<Avatar>>;
@ -64,6 +68,7 @@ public:
virtual ~AvatarManager(); virtual ~AvatarManager();
void init(); void init();
void setSpace(workload::SpacePointer& space );
std::shared_ptr<MyAvatar> getMyAvatar() { return _myAvatar; } std::shared_ptr<MyAvatar> getMyAvatar() { return _myAvatar; }
glm::vec3 getMyAvatarPosition() const { return _myAvatar->getWorldPosition(); } glm::vec3 getMyAvatarPosition() const { return _myAvatar->getWorldPosition(); }
@ -94,6 +99,7 @@ public:
void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates); void getObjectsToRemoveFromPhysics(VectorOfMotionStates& motionStates);
void getObjectsToAddToPhysics(VectorOfMotionStates& motionStates); void getObjectsToAddToPhysics(VectorOfMotionStates& motionStates);
void getObjectsToChange(VectorOfMotionStates& motionStates); void getObjectsToChange(VectorOfMotionStates& motionStates);
void handleChangedMotionStates(const VectorOfMotionStates& motionStates); void handleChangedMotionStates(const VectorOfMotionStates& motionStates);
void handleCollisionEvents(const CollisionEvents& collisionEvents); void handleCollisionEvents(const CollisionEvents& collisionEvents);
@ -111,7 +117,6 @@ public:
* @param {string} [rateName=""] * @param {string} [rateName=""]
* @returns {number} * @returns {number}
*/ */
Q_INVOKABLE float getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName = QString("")) const; Q_INVOKABLE float getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName = QString("")) const;
/**jsdoc /**jsdoc
@ -120,7 +125,6 @@ public:
* @param {string} [rateName=""] * @param {string} [rateName=""]
* @returns {number} * @returns {number}
*/ */
Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")) const; Q_INVOKABLE float getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName = QString("")) const;
/**jsdoc /**jsdoc
@ -177,14 +181,20 @@ public:
float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); } float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); }
int getIdentityRequestsSent() const { return _identityRequestsSent; } int getIdentityRequestsSent() const { return _identityRequestsSent; }
public slots: void queuePhysicsChange(const OtherAvatarPointer& avatar);
void buildPhysicsTransaction(PhysicsEngine::Transaction& transaction);
void handleProcessedPhysicsTransaction(PhysicsEngine::Transaction& transaction);
public slots:
/**jsdoc /**jsdoc
* @function AvatarManager.updateAvatarRenderStatus * @function AvatarManager.updateAvatarRenderStatus
* @param {boolean} shouldRenderAvatars * @param {boolean} shouldRenderAvatars
*/ */
void updateAvatarRenderStatus(bool shouldRenderAvatars); void updateAvatarRenderStatus(bool shouldRenderAvatars);
protected:
AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) override;
private: private:
explicit AvatarManager(QObject* parent = 0); explicit AvatarManager(QObject* parent = 0);
explicit AvatarManager(const AvatarManager& other); explicit AvatarManager(const AvatarManager& other);
@ -192,16 +202,12 @@ private:
void simulateAvatarFades(float deltaTime); void simulateAvatarFades(float deltaTime);
AvatarSharedPointer newSharedAvatar() override; AvatarSharedPointer newSharedAvatar() override;
void deleteMotionStates();
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
QVector<AvatarSharedPointer> _avatarsToFade; QVector<AvatarSharedPointer> _avatarsToFade;
using AvatarMotionStateMap = QMap<Avatar*, AvatarMotionState*>; using SetOfOtherAvatars = std::set<OtherAvatarPointer>;
AvatarMotionStateMap _motionStates; SetOfOtherAvatars _avatarsToChangeInPhysics;
VectorOfMotionStates _motionStatesToRemoveFromPhysics;
VectorOfMotionStates _motionStatesToDelete;
SetOfMotionStates _motionStatesToAddToPhysics;
std::shared_ptr<MyAvatar> _myAvatar; std::shared_ptr<MyAvatar> _myAvatar;
quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate.
@ -214,6 +220,10 @@ private:
float _avatarSimulationTime { 0.0f }; float _avatarSimulationTime { 0.0f };
bool _shouldRender { true }; bool _shouldRender { true };
mutable int _identityRequestsSent { 0 }; mutable int _identityRequestsSent { 0 };
mutable std::mutex _spaceLock;
workload::SpacePointer _space;
std::vector<int32_t> _spaceProxiesToDelete;
}; };
#endif // hifi_AvatarManager_h #endif // hifi_AvatarManager_h

View file

@ -16,7 +16,7 @@
#include <PhysicsHelpers.h> #include <PhysicsHelpers.h>
AvatarMotionState::AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) { AvatarMotionState::AvatarMotionState(OtherAvatarPointer avatar, const btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
assert(_avatar); assert(_avatar);
_type = MOTIONSTATE_TYPE_AVATAR; _type = MOTIONSTATE_TYPE_AVATAR;
cacheShapeDiameter(); cacheShapeDiameter();
@ -57,7 +57,7 @@ PhysicsMotionType AvatarMotionState::computePhysicsMotionType() const {
// virtual and protected // virtual and protected
const btCollisionShape* AvatarMotionState::computeNewShape() { const btCollisionShape* AvatarMotionState::computeNewShape() {
ShapeInfo shapeInfo; ShapeInfo shapeInfo;
std::static_pointer_cast<Avatar>(_avatar)->computeShapeInfo(shapeInfo); _avatar->computeShapeInfo(shapeInfo);
return getShapeManager()->getShape(shapeInfo); return getShapeManager()->getShape(shapeInfo);
} }
@ -151,7 +151,7 @@ glm::vec3 AvatarMotionState::getObjectAngularVelocity() const {
// virtual // virtual
glm::vec3 AvatarMotionState::getObjectGravity() const { glm::vec3 AvatarMotionState::getObjectGravity() const {
return std::static_pointer_cast<Avatar>(_avatar)->getAcceleration(); return _avatar->getAcceleration();
} }
// virtual // virtual
@ -176,7 +176,7 @@ void AvatarMotionState::computeCollisionGroupAndMask(int32_t& group, int32_t& ma
// virtual // virtual
float AvatarMotionState::getMass() const { float AvatarMotionState::getMass() const {
return std::static_pointer_cast<Avatar>(_avatar)->computeMass(); return _avatar->computeMass();
} }
void AvatarMotionState::cacheShapeDiameter() { void AvatarMotionState::cacheShapeDiameter() {

View file

@ -14,14 +14,14 @@
#include <QSet> #include <QSet>
#include <avatars-renderer/Avatar.h>
#include <ObjectMotionState.h> #include <ObjectMotionState.h>
#include <BulletUtil.h> #include <BulletUtil.h>
#include "OtherAvatar.h"
class AvatarMotionState : public ObjectMotionState { class AvatarMotionState : public ObjectMotionState {
public: public:
AvatarMotionState(AvatarSharedPointer avatar, const btCollisionShape* shape); AvatarMotionState(OtherAvatarPointer avatar, const btCollisionShape* shape);
virtual void handleEasyChanges(uint32_t& flags) override; virtual void handleEasyChanges(uint32_t& flags) override;
virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override; virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override;
@ -85,7 +85,7 @@ protected:
virtual bool isReadyToComputeShape() const override { return true; } virtual bool isReadyToComputeShape() const override { return true; }
virtual const btCollisionShape* computeNewShape() override; virtual const btCollisionShape* computeNewShape() override;
AvatarSharedPointer _avatar; OtherAvatarPointer _avatar;
float _diameter { 0.0f }; float _diameter { 0.0f };
uint32_t _dirtyFlags; uint32_t _dirtyFlags;

View file

@ -9,6 +9,8 @@
#include "OtherAvatar.h" #include "OtherAvatar.h"
#include "Application.h" #include "Application.h"
#include "AvatarMotionState.h"
OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) { OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
// give the pointer to our head to inherited _headData variable from AvatarData // give the pointer to our head to inherited _headData variable from AvatarData
_headData = new Head(this); _headData = new Head(this);
@ -58,3 +60,38 @@ void OtherAvatar::createOrb() {
_otherAvatarOrbMeshPlaceholder->setVisible(true); _otherAvatarOrbMeshPlaceholder->setVisible(true);
} }
} }
void OtherAvatar::setSpaceIndex(int32_t index) {
assert(_spaceIndex == -1);
_spaceIndex = index;
}
void OtherAvatar::updateSpaceProxy(workload::Transaction& transaction) const {
if (_spaceIndex > -1) {
float approximateBoundingRadius = glm::length(getTargetScale());
workload::Sphere sphere(getWorldPosition(), approximateBoundingRadius);
transaction.update(_spaceIndex, sphere);
}
}
int OtherAvatar::parseDataFromBuffer(const QByteArray& buffer) {
int32_t bytesRead = Avatar::parseDataFromBuffer(buffer);
if (_moving && _motionState) {
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
}
return bytesRead;
}
void OtherAvatar::setWorkloadRegion(uint8_t region) {
_workloadRegion = region;
}
bool OtherAvatar::shouldBeInPhysicsSimulation() const {
return (_workloadRegion < workload::Region::R3 && !isDead());
}
void OtherAvatar::rebuildCollisionShape() {
if (_motionState) {
_motionState->addDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
}
}

View file

@ -1,6 +1,6 @@
// //
// Created by Bradley Austin Davis on 2017/04/27 // Created by amantly 2018.06.26
// Copyright 2013-2017 High Fidelity, Inc. // Copyright 2018 High Fidelity, Inc.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -9,10 +9,17 @@
#ifndef hifi_OtherAvatar_h #ifndef hifi_OtherAvatar_h
#define hifi_OtherAvatar_h #define hifi_OtherAvatar_h
#include <memory>
#include <avatars-renderer/Avatar.h> #include <avatars-renderer/Avatar.h>
#include <workload/Space.h>
#include "InterfaceLogging.h"
#include "ui/overlays/Overlays.h" #include "ui/overlays/Overlays.h"
#include "ui/overlays/Sphere3DOverlay.h" #include "ui/overlays/Sphere3DOverlay.h"
#include "InterfaceLogging.h"
class AvatarManager;
class AvatarMotionState;
class OtherAvatar : public Avatar { class OtherAvatar : public Avatar {
public: public:
@ -24,9 +31,28 @@ public:
void updateOrbPosition(); void updateOrbPosition();
void removeOrb(); void removeOrb();
void setSpaceIndex(int32_t index);
int32_t getSpaceIndex() const { return _spaceIndex; }
void updateSpaceProxy(workload::Transaction& transaction) const;
int parseDataFromBuffer(const QByteArray& buffer) override;
bool isInPhysicsSimulation() const { return _motionState != nullptr; }
void rebuildCollisionShape() override;
void setWorkloadRegion(uint8_t region);
bool shouldBeInPhysicsSimulation() const;
friend AvatarManager;
protected: protected:
std::shared_ptr<Sphere3DOverlay> _otherAvatarOrbMeshPlaceholder { nullptr }; std::shared_ptr<Sphere3DOverlay> _otherAvatarOrbMeshPlaceholder { nullptr };
OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID }; OverlayID _otherAvatarOrbMeshPlaceholderID { UNKNOWN_OVERLAY_ID };
AvatarMotionState* _motionState { nullptr };
int32_t _spaceIndex { -1 };
uint8_t _workloadRegion { workload::Region::INVALID };
}; };
using OtherAvatarPointer = std::shared_ptr<OtherAvatar>;
#endif // hifi_OtherAvatar_h #endif // hifi_OtherAvatar_h

View file

@ -122,6 +122,7 @@ void Stats::updateStats(bool force) {
auto avatarManager = DependencyManager::get<AvatarManager>(); auto avatarManager = DependencyManager::get<AvatarManager>();
// we need to take one avatar out so we don't include ourselves // we need to take one avatar out so we don't include ourselves
STAT_UPDATE(avatarCount, avatarManager->size() - 1); STAT_UPDATE(avatarCount, avatarManager->size() - 1);
STAT_UPDATE(physicsObjectCount, qApp->getNumCollisionObjects());
STAT_UPDATE(updatedAvatarCount, avatarManager->getNumAvatarsUpdated()); STAT_UPDATE(updatedAvatarCount, avatarManager->getNumAvatarsUpdated());
STAT_UPDATE(notUpdatedAvatarCount, avatarManager->getNumAvatarsNotUpdated()); STAT_UPDATE(notUpdatedAvatarCount, avatarManager->getNumAvatarsNotUpdated());
STAT_UPDATE(serverCount, (int)nodeList->size()); STAT_UPDATE(serverCount, (int)nodeList->size());

View file

@ -48,6 +48,7 @@ private: \
* @property {number} presentdroprate - <em>Read-only.</em> * @property {number} presentdroprate - <em>Read-only.</em>
* @property {number} gameLoopRate - <em>Read-only.</em> * @property {number} gameLoopRate - <em>Read-only.</em>
* @property {number} avatarCount - <em>Read-only.</em> * @property {number} avatarCount - <em>Read-only.</em>
* @property {number} physicsObjectCount - <em>Read-only.</em>
* @property {number} updatedAvatarCount - <em>Read-only.</em> * @property {number} updatedAvatarCount - <em>Read-only.</em>
* @property {number} notUpdatedAvatarCount - <em>Read-only.</em> * @property {number} notUpdatedAvatarCount - <em>Read-only.</em>
* @property {number} packetInCount - <em>Read-only.</em> * @property {number} packetInCount - <em>Read-only.</em>
@ -203,6 +204,7 @@ class Stats : public QQuickItem {
STATS_PROPERTY(float, presentdroprate, 0) STATS_PROPERTY(float, presentdroprate, 0)
STATS_PROPERTY(int, gameLoopRate, 0) STATS_PROPERTY(int, gameLoopRate, 0)
STATS_PROPERTY(int, avatarCount, 0) STATS_PROPERTY(int, avatarCount, 0)
STATS_PROPERTY(int, physicsObjectCount, 0)
STATS_PROPERTY(int, updatedAvatarCount, 0) STATS_PROPERTY(int, updatedAvatarCount, 0)
STATS_PROPERTY(int, notUpdatedAvatarCount, 0) STATS_PROPERTY(int, notUpdatedAvatarCount, 0)
STATS_PROPERTY(int, packetInCount, 0) STATS_PROPERTY(int, packetInCount, 0)
@ -423,6 +425,13 @@ signals:
*/ */
void gameLoopRateChanged(); void gameLoopRateChanged();
/**jsdoc
* Trigered when
* @function Stats.numPhysicsBodiesChanged
* @returns {Signal}
*/
void physicsObjectCountChanged();
/**jsdoc /**jsdoc
* Triggered when the value of the <code>avatarCount</code> property changes. * Triggered when the value of the <code>avatarCount</code> property changes.
* @function Stats.avatarCountChanged * @function Stats.avatarCountChanged

View file

@ -10,9 +10,13 @@
#include "PhysicsBoundary.h" #include "PhysicsBoundary.h"
#include <EntityItem.h>
#include <PhysicalEntitySimulation.h>
#include <PhysicsLogging.h> #include <PhysicsLogging.h>
#include <workload/Space.h> #include <workload/Space.h>
#include "avatar/AvatarManager.h"
#include "avatar/OtherAvatar.h"
#include "workload/GameWorkload.h" #include "workload/GameWorkload.h"
void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const Inputs& inputs) { void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const Inputs& inputs) {
@ -21,13 +25,27 @@ void PhysicsBoundary::run(const workload::WorkloadContextPointer& context, const
return; return;
} }
GameWorkloadContext* gameContext = static_cast<GameWorkloadContext*>(context.get()); GameWorkloadContext* gameContext = static_cast<GameWorkloadContext*>(context.get());
PhysicalEntitySimulationPointer simulation = gameContext->_simulation;
const auto& regionChanges = inputs.get0(); const auto& regionChanges = inputs.get0();
for (uint32_t i = 0; i < (uint32_t)regionChanges.size(); ++i) { for (uint32_t i = 0; i < (uint32_t)regionChanges.size(); ++i) {
const workload::Space::Change& change = regionChanges[i]; const workload::Space::Change& change = regionChanges[i];
auto entity = space->getOwner(change.proxyId).get<EntityItemPointer>(); auto nestable = space->getOwner(change.proxyId).get<SpatiallyNestablePointer>();
if (entity) { if (nestable) {
simulation->changeEntity(entity); switch (nestable->getNestableType()) {
case NestableType::Entity: {
gameContext->_simulation->changeEntity(std::static_pointer_cast<EntityItem>(nestable));
}
break;
case NestableType::Avatar: {
auto avatar = std::static_pointer_cast<OtherAvatar>(nestable);
avatar->setWorkloadRegion(change.region);
if (avatar->isInPhysicsSimulation() != avatar->shouldBeInPhysicsSimulation()) {
DependencyManager::get<AvatarManager>()->queuePhysicsChange(avatar);
}
}
break;
default:
break;
}
} }
} }
} }

View file

@ -7,25 +7,22 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#ifndef hifi_PhysicsGatekeeper_h #ifndef hifi_PhysicsBoundary_h
#define hifi_PhysicsGatekeeper_h #define hifi_PhysicsBoundary_h
#include <EntityItem.h>
#include <workload/Engine.h> #include <workload/Engine.h>
#include <workload/RegionTracker.h> #include <workload/RegionTracker.h>
#include "PhysicalEntitySimulation.h"
class PhysicsBoundary { class PhysicsBoundary {
public: public:
using Config = workload::Job::Config; using Config = workload::Job::Config;
using Inputs = workload::RegionTracker::Outputs; using Inputs = workload::RegionTracker::Outputs;
using Outputs = bool; using Outputs = bool;
using JobModel = workload::Job::ModelI<PhysicsBoundary, Inputs, Config>; // this doesn't work using JobModel = workload::Job::ModelI<PhysicsBoundary, Inputs, Config>;
PhysicsBoundary() {} PhysicsBoundary() {}
void configure(const Config& config) { } void configure(const Config& config) { }
void run(const workload::WorkloadContextPointer& context, const Inputs& inputs); void run(const workload::WorkloadContextPointer& context, const Inputs& inputs);
}; };
#endif // hifi_PhysicsGatekeeper_h #endif // hifi_PhysicsBoundary_h

View file

@ -1483,9 +1483,6 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
const float MOVE_DISTANCE_THRESHOLD = 0.001f; const float MOVE_DISTANCE_THRESHOLD = 0.001f;
_moving = glm::distance(oldPosition, getWorldPosition()) > MOVE_DISTANCE_THRESHOLD; _moving = glm::distance(oldPosition, getWorldPosition()) > MOVE_DISTANCE_THRESHOLD;
if (_moving) {
addPhysicsFlags(Simulation::DIRTY_POSITION);
}
if (_moving || _hasNewJointData) { if (_moving || _hasNewJointData) {
locationChanged(); locationChanged();
} }
@ -1627,20 +1624,6 @@ float Avatar::computeMass() {
return _density * TWO_PI * radius * radius * (glm::length(end - start) + 2.0f * radius / 3.0f); return _density * TWO_PI * radius * radius * (glm::length(end - start) + 2.0f * radius / 3.0f);
} }
void Avatar::rebuildCollisionShape() {
addPhysicsFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
}
void Avatar::setPhysicsCallback(AvatarPhysicsCallback cb) {
_physicsCallback = cb;
}
void Avatar::addPhysicsFlags(uint32_t flags) {
if (_physicsCallback) {
_physicsCallback(flags);
}
}
// thread-safe // thread-safe
glm::vec3 Avatar::getLeftPalmPosition() const { glm::vec3 Avatar::getLeftPalmPosition() const {
return _leftPalmPositionCache.get(); return _leftPalmPositionCache.get();

View file

@ -50,8 +50,6 @@ enum ScreenTintLayer {
class Texture; class Texture;
using AvatarPhysicsCallback = std::function<void(uint32_t)>;
class Avatar : public AvatarData, public scriptable::ModelProvider { class Avatar : public AvatarData, public scriptable::ModelProvider {
Q_OBJECT Q_OBJECT
@ -244,7 +242,7 @@ public:
// (otherwise floating point error will cause problems at large positions). // (otherwise floating point error will cause problems at large positions).
void applyPositionDelta(const glm::vec3& delta); void applyPositionDelta(const glm::vec3& delta);
virtual void rebuildCollisionShape(); virtual void rebuildCollisionShape() = 0;
virtual void computeShapeInfo(ShapeInfo& shapeInfo); virtual void computeShapeInfo(ShapeInfo& shapeInfo);
void getCapsule(glm::vec3& start, glm::vec3& end, float& radius); void getCapsule(glm::vec3& start, glm::vec3& end, float& radius);
@ -332,10 +330,6 @@ public:
render::ItemID getRenderItemID() { return _renderItemID; } render::ItemID getRenderItemID() { return _renderItemID; }
bool isMoving() const { return _moving; } bool isMoving() const { return _moving; }
void setPhysicsCallback(AvatarPhysicsCallback cb);
void addPhysicsFlags(uint32_t flags);
bool isInPhysicsSimulation() const { return _physicsCallback != nullptr; }
void fadeIn(render::ScenePointer scene); void fadeIn(render::ScenePointer scene);
void fadeOut(render::ScenePointer scene, KillAvatarReason reason); void fadeOut(render::ScenePointer scene, KillAvatarReason reason);
bool isFading() const { return _isFading; } bool isFading() const { return _isFading; }
@ -530,8 +524,6 @@ protected:
int _voiceSphereID; int _voiceSphereID;
AvatarPhysicsCallback _physicsCallback { nullptr };
float _displayNameTargetAlpha { 1.0f }; float _displayNameTargetAlpha { 1.0f };
float _displayNameAlpha { 1.0f }; float _displayNameAlpha { 1.0f };

View file

@ -295,7 +295,8 @@ void EntityTreeRenderer::addPendingEntities(const render::ScenePointer& scene, r
auto spaceIndex = _space->allocateID(); auto spaceIndex = _space->allocateID();
workload::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius()); workload::Sphere sphere(entity->getWorldPosition(), entity->getBoundingRadius());
workload::Transaction transaction; workload::Transaction transaction;
transaction.reset(spaceIndex, sphere, workload::Owner(entity)); SpatiallyNestablePointer nestable = std::static_pointer_cast<SpatiallyNestable>(entity);
transaction.reset(spaceIndex, sphere, workload::Owner(nestable));
_space->enqueueTransaction(transaction); _space->enqueueTransaction(transaction);
entity->setSpaceIndex(spaceIndex); entity->setSpaceIndex(spaceIndex);
connect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate, Qt::QueuedConnection); connect(entity.get(), &EntityItem::spaceUpdate, this, &EntityTreeRenderer::handleSpaceUpdate, Qt::QueuedConnection);

View file

@ -64,6 +64,13 @@ void ZoneEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity
_hazeIndex = INVALID_INDEX; _hazeIndex = INVALID_INDEX;
} }
} }
if (_bloomStage) {
if (!BloomStage::isIndexInvalid(_bloomIndex)) {
_bloomStage->removeBloom(_bloomIndex);
_bloomIndex = INVALID_INDEX;
}
}
} }
void ZoneEntityRenderer::doRender(RenderArgs* args) { void ZoneEntityRenderer::doRender(RenderArgs* args) {
@ -112,6 +119,11 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
assert(_hazeStage); assert(_hazeStage);
} }
if (!_bloomStage) {
_bloomStage = args->_scene->getStage<BloomStage>();
assert(_bloomStage);
}
{ // Sun { // Sun
// Need an update ? // Need an update ?
if (_needSunUpdate) { if (_needSunUpdate) {
@ -161,6 +173,15 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
} }
} }
{
if (_needBloomUpdate) {
if (BloomStage::isIndexInvalid(_bloomIndex)) {
_bloomIndex = _bloomStage->addBloom(_bloom);
}
_needBloomUpdate = false;
}
}
if (_visible) { if (_visible) {
// Finally, push the lights visible in the frame // Finally, push the lights visible in the frame
// //
@ -190,6 +211,12 @@ void ZoneEntityRenderer::doRender(RenderArgs* args) {
if (_hazeMode != COMPONENT_MODE_INHERIT) { if (_hazeMode != COMPONENT_MODE_INHERIT) {
_hazeStage->_currentFrame.pushHaze(_hazeIndex); _hazeStage->_currentFrame.pushHaze(_hazeIndex);
} }
if (_bloomMode == COMPONENT_MODE_DISABLED) {
_bloomStage->_currentFrame.pushBloom(INVALID_INDEX);
} else if (_bloomMode == COMPONENT_MODE_ENABLED) {
_bloomStage->_currentFrame.pushBloom(_bloomIndex);
}
} }
} }
@ -211,6 +238,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
bool ambientLightChanged = entity->ambientLightPropertiesChanged(); bool ambientLightChanged = entity->ambientLightPropertiesChanged();
bool skyboxChanged = entity->skyboxPropertiesChanged(); bool skyboxChanged = entity->skyboxPropertiesChanged();
bool hazeChanged = entity->hazePropertiesChanged(); bool hazeChanged = entity->hazePropertiesChanged();
bool bloomChanged = entity->bloomPropertiesChanged();
entity->resetRenderingPropertiesChanged(); entity->resetRenderingPropertiesChanged();
_lastPosition = entity->getWorldPosition(); _lastPosition = entity->getWorldPosition();
@ -221,6 +249,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
_ambientLightProperties = entity->getAmbientLightProperties(); _ambientLightProperties = entity->getAmbientLightProperties();
_skyboxProperties = entity->getSkyboxProperties(); _skyboxProperties = entity->getSkyboxProperties();
_hazeProperties = entity->getHazeProperties(); _hazeProperties = entity->getHazeProperties();
_bloomProperties = entity->getBloomProperties();
#if 0 #if 0
if (_lastShapeURL != _typedEntity->getCompoundShapeURL()) { if (_lastShapeURL != _typedEntity->getCompoundShapeURL()) {
@ -258,6 +287,10 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen
if (hazeChanged) { if (hazeChanged) {
updateHazeFromEntity(entity); updateHazeFromEntity(entity);
} }
if (bloomChanged) {
updateBloomFromEntity(entity);
}
} }
void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { void ZoneEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) {
@ -276,6 +309,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint
if (entity->keyLightPropertiesChanged() || if (entity->keyLightPropertiesChanged() ||
entity->ambientLightPropertiesChanged() || entity->ambientLightPropertiesChanged() ||
entity->hazePropertiesChanged() || entity->hazePropertiesChanged() ||
entity->bloomPropertiesChanged() ||
entity->skyboxPropertiesChanged()) { entity->skyboxPropertiesChanged()) {
return true; return true;
@ -388,6 +422,16 @@ void ZoneEntityRenderer::updateHazeFromEntity(const TypedEntityPointer& entity)
haze->setTransform(entity->getTransform().getMatrix()); haze->setTransform(entity->getTransform().getMatrix());
} }
void ZoneEntityRenderer::updateBloomFromEntity(const TypedEntityPointer& entity) {
setBloomMode((ComponentMode)entity->getBloomMode());
const auto& bloom = editBloom();
bloom->setBloomIntensity(_bloomProperties.getBloomIntensity());
bloom->setBloomThreshold(_bloomProperties.getBloomThreshold());
bloom->setBloomSize(_bloomProperties.getBloomSize());
}
void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) { void ZoneEntityRenderer::updateKeyBackgroundFromEntity(const TypedEntityPointer& entity) {
setSkyboxMode((ComponentMode)entity->getSkyboxMode()); setSkyboxMode((ComponentMode)entity->getSkyboxMode());
@ -510,6 +554,10 @@ void ZoneEntityRenderer::setSkyboxMode(ComponentMode mode) {
_skyboxMode = mode; _skyboxMode = mode;
} }
void ZoneEntityRenderer::setBloomMode(ComponentMode mode) {
_bloomMode = mode;
}
void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) { void ZoneEntityRenderer::setSkyboxColor(const glm::vec3& color) {
editSkybox()->setColor(color); editSkybox()->setColor(color);
} }

View file

@ -1,7 +1,6 @@
// //
// RenderableZoneEntityItem.h // RenderableZoneEntityItem.h
// //
//
// Created by Clement on 4/22/15. // Created by Clement on 4/22/15.
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
@ -15,10 +14,12 @@
#include <ZoneEntityItem.h> #include <ZoneEntityItem.h>
#include <graphics/Skybox.h> #include <graphics/Skybox.h>
#include <graphics/Haze.h> #include <graphics/Haze.h>
#include <graphics/Bloom.h>
#include <graphics/Stage.h> #include <graphics/Stage.h>
#include <LightStage.h> #include <LightStage.h>
#include <BackgroundStage.h> #include <BackgroundStage.h>
#include <HazeStage.h> #include <HazeStage.h>
#include <BloomStage.h>
#include <TextureCache.h> #include <TextureCache.h>
#include "RenderableEntityItem.h" #include "RenderableEntityItem.h"
#include <ComponentMode.h> #include <ComponentMode.h>
@ -50,6 +51,7 @@ private:
void updateAmbientLightFromEntity(const TypedEntityPointer& entity); void updateAmbientLightFromEntity(const TypedEntityPointer& entity);
void updateHazeFromEntity(const TypedEntityPointer& entity); void updateHazeFromEntity(const TypedEntityPointer& entity);
void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity); void updateKeyBackgroundFromEntity(const TypedEntityPointer& entity);
void updateBloomFromEntity(const TypedEntityPointer& entity);
void updateAmbientMap(); void updateAmbientMap();
void updateSkyboxMap(); void updateSkyboxMap();
void setAmbientURL(const QString& ambientUrl); void setAmbientURL(const QString& ambientUrl);
@ -59,6 +61,7 @@ private:
void setKeyLightMode(ComponentMode mode); void setKeyLightMode(ComponentMode mode);
void setAmbientLightMode(ComponentMode mode); void setAmbientLightMode(ComponentMode mode);
void setSkyboxMode(ComponentMode mode); void setSkyboxMode(ComponentMode mode);
void setBloomMode(ComponentMode mode);
void setSkyboxColor(const glm::vec3& color); void setSkyboxColor(const glm::vec3& color);
void setProceduralUserData(const QString& userData); void setProceduralUserData(const QString& userData);
@ -68,6 +71,7 @@ private:
graphics::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; } graphics::SunSkyStagePointer editBackground() { _needBackgroundUpdate = true; return _background; }
graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); } graphics::SkyboxPointer editSkybox() { return editBackground()->getSkybox(); }
graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; } graphics::HazePointer editHaze() { _needHazeUpdate = true; return _haze; }
graphics::BloomPointer editBloom() { _needBloomUpdate = true; return _bloom; }
glm::vec3 _lastPosition; glm::vec3 _lastPosition;
glm::vec3 _lastDimensions; glm::vec3 _lastDimensions;
@ -86,11 +90,13 @@ private:
const graphics::LightPointer _ambientLight { std::make_shared<graphics::Light>() }; const graphics::LightPointer _ambientLight { std::make_shared<graphics::Light>() };
const graphics::SunSkyStagePointer _background { std::make_shared<graphics::SunSkyStage>() }; const graphics::SunSkyStagePointer _background { std::make_shared<graphics::SunSkyStage>() };
const graphics::HazePointer _haze { std::make_shared<graphics::Haze>() }; const graphics::HazePointer _haze { std::make_shared<graphics::Haze>() };
const graphics::BloomPointer _bloom { std::make_shared<graphics::Bloom>() };
ComponentMode _keyLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _keyLightMode { COMPONENT_MODE_INHERIT };
ComponentMode _ambientLightMode { COMPONENT_MODE_INHERIT }; ComponentMode _ambientLightMode { COMPONENT_MODE_INHERIT };
ComponentMode _skyboxMode { COMPONENT_MODE_INHERIT }; ComponentMode _skyboxMode { COMPONENT_MODE_INHERIT };
ComponentMode _hazeMode { COMPONENT_MODE_INHERIT }; ComponentMode _hazeMode { COMPONENT_MODE_INHERIT };
ComponentMode _bloomMode { COMPONENT_MODE_INHERIT };
indexed_container::Index _sunIndex { LightStage::INVALID_INDEX }; indexed_container::Index _sunIndex { LightStage::INVALID_INDEX };
indexed_container::Index _shadowIndex { LightStage::INVALID_INDEX }; indexed_container::Index _shadowIndex { LightStage::INVALID_INDEX };
@ -102,16 +108,21 @@ private:
HazeStagePointer _hazeStage; HazeStagePointer _hazeStage;
HazeStage::Index _hazeIndex { HazeStage::INVALID_INDEX }; HazeStage::Index _hazeIndex { HazeStage::INVALID_INDEX };
BloomStagePointer _bloomStage;
BloomStage::Index _bloomIndex { BloomStage::INVALID_INDEX };
bool _needUpdate{ true }; bool _needUpdate{ true };
bool _needSunUpdate{ true }; bool _needSunUpdate{ true };
bool _needAmbientUpdate{ true }; bool _needAmbientUpdate{ true };
bool _needBackgroundUpdate{ true }; bool _needBackgroundUpdate{ true };
bool _needHazeUpdate{ true }; bool _needHazeUpdate{ true };
bool _needBloomUpdate { true };
KeyLightPropertyGroup _keyLightProperties; KeyLightPropertyGroup _keyLightProperties;
AmbientLightPropertyGroup _ambientLightProperties; AmbientLightPropertyGroup _ambientLightProperties;
HazePropertyGroup _hazeProperties; HazePropertyGroup _hazeProperties;
SkyboxPropertyGroup _skyboxProperties; SkyboxPropertyGroup _skyboxProperties;
BloomPropertyGroup _bloomProperties;
// More attributes used for rendering: // More attributes used for rendering:
QString _ambientTextureURL; QString _ambientTextureURL;

View file

@ -0,0 +1,159 @@
//
// BloomPropertyGroup.cpp
// libraries/entities/src
//
// Created by Sam Gondelman on 8/7/2018
// 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 "BloomPropertyGroup.h"
#include <OctreePacketData.h>
#include "EntityItemProperties.h"
#include "EntityItemPropertiesMacros.h"
void BloomPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold);
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize);
}
void BloomPropertyGroup::copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) {
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomIntensity, float, setBloomIntensity);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomThreshold, float, setBloomThreshold);
COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(bloom, bloomSize, float, setBloomSize);
}
void BloomPropertyGroup::merge(const BloomPropertyGroup& other) {
COPY_PROPERTY_IF_CHANGED(bloomIntensity);
COPY_PROPERTY_IF_CHANGED(bloomThreshold);
COPY_PROPERTY_IF_CHANGED(bloomSize);
}
void BloomPropertyGroup::debugDump() const {
qCDebug(entities) << " BloomPropertyGroup: ---------------------------------------------";
qCDebug(entities) << " _bloomIntensity:" << _bloomIntensity;
qCDebug(entities) << " _bloomThreshold:" << _bloomThreshold;
qCDebug(entities) << " _bloomSize:" << _bloomSize;
}
void BloomPropertyGroup::listChangedProperties(QList<QString>& out) {
if (bloomIntensityChanged()) {
out << "bloom-bloomIntensity";
}
if (bloomThresholdChanged()) {
out << "bloom-bloomThreshold";
}
if (bloomSizeChanged()) {
out << "bloom-bloomSize";
}
}
bool BloomPropertyGroup::appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize());
return true;
}
bool BloomPropertyGroup::decodeFromEditPacket(EntityPropertyFlags& propertyFlags, const unsigned char*& dataAt , int& processedBytes) {
int bytesRead = 0;
bool overwriteLocalData = true;
bool somethingChanged = false;
READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity);
READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold);
READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_INTENSITY, BloomIntensity);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_THRESHOLD, BloomThreshold);
DECODE_GROUP_PROPERTY_HAS_CHANGED(PROP_BLOOM_SIZE, BloomSize);
processedBytes += bytesRead;
Q_UNUSED(somethingChanged);
return true;
}
void BloomPropertyGroup::markAllChanged() {
_bloomIntensityChanged = true;
_bloomThresholdChanged = true;
_bloomSizeChanged = true;
}
EntityPropertyFlags BloomPropertyGroup::getChangedProperties() const {
EntityPropertyFlags changedProperties;
CHECK_PROPERTY_CHANGE(PROP_BLOOM_INTENSITY, bloomIntensity);
CHECK_PROPERTY_CHANGE(PROP_BLOOM_THRESHOLD, bloomThreshold);
CHECK_PROPERTY_CHANGE(PROP_BLOOM_SIZE, bloomSize);
return changedProperties;
}
void BloomPropertyGroup::getProperties(EntityItemProperties& properties) const {
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomIntensity, getBloomIntensity);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomThreshold, getBloomThreshold);
COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(Bloom, BloomSize, getBloomSize);
}
bool BloomPropertyGroup::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = false;
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomIntensity, bloomIntensity, setBloomIntensity);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomThreshold, bloomThreshold, setBloomThreshold);
SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(Bloom, BloomSize, bloomSize, setBloomSize);
return somethingChanged;
}
EntityPropertyFlags BloomPropertyGroup::getEntityProperties(EncodeBitstreamParams& params) const {
EntityPropertyFlags requestedProperties;
requestedProperties += PROP_BLOOM_INTENSITY;
requestedProperties += PROP_BLOOM_THRESHOLD;
requestedProperties += PROP_BLOOM_SIZE;
return requestedProperties;
}
void BloomPropertyGroup::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const {
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, getBloomIntensity());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, getBloomThreshold());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_SIZE, getBloomSize());
}
int BloomPropertyGroup::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) {
int bytesRead = 0;
const unsigned char* dataAt = data;
READ_ENTITY_PROPERTY(PROP_BLOOM_INTENSITY, float, setBloomIntensity);
READ_ENTITY_PROPERTY(PROP_BLOOM_THRESHOLD, float, setBloomThreshold);
READ_ENTITY_PROPERTY(PROP_BLOOM_SIZE, float, setBloomSize);
return bytesRead;
}

View file

@ -0,0 +1,94 @@
//
// BloomPropertyGroup.h
// libraries/entities/src
//
// Created by Sam Gondelman on 8/7/2018
// 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
//
#ifndef hifi_BloomPropertyGroup_h
#define hifi_BloomPropertyGroup_h
#include <stdint.h>
#include <glm/glm.hpp>
#include <QtScript/QScriptEngine>
#include "PropertyGroup.h"
#include "EntityItemPropertiesMacros.h"
class EntityItemProperties;
class EncodeBitstreamParams;
class OctreePacketData;
class EntityTreeElementExtraEncodeData;
class ReadBitstreamToTreeParams;
static const float INITIAL_BLOOM_INTENSITY { 0.25f };
static const float INITIAL_BLOOM_THRESHOLD { 0.7f };
static const float INITIAL_BLOOM_SIZE { 0.9f };
/**jsdoc
* Bloom is defined by the following properties.
* @typedef {object} Entities.Bloom
*
* @property {number} bloomIntensity=0.25 - The intensity of the bloom effect.
* @property {number} bloomThreshold=0.7 - The threshold for the bloom effect.
* @property {number} bloomSize=0.9 - The size of the bloom effect.
*/
class BloomPropertyGroup : public PropertyGroup {
public:
// EntityItemProperty related helpers
virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties,
QScriptEngine* engine, bool skipDefaults,
EntityItemProperties& defaultEntityProperties) const override;
virtual void copyFromScriptValue(const QScriptValue& object, bool& _defaultSettings) override;
void merge(const BloomPropertyGroup& other);
virtual void debugDump() const override;
virtual void listChangedProperties(QList<QString>& out) override;
virtual bool appendToEditPacket(OctreePacketData* packetData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags,
const unsigned char*& dataAt, int& processedBytes) override;
virtual void markAllChanged() override;
virtual EntityPropertyFlags getChangedProperties() const override;
// EntityItem related helpers
// methods for getting/setting all properties of an entity
virtual void getProperties(EntityItemProperties& propertiesOut) const override;
/// returns true if something changed
virtual bool setProperties(const EntityItemProperties& properties) override;
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override;
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData,
EntityPropertyFlags& requestedProperties,
EntityPropertyFlags& propertyFlags,
EntityPropertyFlags& propertiesDidntFit,
int& propertyCount,
OctreeElement::AppendState& appendState) const override;
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
bool& somethingChanged) override;
DEFINE_PROPERTY(PROP_BLOOM_INTENSITY, BloomIntensity, bloomIntensity, float, INITIAL_BLOOM_INTENSITY);
DEFINE_PROPERTY(PROP_BLOOM_THRESHOLD, BloomThreshold, bloomThreshold, float, INITIAL_BLOOM_THRESHOLD);
DEFINE_PROPERTY(PROP_BLOOM_SIZE, BloomSize, bloomSize, float, INITIAL_BLOOM_SIZE);
};
#endif // hifi_BloomPropertyGroup_h

View file

@ -37,6 +37,7 @@
AnimationPropertyGroup EntityItemProperties::_staticAnimation; AnimationPropertyGroup EntityItemProperties::_staticAnimation;
SkyboxPropertyGroup EntityItemProperties::_staticSkybox; SkyboxPropertyGroup EntityItemProperties::_staticSkybox;
HazePropertyGroup EntityItemProperties::_staticHaze; HazePropertyGroup EntityItemProperties::_staticHaze;
BloomPropertyGroup EntityItemProperties::_staticBloom;
KeyLightPropertyGroup EntityItemProperties::_staticKeyLight; KeyLightPropertyGroup EntityItemProperties::_staticKeyLight;
AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight; AmbientLightPropertyGroup EntityItemProperties::_staticAmbientLight;
@ -84,6 +85,7 @@ void EntityItemProperties::debugDump() const {
getHaze().debugDump(); getHaze().debugDump();
getKeyLight().debugDump(); getKeyLight().debugDump();
getAmbientLight().debugDump(); getAmbientLight().debugDump();
getBloom().debugDump();
qCDebug(entities) << " changed properties..."; qCDebug(entities) << " changed properties...";
EntityPropertyFlags props = getChangedProperties(); EntityPropertyFlags props = getChangedProperties();
@ -211,6 +213,10 @@ QString EntityItemProperties::getHazeModeAsString() const {
return getComponentModeAsString(_hazeMode); return getComponentModeAsString(_hazeMode);
} }
QString EntityItemProperties::getBloomModeAsString() const {
return getComponentModeAsString(_bloomMode);
}
QString EntityItemProperties::getComponentModeString(uint32_t mode) { QString EntityItemProperties::getComponentModeString(uint32_t mode) {
// return "inherit" if mode is not valid // return "inherit" if mode is not valid
if (mode < COMPONENT_MODE_ITEM_COUNT) { if (mode < COMPONENT_MODE_ITEM_COUNT) {
@ -235,6 +241,15 @@ void EntityItemProperties::setHazeModeFromString(const QString& hazeMode) {
} }
} }
void EntityItemProperties::setBloomModeFromString(const QString& bloomMode) {
auto result = findComponent(bloomMode);
if (result != COMPONENT_MODES.end()) {
_bloomMode = result->first;
_bloomModeChanged = true;
}
}
QString EntityItemProperties::getKeyLightModeAsString() const { QString EntityItemProperties::getKeyLightModeAsString() const {
return getComponentModeAsString(_keyLightMode); return getComponentModeAsString(_keyLightMode);
} }
@ -394,6 +409,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_KEY_LIGHT_MODE, keyLightMode); CHECK_PROPERTY_CHANGE(PROP_KEY_LIGHT_MODE, keyLightMode);
CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode); CHECK_PROPERTY_CHANGE(PROP_AMBIENT_LIGHT_MODE, ambientLightMode);
CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode); CHECK_PROPERTY_CHANGE(PROP_SKYBOX_MODE, skyboxMode);
CHECK_PROPERTY_CHANGE(PROP_BLOOM_MODE, bloomMode);
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl); CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize); CHECK_PROPERTY_CHANGE(PROP_VOXEL_VOLUME_SIZE, voxelVolumeSize);
@ -454,6 +470,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
changedProperties += _ambientLight.getChangedProperties(); changedProperties += _ambientLight.getChangedProperties();
changedProperties += _skybox.getChangedProperties(); changedProperties += _skybox.getChangedProperties();
changedProperties += _haze.getChangedProperties(); changedProperties += _haze.getChangedProperties();
changedProperties += _bloom.getChangedProperties();
return changedProperties; return changedProperties;
} }
@ -1164,6 +1181,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* <code>"enabled"</code>: The haze properties of this zone are enabled, overriding the haze from any enclosing zone. * <code>"enabled"</code>: The haze properties of this zone are enabled, overriding the haze from any enclosing zone.
* @property {Entities.Haze} haze - The haze properties of the zone. * @property {Entities.Haze} haze - The haze properties of the zone.
* *
* @property {string} bloomMode="inherit" - Configures the bloom in the zone. Possible values:<br />
* <code>"inherit"</code>: The bloom from any enclosing zone continues into this zone.<br />
* <code>"disabled"</code>: The bloom from any enclosing zone and the bloom of this zone are disabled in this zone.<br />
* <code>"enabled"</code>: The bloom properties of this zone are enabled, overriding the bloom from any enclosing zone.
* @property {Entities.Bloom} bloom - The bloom properties of the zone.
*
* @property {boolean} flyingAllowed=true - If <code>true</code> then visitors can fly in the zone; otherwise they cannot. * @property {boolean} flyingAllowed=true - If <code>true</code> then visitors can fly in the zone; otherwise they cannot.
* @property {boolean} ghostingAllowed=true - If <code>true</code> then visitors with avatar collisions turned off will not * @property {boolean} ghostingAllowed=true - If <code>true</code> then visitors with avatar collisions turned off will not
* collide with content in the zone; otherwise visitors will always collide with content in the zone. * collide with content in the zone; otherwise visitors will always collide with content in the zone.
@ -1382,6 +1405,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_HAZE_MODE, hazeMode, getHazeModeAsString());
_haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties); _haze.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_BLOOM_MODE, bloomMode, getBloomModeAsString());
_bloom.copyToScriptValue(_desiredProperties, properties, engine, skipDefaults, defaultEntityProperties);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_KEY_LIGHT_MODE, keyLightMode, getKeyLightModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_AMBIENT_LIGHT_MODE, ambientLightMode, getAmbientLightModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_SKYBOX_MODE, skyboxMode, getSkyboxModeAsString());
@ -1630,6 +1656,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(bloomMode, BloomMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, vec3, setVoxelVolumeSize);
@ -1662,6 +1689,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
_ambientLight.copyFromScriptValue(object, _defaultSettings); _ambientLight.copyFromScriptValue(object, _defaultSettings);
_skybox.copyFromScriptValue(object, _defaultSettings); _skybox.copyFromScriptValue(object, _defaultSettings);
_haze.copyFromScriptValue(object, _defaultSettings); _haze.copyFromScriptValue(object, _defaultSettings);
_bloom.copyFromScriptValue(object, _defaultSettings);
COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(xTextureURL, QString, setXTextureURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
@ -1803,6 +1831,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
COPY_PROPERTY_IF_CHANGED(keyLightMode); COPY_PROPERTY_IF_CHANGED(keyLightMode);
COPY_PROPERTY_IF_CHANGED(ambientLightMode); COPY_PROPERTY_IF_CHANGED(ambientLightMode);
COPY_PROPERTY_IF_CHANGED(skyboxMode); COPY_PROPERTY_IF_CHANGED(skyboxMode);
COPY_PROPERTY_IF_CHANGED(bloomMode);
COPY_PROPERTY_IF_CHANGED(sourceUrl); COPY_PROPERTY_IF_CHANGED(sourceUrl);
COPY_PROPERTY_IF_CHANGED(voxelVolumeSize); COPY_PROPERTY_IF_CHANGED(voxelVolumeSize);
@ -1825,6 +1854,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
_ambientLight.merge(other._ambientLight); _ambientLight.merge(other._ambientLight);
_skybox.merge(other._skybox); _skybox.merge(other._skybox);
_haze.merge(other._haze); _haze.merge(other._haze);
_bloom.merge(other._bloom);
COPY_PROPERTY_IF_CHANGED(xTextureURL); COPY_PROPERTY_IF_CHANGED(xTextureURL);
COPY_PROPERTY_IF_CHANGED(yTextureURL); COPY_PROPERTY_IF_CHANGED(yTextureURL);
@ -2096,6 +2126,11 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_RANGE, Haze, haze, HazeKeyLightRange, hazeKeyLightRange); ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_RANGE, Haze, haze, HazeKeyLightRange, hazeKeyLightRange);
ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude); ADD_GROUP_PROPERTY_TO_MAP(PROP_HAZE_KEYLIGHT_ALTITUDE, Haze, haze, HazeKeyLightAltitude, hazeKeyLightAltitude);
ADD_PROPERTY_TO_MAP(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t);
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_INTENSITY, Bloom, bloom, BloomIntensity, bloomIntensity);
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_THRESHOLD, Bloom, bloom, BloomThreshold, bloomThreshold);
ADD_GROUP_PROPERTY_TO_MAP(PROP_BLOOM_SIZE, Bloom, bloom, BloomSize, bloomSize);
ADD_PROPERTY_TO_MAP(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_KEY_LIGHT_MODE, KeyLightMode, keyLightMode, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t); ADD_PROPERTY_TO_MAP(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t);
@ -2357,6 +2392,10 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
_staticHaze.setProperties(properties); _staticHaze.setProperties(properties);
_staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState); _staticHaze.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)properties.getBloomMode());
_staticBloom.setProperties(properties);
_staticBloom.appendToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)properties.getKeyLightMode());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)properties.getAmbientLightMode());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)properties.getSkyboxMode());
@ -2731,6 +2770,9 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_HAZE_MODE, uint32_t, setHazeMode);
properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes); properties.getHaze().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BLOOM_MODE, uint32_t, setBloomMode);
properties.getBloom().decodeFromEditPacket(propertyFlags, dataAt, processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode);
@ -3044,10 +3086,12 @@ void EntityItemProperties::markAllChanged() {
_skyboxModeChanged = true; _skyboxModeChanged = true;
_ambientLightModeChanged = true; _ambientLightModeChanged = true;
_hazeModeChanged = true; _hazeModeChanged = true;
_bloomModeChanged = true;
_animation.markAllChanged(); _animation.markAllChanged();
_skybox.markAllChanged(); _skybox.markAllChanged();
_haze.markAllChanged(); _haze.markAllChanged();
_bloom.markAllChanged();
_sourceUrlChanged = true; _sourceUrlChanged = true;
_voxelVolumeSizeChanged = true; _voxelVolumeSizeChanged = true;
@ -3442,15 +3486,15 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (hazeModeChanged()) { if (hazeModeChanged()) {
out += "hazeMode"; out += "hazeMode";
} }
if (bloomModeChanged()) {
out += "bloomMode";
}
if (keyLightModeChanged()) { if (keyLightModeChanged()) {
out += "keyLightMode"; out += "keyLightMode";
} }
if (ambientLightModeChanged()) { if (ambientLightModeChanged()) {
out += "ambientLightMode"; out += "ambientLightMode";
} }
if (skyboxModeChanged()) { if (skyboxModeChanged()) {
out += "skyboxMode"; out += "skyboxMode";
} }
@ -3581,6 +3625,7 @@ QList<QString> EntityItemProperties::listChangedProperties() {
getAmbientLight().listChangedProperties(out); getAmbientLight().listChangedProperties(out);
getSkybox().listChangedProperties(out); getSkybox().listChangedProperties(out);
getHaze().listChangedProperties(out); getHaze().listChangedProperties(out);
getBloom().listChangedProperties(out);
return out; return out;
} }

View file

@ -42,6 +42,7 @@
#include "SimulationOwner.h" #include "SimulationOwner.h"
#include "SkyboxPropertyGroup.h" #include "SkyboxPropertyGroup.h"
#include "HazePropertyGroup.h" #include "HazePropertyGroup.h"
#include "BloomPropertyGroup.h"
#include "TextEntityItem.h" #include "TextEntityItem.h"
#include "ZoneEntityItem.h" #include "ZoneEntityItem.h"
@ -195,9 +196,11 @@ public:
DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_SKYBOX_MODE, SkyboxMode, skyboxMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_AMBIENT_LIGHT_MODE, AmbientLightMode, ambientLightMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT); DEFINE_PROPERTY_REF_ENUM(PROP_HAZE_MODE, HazeMode, hazeMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_REF_ENUM(PROP_BLOOM_MODE, BloomMode, bloomMode, uint32_t, (uint32_t)COMPONENT_MODE_INHERIT);
DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup); DEFINE_PROPERTY_GROUP(Skybox, skybox, SkyboxPropertyGroup);
DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup); DEFINE_PROPERTY_GROUP(Haze, haze, HazePropertyGroup);
DEFINE_PROPERTY_GROUP(Bloom, bloom, BloomPropertyGroup);
DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup); DEFINE_PROPERTY_GROUP(Animation, animation, AnimationPropertyGroup);
DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, ""); DEFINE_PROPERTY_REF(PROP_SOURCE_URL, SourceUrl, sourceUrl, QString, "");
DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH); DEFINE_PROPERTY(PROP_LINE_WIDTH, LineWidth, lineWidth, float, LineEntityItem::DEFAULT_LINE_WIDTH);
@ -533,6 +536,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, KeyLightMode, keyLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, KeyLightMode, keyLightMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AmbientLightMode, ambientLightMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, AmbientLightMode, ambientLightMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, SkyboxMode, skyboxMode, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, SkyboxMode, skyboxMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BloomMode, bloomMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cloneable, cloneable, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, Cloneable, cloneable, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneLifetime, cloneLifetime, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, CloneLifetime, cloneLifetime, "");

View file

@ -257,6 +257,11 @@ enum EntityPropertyList {
PROP_SPIN_SPREAD, PROP_SPIN_SPREAD,
PROP_PARTICLE_ROTATE_WITH_ENTITY, PROP_PARTICLE_ROTATE_WITH_ENTITY,
PROP_BLOOM_MODE,
PROP_BLOOM_INTENSITY,
PROP_BLOOM_THRESHOLD,
PROP_BLOOM_SIZE,
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line // ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM, PROP_AFTER_LAST_ITEM,

View file

@ -47,33 +47,27 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID) : EntityItem(en
EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties ZoneEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class
// Contains a QString property, must be synchronized // Contain QString properties, must be synchronized
withReadLock([&] { withReadLock([&] {
_keyLightProperties.getProperties(properties); _keyLightProperties.getProperties(properties);
});
withReadLock([&] {
_ambientLightProperties.getProperties(properties); _ambientLightProperties.getProperties(properties);
_skyboxProperties.getProperties(properties);
}); });
_hazeProperties.getProperties(properties);
_bloomProperties.getProperties(properties);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType); COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
// Contains a QString property, must be synchronized
withReadLock([&] {
_skyboxProperties.getProperties(properties);
});
COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(flyingAllowed, getFlyingAllowed);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ghostingAllowed, getGhostingAllowed);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(filterURL, getFilterURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(hazeMode, getHazeMode);
_hazeProperties.getProperties(properties);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightMode, getKeyLightMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ambientLightMode, getAmbientLightMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode); COPY_ENTITY_PROPERTY_TO_PROPERTIES(skyboxMode, getSkyboxMode);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(bloomMode, getBloomMode);
return properties; return properties;
} }
@ -102,32 +96,27 @@ bool ZoneEntityItem::setSubClassProperties(const EntityItemProperties& propertie
// Contains a QString property, must be synchronized // Contains a QString property, must be synchronized
withWriteLock([&] { withWriteLock([&] {
_keyLightPropertiesChanged = _keyLightProperties.setProperties(properties); _keyLightPropertiesChanged = _keyLightProperties.setProperties(properties);
});
withWriteLock([&] {
_ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties); _ambientLightPropertiesChanged = _ambientLightProperties.setProperties(properties);
_skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
}); });
_hazePropertiesChanged = _hazeProperties.setProperties(properties);
_bloomPropertiesChanged = _bloomProperties.setProperties(properties);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType); SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, setShapeType);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
// Contains a QString property, must be synchronized
withWriteLock([&] {
_skyboxPropertiesChanged = _skyboxProperties.setProperties(properties);
});
SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(flyingAllowed, setFlyingAllowed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ghostingAllowed, setGhostingAllowed);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(filterURL, setFilterURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(hazeMode, setHazeMode);
_hazePropertiesChanged = _hazeProperties.setProperties(properties);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightMode, setKeyLightMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ambientLightMode, setAmbientLightMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode); SET_ENTITY_PROPERTY_FROM_PROPERTIES(skyboxMode, setSkyboxMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(bloomMode, setBloomMode);
somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged || somethingChanged = somethingChanged || _keyLightPropertiesChanged || _ambientLightPropertiesChanged ||
_stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged; _stagePropertiesChanged || _skyboxPropertiesChanged || _hazePropertiesChanged || _bloomPropertiesChanged;
return somethingChanged; return somethingChanged;
} }
@ -139,29 +128,29 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
int bytesRead = 0; int bytesRead = 0;
const unsigned char* dataAt = data; const unsigned char* dataAt = data;
{
int bytesFromKeylight; int bytesFromKeylight;
withWriteLock([&] { withWriteLock([&] {
bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, bytesFromKeylight = _keyLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _keyLightPropertiesChanged); propertyFlags, overwriteLocalData, _keyLightPropertiesChanged);
}); });
somethingChanged = somethingChanged || _keyLightPropertiesChanged; somethingChanged = somethingChanged || _keyLightPropertiesChanged;
bytesRead += bytesFromKeylight; bytesRead += bytesFromKeylight;
dataAt += bytesFromKeylight; dataAt += bytesFromKeylight;
}
{
int bytesFromAmbientlight; int bytesFromAmbientlight;
withWriteLock([&] { withWriteLock([&] {
bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, bytesFromAmbientlight = _ambientLightProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged); propertyFlags, overwriteLocalData, _ambientLightPropertiesChanged);
}); });
somethingChanged = somethingChanged || _ambientLightPropertiesChanged; somethingChanged = somethingChanged || _ambientLightPropertiesChanged;
bytesRead += bytesFromAmbientlight; bytesRead += bytesFromAmbientlight;
dataAt += bytesFromAmbientlight; dataAt += bytesFromAmbientlight;
}
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType); {
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
int bytesFromSkybox; int bytesFromSkybox;
withWriteLock([&] { withWriteLock([&] {
bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, bytesFromSkybox = _skyboxProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
@ -170,23 +159,36 @@ int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
somethingChanged = somethingChanged || _skyboxPropertiesChanged; somethingChanged = somethingChanged || _skyboxPropertiesChanged;
bytesRead += bytesFromSkybox; bytesRead += bytesFromSkybox;
dataAt += bytesFromSkybox; dataAt += bytesFromSkybox;
}
{
int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _hazePropertiesChanged);
somethingChanged = somethingChanged || _hazePropertiesChanged;
bytesRead += bytesFromHaze;
dataAt += bytesFromHaze;
}
{
int bytesFromBloom = _bloomProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _bloomPropertiesChanged);
somethingChanged = somethingChanged || _bloomPropertiesChanged;
bytesRead += bytesFromBloom;
dataAt += bytesFromBloom;
}
READ_ENTITY_PROPERTY(PROP_SHAPE_TYPE, ShapeType, setShapeType);
READ_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed); READ_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, bool, setFlyingAllowed);
READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed); READ_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, bool, setGhostingAllowed);
READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL); READ_ENTITY_PROPERTY(PROP_FILTER_URL, QString, setFilterURL);
READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode); READ_ENTITY_PROPERTY(PROP_HAZE_MODE, uint32_t, setHazeMode);
int bytesFromHaze = _hazeProperties.readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args,
propertyFlags, overwriteLocalData, _hazePropertiesChanged);
somethingChanged = somethingChanged || _hazePropertiesChanged;
bytesRead += bytesFromHaze;
dataAt += bytesFromHaze;
READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode); READ_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, uint32_t, setKeyLightMode);
READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode); READ_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, uint32_t, setAmbientLightMode);
READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode); READ_ENTITY_PROPERTY(PROP_SKYBOX_MODE, uint32_t, setSkyboxMode);
READ_ENTITY_PROPERTY(PROP_BLOOM_MODE, uint32_t, setBloomMode);
return bytesRead; return bytesRead;
} }
@ -196,29 +198,24 @@ EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& p
withReadLock([&] { withReadLock([&] {
requestedProperties += _keyLightProperties.getEntityProperties(params); requestedProperties += _keyLightProperties.getEntityProperties(params);
});
withReadLock([&] {
requestedProperties += _ambientLightProperties.getEntityProperties(params); requestedProperties += _ambientLightProperties.getEntityProperties(params);
requestedProperties += _skyboxProperties.getEntityProperties(params);
}); });
requestedProperties += _hazeProperties.getEntityProperties(params);
requestedProperties += _bloomProperties.getEntityProperties(params);
requestedProperties += PROP_SHAPE_TYPE; requestedProperties += PROP_SHAPE_TYPE;
requestedProperties += PROP_COMPOUND_SHAPE_URL; requestedProperties += PROP_COMPOUND_SHAPE_URL;
withReadLock([&] {
requestedProperties += _skyboxProperties.getEntityProperties(params);
});
requestedProperties += PROP_FLYING_ALLOWED; requestedProperties += PROP_FLYING_ALLOWED;
requestedProperties += PROP_GHOSTING_ALLOWED; requestedProperties += PROP_GHOSTING_ALLOWED;
requestedProperties += PROP_FILTER_URL; requestedProperties += PROP_FILTER_URL;
requestedProperties += PROP_HAZE_MODE; requestedProperties += PROP_HAZE_MODE;
requestedProperties += _hazeProperties.getEntityProperties(params);
requestedProperties += PROP_KEY_LIGHT_MODE; requestedProperties += PROP_KEY_LIGHT_MODE;
requestedProperties += PROP_AMBIENT_LIGHT_MODE; requestedProperties += PROP_AMBIENT_LIGHT_MODE;
requestedProperties += PROP_SKYBOX_MODE; requestedProperties += PROP_SKYBOX_MODE;
requestedProperties += PROP_BLOOM_MODE;
return requestedProperties; return requestedProperties;
} }
@ -235,27 +232,27 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
_keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, _keyLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState); propertyFlags, propertiesDidntFit, propertyCount, appendState);
_ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties, _ambientLightProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState); propertyFlags, propertiesDidntFit, propertyCount, appendState);
_skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
_hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
_bloomProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType()); APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL()); APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, getCompoundShapeURL());
_skyboxProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed()); APPEND_ENTITY_PROPERTY(PROP_FLYING_ALLOWED, getFlyingAllowed());
APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed()); APPEND_ENTITY_PROPERTY(PROP_GHOSTING_ALLOWED, getGhostingAllowed());
APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL()); APPEND_ENTITY_PROPERTY(PROP_FILTER_URL, getFilterURL());
APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode()); APPEND_ENTITY_PROPERTY(PROP_HAZE_MODE, (uint32_t)getHazeMode());
_hazeProperties.appendSubclassData(packetData, params, modelTreeElementExtraEncodeData, requestedProperties,
propertyFlags, propertiesDidntFit, propertyCount, appendState);
APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode()); APPEND_ENTITY_PROPERTY(PROP_KEY_LIGHT_MODE, (uint32_t)getKeyLightMode());
APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode()); APPEND_ENTITY_PROPERTY(PROP_AMBIENT_LIGHT_MODE, (uint32_t)getAmbientLightMode());
APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode()); APPEND_ENTITY_PROPERTY(PROP_SKYBOX_MODE, (uint32_t)getSkyboxMode());
APPEND_ENTITY_PROPERTY(PROP_BLOOM_MODE, (uint32_t)getBloomMode());
} }
void ZoneEntityItem::debugDump() const { void ZoneEntityItem::debugDump() const {
@ -268,11 +265,13 @@ void ZoneEntityItem::debugDump() const {
qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode); qCDebug(entities) << " _keyLightMode:" << EntityItemProperties::getComponentModeString(_keyLightMode);
qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode); qCDebug(entities) << " _ambientLightMode:" << EntityItemProperties::getComponentModeString(_ambientLightMode);
qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode); qCDebug(entities) << " _skyboxMode:" << EntityItemProperties::getComponentModeString(_skyboxMode);
qCDebug(entities) << " _bloomMode:" << EntityItemProperties::getComponentModeString(_bloomMode);
_keyLightProperties.debugDump(); _keyLightProperties.debugDump();
_ambientLightProperties.debugDump(); _ambientLightProperties.debugDump();
_skyboxProperties.debugDump(); _skyboxProperties.debugDump();
_hazeProperties.debugDump(); _hazeProperties.debugDump();
_bloomProperties.debugDump();
} }
ShapeType ZoneEntityItem::getShapeType() const { ShapeType ZoneEntityItem::getShapeType() const {
@ -344,6 +343,7 @@ void ZoneEntityItem::resetRenderingPropertiesChanged() {
_ambientLightPropertiesChanged = false; _ambientLightPropertiesChanged = false;
_skyboxPropertiesChanged = false; _skyboxPropertiesChanged = false;
_hazePropertiesChanged = false; _hazePropertiesChanged = false;
_bloomPropertiesChanged = false;
_stagePropertiesChanged = false; _stagePropertiesChanged = false;
}); });
} }
@ -359,6 +359,17 @@ uint32_t ZoneEntityItem::getHazeMode() const {
return _hazeMode; return _hazeMode;
} }
void ZoneEntityItem::setBloomMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _bloomMode) {
_bloomMode = value;
_bloomPropertiesChanged = true;
}
}
uint32_t ZoneEntityItem::getBloomMode() const {
return _bloomMode;
}
void ZoneEntityItem::setKeyLightMode(const uint32_t value) { void ZoneEntityItem::setKeyLightMode(const uint32_t value) {
if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) { if (value < COMPONENT_MODE_ITEM_COUNT && value != _keyLightMode) {
_keyLightMode = value; _keyLightMode = value;

View file

@ -18,6 +18,7 @@
#include "EntityTree.h" #include "EntityTree.h"
#include "SkyboxPropertyGroup.h" #include "SkyboxPropertyGroup.h"
#include "HazePropertyGroup.h" #include "HazePropertyGroup.h"
#include "BloomPropertyGroup.h"
#include <ComponentMode.h> #include <ComponentMode.h>
class ZoneEntityItem : public EntityItem { class ZoneEntityItem : public EntityItem {
@ -79,9 +80,13 @@ public:
void setSkyboxMode(uint32_t value); void setSkyboxMode(uint32_t value);
uint32_t getSkyboxMode() const; uint32_t getSkyboxMode() const;
void setBloomMode(const uint32_t value);
uint32_t getBloomMode() const;
SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock<SkyboxPropertyGroup>([&] { return _skyboxProperties; }); } SkyboxPropertyGroup getSkyboxProperties() const { return resultWithReadLock<SkyboxPropertyGroup>([&] { return _skyboxProperties; }); }
const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; } const HazePropertyGroup& getHazeProperties() const { return _hazeProperties; }
const BloomPropertyGroup& getBloomProperties() const { return _bloomProperties; }
bool getFlyingAllowed() const { return _flyingAllowed; } bool getFlyingAllowed() const { return _flyingAllowed; }
void setFlyingAllowed(bool value) { _flyingAllowed = value; } void setFlyingAllowed(bool value) { _flyingAllowed = value; }
@ -93,10 +98,8 @@ public:
bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; } bool keyLightPropertiesChanged() const { return _keyLightPropertiesChanged; }
bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; } bool ambientLightPropertiesChanged() const { return _ambientLightPropertiesChanged; }
bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; } bool skyboxPropertiesChanged() const { return _skyboxPropertiesChanged; }
bool hazePropertiesChanged() const { return _hazePropertiesChanged; }
bool hazePropertiesChanged() const { bool bloomPropertiesChanged() const { return _bloomPropertiesChanged; }
return _hazePropertiesChanged;
}
bool stagePropertiesChanged() const { return _stagePropertiesChanged; } bool stagePropertiesChanged() const { return _stagePropertiesChanged; }
@ -133,9 +136,11 @@ protected:
uint32_t _ambientLightMode { COMPONENT_MODE_INHERIT }; uint32_t _ambientLightMode { COMPONENT_MODE_INHERIT };
uint32_t _hazeMode { COMPONENT_MODE_INHERIT }; uint32_t _hazeMode { COMPONENT_MODE_INHERIT };
uint32_t _bloomMode { COMPONENT_MODE_INHERIT };
SkyboxPropertyGroup _skyboxProperties; SkyboxPropertyGroup _skyboxProperties;
HazePropertyGroup _hazeProperties; HazePropertyGroup _hazeProperties;
BloomPropertyGroup _bloomProperties;
bool _flyingAllowed { DEFAULT_FLYING_ALLOWED }; bool _flyingAllowed { DEFAULT_FLYING_ALLOWED };
bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED }; bool _ghostingAllowed { DEFAULT_GHOSTING_ALLOWED };
@ -146,6 +151,7 @@ protected:
bool _ambientLightPropertiesChanged { false }; bool _ambientLightPropertiesChanged { false };
bool _skyboxPropertiesChanged { false }; bool _skyboxPropertiesChanged { false };
bool _hazePropertiesChanged{ false }; bool _hazePropertiesChanged{ false };
bool _bloomPropertiesChanged { false };
bool _stagePropertiesChanged { false }; bool _stagePropertiesChanged { false };
static bool _drawZoneBoundaries; static bool _drawZoneBoundaries;

View file

@ -28,6 +28,20 @@
#include <graphics/Geometry.h> #include <graphics/Geometry.h>
#include <graphics/Material.h> #include <graphics/Material.h>
#if defined(Q_OS_ANDROID)
#define FBX_PACK_NORMALS 0
#else
#define FBX_PACK_NORMALS 1
#endif
#if FBX_PACK_NORMALS
using NormalType = glm::uint32;
#define FBX_NORMAL_ELEMENT gpu::Element::VEC4F_NORMALIZED_XYZ10W2
#else
using NormalType = glm::vec3;
#define FBX_NORMAL_ELEMENT gpu::Element::VEC3F_XYZ
#endif
// See comment in FBXReader::parseFBX(). // See comment in FBXReader::parseFBX().
static const int FBX_HEADER_BYTES_BEFORE_VERSION = 23; static const int FBX_HEADER_BYTES_BEFORE_VERSION = 23;
static const QByteArray FBX_BINARY_PROLOG("Kaydara FBX Binary "); static const QByteArray FBX_BINARY_PROLOG("Kaydara FBX Binary ");
@ -226,6 +240,7 @@ public:
QVector<glm::vec3> vertices; QVector<glm::vec3> vertices;
QVector<glm::vec3> normals; QVector<glm::vec3> normals;
QVector<glm::vec3> tangents; QVector<glm::vec3> tangents;
mutable QVector<NormalType> normalsAndTangents; // Populated later if needed for blendshapes
QVector<glm::vec3> colors; QVector<glm::vec3> colors;
QVector<glm::vec2> texCoords; QVector<glm::vec2> texCoords;
QVector<glm::vec2> texCoords1; QVector<glm::vec2> texCoords1;

View file

@ -34,20 +34,6 @@
class QIODevice; class QIODevice;
class FBXNode; class FBXNode;
#if defined(Q_OS_ANDROID)
#define FBX_PACK_NORMALS 0
#else
#define FBX_PACK_NORMALS 1
#endif
#if FBX_PACK_NORMALS
using NormalType = glm::uint32;
#define FBX_NORMAL_ELEMENT gpu::Element::VEC4F_NORMALIZED_XYZ10W2
#else
using NormalType = glm::vec3;
#define FBX_NORMAL_ELEMENT gpu::Element::VEC3F_XYZ
#endif
/// Reads FBX geometry from the supplied model and mapping data. /// Reads FBX geometry from the supplied model and mapping data.
/// \exception QString if an error occurs in parsing /// \exception QString if an error occurs in parsing
FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f); FBXGeometry* readFBX(const QByteArray& model, const QVariantHash& mapping, const QString& url = "", bool loadLightmaps = true, float lightmapLevel = 1.0f);

View file

@ -0,0 +1,18 @@
//
// Bloom.cpp
// libraries/graphics/src/graphics
//
// Created by Sam Gondelman on 8/7/2018
// 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 "Bloom.h"
using namespace graphics;
const float Bloom::INITIAL_BLOOM_INTENSITY { 0.25f };
const float Bloom::INITIAL_BLOOM_THRESHOLD { 0.7f };
const float Bloom::INITIAL_BLOOM_SIZE { 0.9f };

View file

@ -0,0 +1,41 @@
//
// Bloom.h
// libraries/graphics/src/graphics
//
// Created by Sam Gondelman on 8/7/2018
// 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
//
#ifndef hifi_model_Bloom_h
#define hifi_model_Bloom_h
#include <memory>
namespace graphics {
class Bloom {
public:
// Initial values
static const float INITIAL_BLOOM_INTENSITY;
static const float INITIAL_BLOOM_THRESHOLD;
static const float INITIAL_BLOOM_SIZE;
Bloom() {}
void setBloomIntensity(const float bloomIntensity) { _bloomIntensity = bloomIntensity; }
void setBloomThreshold(const float bloomThreshold) { _bloomThreshold = bloomThreshold; }
void setBloomSize(const float bloomSize) { _bloomSize = bloomSize; }
float getBloomIntensity() { return _bloomIntensity; }
float getBloomThreshold() { return _bloomThreshold; }
float getBloomSize() { return _bloomSize; }
private:
float _bloomIntensity { INITIAL_BLOOM_INTENSITY };
float _bloomThreshold {INITIAL_BLOOM_THRESHOLD };
float _bloomSize { INITIAL_BLOOM_SIZE };
};
using BloomPointer = std::shared_ptr<Bloom>;
}
#endif // hifi_model_Bloom_h

View file

@ -20,9 +20,6 @@
#include <AABox.h> #include <AABox.h>
#include <Extents.h> #include <Extents.h>
#include <glm/gtc/packing.hpp>
#include <glm/detail/type_vec.hpp>
namespace glm { namespace glm {
using hvec2 = glm::tvec2<glm::detail::hdata>; using hvec2 = glm::tvec2<glm::detail::hdata>;
using hvec4 = glm::tvec4<glm::detail::hdata>; using hvec4 = glm::tvec4<glm::detail::hdata>;
@ -62,32 +59,6 @@ namespace {
} }
} }
void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent) {
auto absNormal = glm::abs(normal);
auto absTangent = glm::abs(tangent);
normal /= glm::max(1e-6f, glm::max(glm::max(absNormal.x, absNormal.y), absNormal.z));
tangent /= glm::max(1e-6f, glm::max(glm::max(absTangent.x, absTangent.y), absTangent.z));
normal = glm::clamp(normal, -1.0f, 1.0f);
tangent = glm::clamp(tangent, -1.0f, 1.0f);
normal *= 511.0f;
tangent *= 511.0f;
normal = glm::round(normal);
tangent = glm::round(tangent);
glm::detail::i10i10i10i2 normalStruct;
glm::detail::i10i10i10i2 tangentStruct;
normalStruct.data.x = int(normal.x);
normalStruct.data.y = int(normal.y);
normalStruct.data.z = int(normal.z);
normalStruct.data.w = 0;
tangentStruct.data.x = int(tangent.x);
tangentStruct.data.y = int(tangent.y);
tangentStruct.data.z = int(tangent.z);
tangentStruct.data.w = 0;
packedNormal = normalStruct.pack;
packedTangent = tangentStruct.pack;
}
template <typename T> template <typename T>
glm::uint32 forEachGlmVec(const gpu::BufferView& view, std::function<bool(glm::uint32 index, const T& value)> func) { glm::uint32 forEachGlmVec(const gpu::BufferView& view, std::function<bool(glm::uint32 index, const T& value)> func) {
QVector<glm::uint32> result; QVector<glm::uint32> result;

View file

@ -9,6 +9,8 @@
#include <QtCore> #include <QtCore>
#include <memory> #include <memory>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/packing.hpp>
#include <glm/detail/type_vec.hpp>
#include "GpuHelpers.h" #include "GpuHelpers.h"
@ -44,7 +46,31 @@ namespace buffer_helpers {
gpu::BufferView clone(const gpu::BufferView& input); gpu::BufferView clone(const gpu::BufferView& input);
gpu::BufferView resized(const gpu::BufferView& input, glm::uint32 numElements); gpu::BufferView resized(const gpu::BufferView& input, glm::uint32 numElements);
void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent); inline void packNormalAndTangent(glm::vec3 normal, glm::vec3 tangent, glm::uint32& packedNormal, glm::uint32& packedTangent) {
auto absNormal = glm::abs(normal);
auto absTangent = glm::abs(tangent);
normal /= glm::max(1e-6f, glm::max(glm::max(absNormal.x, absNormal.y), absNormal.z));
tangent /= glm::max(1e-6f, glm::max(glm::max(absTangent.x, absTangent.y), absTangent.z));
normal = glm::clamp(normal, -1.0f, 1.0f);
tangent = glm::clamp(tangent, -1.0f, 1.0f);
normal *= 511.0f;
tangent *= 511.0f;
normal = glm::round(normal);
tangent = glm::round(tangent);
glm::detail::i10i10i10i2 normalStruct;
glm::detail::i10i10i10i2 tangentStruct;
normalStruct.data.x = int(normal.x);
normalStruct.data.y = int(normal.y);
normalStruct.data.z = int(normal.z);
normalStruct.data.w = 0;
tangentStruct.data.x = int(tangent.x);
tangentStruct.data.y = int(tangent.y);
tangentStruct.data.z = int(tangent.z);
tangentStruct.data.w = 0;
packedNormal = normalStruct.pack;
packedTangent = tangentStruct.pack;
}
namespace mesh { namespace mesh {
glm::uint32 forEachVertex(const graphics::MeshPointer& mesh, std::function<bool(glm::uint32 index, const QVariantMap& attributes)> func); glm::uint32 forEachVertex(const graphics::MeshPointer& mesh, std::function<bool(glm::uint32 index, const QVariantMap& attributes)> func);

View file

@ -273,6 +273,7 @@ void NodeList::reset(bool skipDomainHandlerReset) {
// refresh the owner UUID to the NULL UUID // refresh the owner UUID to the NULL UUID
setSessionUUID(QUuid()); setSessionUUID(QUuid());
setSessionLocalID(Node::NULL_LOCAL_ID);
// if we setup the DTLS socket, also disconnect from the DTLS socket readyRead() so it can handle handshaking // if we setup the DTLS socket, also disconnect from the DTLS socket readyRead() so it can handle handshaking
if (_dtlsSocket) { if (_dtlsSocket) {
@ -647,6 +648,23 @@ void NodeList::processDomainServerList(QSharedPointer<ReceivedMessage> message)
Node::LocalID newLocalID; Node::LocalID newLocalID;
packetStream >> newUUID; packetStream >> newUUID;
packetStream >> newLocalID; packetStream >> newLocalID;
// when connected, if the session ID or local ID were not null and changed, we should reset
auto currentLocalID = getSessionLocalID();
auto currentSessionID = getSessionUUID();
if (_domainHandler.isConnected() &&
((currentLocalID != Node::NULL_LOCAL_ID && newLocalID != currentLocalID) ||
(!currentSessionID.isNull() && newUUID != currentSessionID))) {
qCDebug(networking) << "Local ID or Session ID changed while connected to domain - forcing NodeList reset";
// reset the nodelist, but don't do a domain handler reset since we're about to process a good domain list
reset(true);
// tell the domain handler that we're no longer connected so that below
// it can re-perform actions as if we just connected
_domainHandler.setIsConnected(false);
}
setSessionLocalID(newLocalID); setSessionLocalID(newLocalID);
setSessionUUID(newUUID); setSessionUUID(newUUID);

View file

@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit: case PacketType::EntityEdit:
case PacketType::EntityData: case PacketType::EntityData:
case PacketType::EntityPhysics: case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::ParticleSpin); return static_cast<PacketVersion>(EntityVersion::BloomEffect);
case PacketType::EntityQuery: case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums); return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
case PacketType::AvatarIdentity: case PacketType::AvatarIdentity:

View file

@ -241,7 +241,8 @@ enum class EntityVersion : PacketVersion {
CollisionMask16Bytes, CollisionMask16Bytes,
YieldSimulationOwnership, YieldSimulationOwnership,
ParticleEntityFix, ParticleEntityFix,
ParticleSpin ParticleSpin,
BloomEffect
}; };
enum class EntityScriptCallMethodVersion : PacketVersion { enum class EntityScriptCallMethodVersion : PacketVersion {

View file

@ -119,7 +119,7 @@ bool Octree::recurseElementWithOperationSorted(const OctreeElementPointer& eleme
} }
if (sortedChildren.size() > 1) { if (sortedChildren.size() > 1) {
static auto comparator = [](const SortedChild& left, const SortedChild& right) { return left.first > right.first; }; static auto comparator = [](const SortedChild& left, const SortedChild& right) { return left.first < right.first; };
std::sort(sortedChildren.begin(), sortedChildren.end(), comparator); std::sort(sortedChildren.begin(), sortedChildren.end(), comparator);
} }

View file

@ -77,6 +77,10 @@ uint32_t PhysicsEngine::getNumSubsteps() const {
return _dynamicsWorld->getNumSubsteps(); return _dynamicsWorld->getNumSubsteps();
} }
int32_t PhysicsEngine::getNumCollisionObjects() const {
return _dynamicsWorld ? _dynamicsWorld->getNumCollisionObjects() : 0;
}
// private // private
void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
assert(motionState); assert(motionState);
@ -279,6 +283,57 @@ void PhysicsEngine::reinsertObject(ObjectMotionState* object) {
} }
} }
void PhysicsEngine::processTransaction(PhysicsEngine::Transaction& transaction) {
// removes
for (auto object : transaction.objectsToRemove) {
btRigidBody* body = object->getRigidBody();
if (body) {
removeDynamicsForBody(body);
_dynamicsWorld->removeRigidBody(body);
// NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it.
object->setRigidBody(nullptr);
body->setMotionState(nullptr);
delete body;
}
object->clearIncomingDirtyFlags();
}
// adds
for (auto object : transaction.objectsToAdd) {
addObjectToDynamicsWorld(object);
}
// changes
std::vector<ObjectMotionState*> failedChanges;
for (auto object : transaction.objectsToChange) {
uint32_t flags = object->getIncomingDirtyFlags() & DIRTY_PHYSICS_FLAGS;
if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
if (object->handleHardAndEasyChanges(flags, this)) {
object->clearIncomingDirtyFlags();
} else {
failedChanges.push_back(object);
}
} else if (flags & EASY_DIRTY_PHYSICS_FLAGS) {
object->handleEasyChanges(flags);
object->clearIncomingDirtyFlags();
}
if (object->getMotionType() == MOTION_TYPE_STATIC && object->isActive()) {
_activeStaticBodies.insert(object->getRigidBody());
}
}
// activeStaticBodies have changed (in an Easy way) and need their Aabbs updated
// but we've configured Bullet to NOT update them automatically (for improved performance)
// so we must do it ourselves
std::set<btRigidBody*>::const_iterator itr = _activeStaticBodies.begin();
while (itr != _activeStaticBodies.end()) {
_dynamicsWorld->updateSingleAabb(*itr);
++itr;
}
// we replace objectsToChange with any that failed
transaction.objectsToChange.swap(failedChanges);
}
void PhysicsEngine::removeContacts(ObjectMotionState* motionState) { void PhysicsEngine::removeContacts(ObjectMotionState* motionState) {
// trigger events for new/existing/old contacts // trigger events for new/existing/old contacts
ContactMap::iterator contactItr = _contactMap.begin(); ContactMap::iterator contactItr = _contactMap.begin();

View file

@ -70,11 +70,24 @@ using CollisionEvents = std::vector<Collision>;
class PhysicsEngine { class PhysicsEngine {
public: public:
class Transaction {
public:
void clear() {
objectsToRemove.clear();
objectsToAdd.clear();
objectsToChange.clear();
}
std::vector<ObjectMotionState*> objectsToRemove;
std::vector<ObjectMotionState*> objectsToAdd;
std::vector<ObjectMotionState*> objectsToChange;
};
PhysicsEngine(const glm::vec3& offset); PhysicsEngine(const glm::vec3& offset);
~PhysicsEngine(); ~PhysicsEngine();
void init(); void init();
uint32_t getNumSubsteps() const; uint32_t getNumSubsteps() const;
int32_t getNumCollisionObjects() const;
void removeObjects(const VectorOfMotionStates& objects); void removeObjects(const VectorOfMotionStates& objects);
void removeSetOfObjects(const SetOfMotionStates& objects); // only called during teardown void removeSetOfObjects(const SetOfMotionStates& objects); // only called during teardown
@ -83,6 +96,8 @@ public:
VectorOfMotionStates changeObjects(const VectorOfMotionStates& objects); VectorOfMotionStates changeObjects(const VectorOfMotionStates& objects);
void reinsertObject(ObjectMotionState* object); void reinsertObject(ObjectMotionState* object);
void processTransaction(Transaction& transaction);
void stepSimulation(); void stepSimulation();
void harvestPerformanceStats(); void harvestPerformanceStats();
void printPerformanceStatsToFile(const QString& filename); void printPerformanceStatsToFile(const QString& filename);
@ -160,7 +175,7 @@ private:
CharacterController* _myAvatarController; CharacterController* _myAvatarController;
uint32_t _numContactFrames = 0; uint32_t _numContactFrames { 0 };
bool _dumpNextStats { false }; bool _dumpNextStats { false };
bool _saveNextStats { false }; bool _saveNextStats { false };

View file

@ -25,11 +25,7 @@ BloomThreshold::BloomThreshold(unsigned int downsamplingFactor) {
_parameters.edit()._sampleCount = downsamplingFactor; _parameters.edit()._sampleCount = downsamplingFactor;
} }
void BloomThreshold::configure(const Config& config) { void BloomThreshold::configure(const Config& config) {}
if (_parameters.get()._threshold != config.threshold) {
_parameters.edit()._threshold = config.threshold;
}
}
void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { void BloomThreshold::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) {
assert(renderContext->args); assert(renderContext->args);
@ -39,6 +35,7 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
const auto frameTransform = inputs.get0(); const auto frameTransform = inputs.get0();
const auto inputFrameBuffer = inputs.get1(); const auto inputFrameBuffer = inputs.get1();
const auto bloom = inputs.get2();
assert(inputFrameBuffer->hasColor()); assert(inputFrameBuffer->hasColor());
@ -68,6 +65,13 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y }; glm::ivec4 viewport{ 0, 0, bufferSize.x, bufferSize.y };
if (!bloom) {
renderContext->taskFlow.abortTask();
return;
}
_parameters.edit()._threshold = bloom->getBloomThreshold();
gpu::doInBatch("BloomThreshold::run", args->_context, [&](gpu::Batch& batch) { gpu::doInBatch("BloomThreshold::run", args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false); batch.enableStereo(false);
@ -83,23 +87,15 @@ void BloomThreshold::run(const render::RenderContextPointer& renderContext, cons
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);
}); });
outputs = _outputBuffer; outputs.edit0() = _outputBuffer;
outputs.edit1() = 0.5f + bloom->getBloomSize() * 3.5f;
} }
BloomApply::BloomApply() { BloomApply::BloomApply() {
} }
void BloomApply::configure(const Config& config) { void BloomApply::configure(const Config& config) {}
const auto newIntensity = config.intensity / 3.0f;
if (_parameters.get()._intensities.x != newIntensity) {
auto& parameters = _parameters.edit();
parameters._intensities.x = newIntensity;
parameters._intensities.y = newIntensity;
parameters._intensities.z = newIntensity;
}
}
void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { void BloomApply::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) {
assert(renderContext->args); assert(renderContext->args);
@ -109,7 +105,6 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
static const auto BLUR0_SLOT = 0; static const auto BLUR0_SLOT = 0;
static const auto BLUR1_SLOT = 1; static const auto BLUR1_SLOT = 1;
static const auto BLUR2_SLOT = 2; static const auto BLUR2_SLOT = 2;
static const auto PARAMETERS_SLOT = 0;
if (!_pipeline) { if (!_pipeline) {
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::bloomApply); gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::bloomApply);
@ -123,8 +118,15 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
const auto blur0FB = inputs.get1(); const auto blur0FB = inputs.get1();
const auto blur1FB = inputs.get2(); const auto blur1FB = inputs.get2();
const auto blur2FB = inputs.get3(); const auto blur2FB = inputs.get3();
const auto bloom = inputs.get4();
const glm::ivec4 viewport{ 0, 0, framebufferSize.x, framebufferSize.y }; const glm::ivec4 viewport{ 0, 0, framebufferSize.x, framebufferSize.y };
const auto newIntensity = bloom->getBloomIntensity() / 3.0f;
auto& parameters = _parameters.edit();
parameters._intensities.x = newIntensity;
parameters._intensities.y = newIntensity;
parameters._intensities.z = newIntensity;
gpu::doInBatch("BloomApply::run", args->_context, [&](gpu::Batch& batch) { gpu::doInBatch("BloomApply::run", args->_context, [&](gpu::Batch& batch) {
batch.enableStereo(false); batch.enableStereo(false);
@ -139,7 +141,7 @@ void BloomApply::run(const render::RenderContextPointer& renderContext, const In
batch.setResourceTexture(BLUR0_SLOT, blur0FB->getRenderBuffer(0)); batch.setResourceTexture(BLUR0_SLOT, blur0FB->getRenderBuffer(0));
batch.setResourceTexture(BLUR1_SLOT, blur1FB->getRenderBuffer(0)); batch.setResourceTexture(BLUR1_SLOT, blur1FB->getRenderBuffer(0));
batch.setResourceTexture(BLUR2_SLOT, blur2FB->getRenderBuffer(0)); batch.setResourceTexture(BLUR2_SLOT, blur2FB->getRenderBuffer(0));
batch.setUniformBuffer(PARAMETERS_SLOT, _parameters); batch.setUniformBuffer(render_utils::slot::buffer::BloomParams, _parameters);
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);
}); });
} }
@ -206,8 +208,6 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
level2FB->getRenderBuffer(0) level2FB->getRenderBuffer(0)
}; };
static auto TEXCOORD_RECT_SLOT = 1;
if (!_pipeline) { if (!_pipeline) {
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTextureOpaqueTexcoordRect); gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTextureOpaqueTexcoordRect);
gpu::StatePointer state = gpu::StatePointer(new gpu::State()); gpu::StatePointer state = gpu::StatePointer(new gpu::State());
@ -227,7 +227,7 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
Transform modelTransform; Transform modelTransform;
if (_mode == DebugBloomConfig::MODE_ALL_LEVELS) { if (_mode == DebugBloomConfig::MODE_ALL_LEVELS) {
batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.0f, 0.0f, 1.f, 1.f); batch._glUniform4f(gpu::slot::uniform::TexCoordRect, 0.0f, 0.0f, 1.f, 1.f);
modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2); modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2);
modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f)); modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f));
@ -255,7 +255,7 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
viewport.z /= 2; viewport.z /= 2;
batch._glUniform4f(TEXCOORD_RECT_SLOT, 0.5f, 0.0f, 0.5f, 1.f); batch._glUniform4f(gpu::slot::uniform::TexCoordRect, 0.5f, 0.0f, 0.5f, 1.f);
modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport); modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport);
modelTransform.postTranslate(glm::vec3(-1.0f, 0.0f, 0.0f)); modelTransform.postTranslate(glm::vec3(-1.0f, 0.0f, 0.0f));
@ -266,43 +266,9 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In
}); });
} }
void BloomConfig::setIntensity(float value) { BloomEffect::BloomEffect() {}
auto task = static_cast<render::Task::TaskConcept*>(_task);
auto blurJobIt = task->editJob("BloomApply");
assert(blurJobIt != task->_jobs.end());
blurJobIt->getConfiguration()->setProperty("intensity", value);
}
float BloomConfig::getIntensity() const { void BloomEffect::configure(const Config& config) {
auto task = static_cast<render::Task::TaskConcept*>(_task);
auto blurJobIt = task->getJob("BloomApply");
assert(blurJobIt != task->_jobs.end());
return blurJobIt->getConfiguration()->property("intensity").toFloat();
}
void BloomConfig::setSize(float value) {
std::string blurName{ "BloomBlurN" };
auto sigma = 0.5f+value*3.5f;
auto task = static_cast<render::Task::TaskConcept*>(_task);
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
blurName.back() = '0' + i;
auto blurJobIt = task->editJob(blurName);
assert(blurJobIt != task->_jobs.end());
auto& gaussianBlur = blurJobIt->edit<render::BlurGaussian>();
auto gaussianBlurParams = gaussianBlur.getParameters();
gaussianBlurParams->setFilterGaussianTaps(9, sigma);
}
auto blurJobIt = task->getJob("BloomApply");
assert(blurJobIt != task->_jobs.end());
blurJobIt->getConfiguration()->setProperty("sigma", sigma);
}
Bloom::Bloom() {
}
void Bloom::configure(const Config& config) {
std::string blurName { "BloomBlurN" }; std::string blurName { "BloomBlurN" };
for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) { for (auto i = 0; i < BLOOM_BLUR_LEVEL_COUNT; i++) {
@ -312,25 +278,30 @@ void Bloom::configure(const Config& config) {
} }
} }
void Bloom::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) { void BloomEffect::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs) {
// Start by computing threshold of color buffer input at quarter resolution // Start by computing threshold of color buffer input at quarter resolution
const auto bloomInputBuffer = task.addJob<BloomThreshold>("BloomThreshold", inputs, 4U); const auto bloomOutputs = task.addJob<BloomThreshold>("BloomThreshold", inputs, 4U);
// Multi-scale blur, each new blur is half resolution of the previous pass // Multi-scale blur, each new blur is half resolution of the previous pass
const auto blurFB0 = task.addJob<render::BlurGaussian>("BloomBlur0", bloomInputBuffer, true); const auto blurInputBuffer = bloomOutputs.getN<BloomThreshold::Outputs>(0);
const auto blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", blurFB0, true, 2U); const auto sigma = bloomOutputs.getN<BloomThreshold::Outputs>(1);
const auto blurFB2 = task.addJob<render::BlurGaussian>("BloomBlur2", blurFB1, true, 2U); const auto blurInput0 = render::BlurGaussian::Inputs(blurInputBuffer, true, 1U, 9, sigma).asVarying();
const auto blurFB0 = task.addJob<render::BlurGaussian>("BloomBlur0", blurInput0);
const auto blurInput1 = render::BlurGaussian::Inputs(blurFB0, true, 2U, 9, sigma).asVarying();
const auto blurFB1 = task.addJob<render::BlurGaussian>("BloomBlur1", blurInput1);
const auto blurInput2 = render::BlurGaussian::Inputs(blurFB1, true, 2U, 9, sigma).asVarying();
const auto blurFB2 = task.addJob<render::BlurGaussian>("BloomBlur2", blurInput2);
const auto& input = inputs.get<Inputs>(); const auto& frameBuffer = inputs.getN<Inputs>(1);
const auto& frameBuffer = input[1]; const auto& bloom = inputs.getN<Inputs>(2);
// Mix all blur levels at quarter resolution // Mix all blur levels at quarter resolution
const auto applyInput = BloomApply::Inputs(bloomInputBuffer, blurFB0, blurFB1, blurFB2).asVarying(); const auto applyInput = BloomApply::Inputs(blurInputBuffer, blurFB0, blurFB1, blurFB2, bloom).asVarying();
task.addJob<BloomApply>("BloomApply", applyInput); task.addJob<BloomApply>("BloomApply", applyInput);
// And then blend result in additive manner on top of final color buffer // And then blend result in additive manner on top of final color buffer
const auto drawInput = BloomDraw::Inputs(frameBuffer, bloomInputBuffer).asVarying(); const auto drawInput = BloomDraw::Inputs(frameBuffer, blurInputBuffer).asVarying();
task.addJob<BloomDraw>("BloomDraw", drawInput); task.addJob<BloomDraw>("BloomDraw", drawInput);
const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2, bloomInputBuffer).asVarying(); const auto debugInput = DebugBloom::Inputs(frameBuffer, blurFB0, blurFB1, blurFB2, blurInputBuffer).asVarying();
task.addJob<DebugBloom>("DebugBloom", debugInput); task.addJob<DebugBloom>("DebugBloom", debugInput);
} }

View file

@ -14,43 +14,22 @@
#include <render/Engine.h> #include <render/Engine.h>
#include "graphics/Bloom.h"
#include "DeferredFrameTransform.h" #include "DeferredFrameTransform.h"
class BloomConfig : public render::Task::Config { class BloomConfig : public render::Task::Config {
Q_OBJECT Q_OBJECT
Q_PROPERTY(float intensity READ getIntensity WRITE setIntensity NOTIFY dirty)
Q_PROPERTY(float size MEMBER size WRITE setSize NOTIFY dirty)
public:
BloomConfig() : render::Task::Config(false) {}
float size{ 0.7f };
void setIntensity(float value);
float getIntensity() const;
void setSize(float value);
signals:
void dirty();
}; };
class BloomThresholdConfig : public render::Job::Config { class BloomThresholdConfig : public render::Job::Config {
Q_OBJECT Q_OBJECT
Q_PROPERTY(float threshold MEMBER threshold NOTIFY dirty)
public:
float threshold{ 0.9f };
signals:
void dirty();
}; };
class BloomThreshold { class BloomThreshold {
public: public:
using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>; using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, gpu::FramebufferPointer, graphics::BloomPointer>;
using Outputs = gpu::FramebufferPointer; using Outputs = render::VaryingSet2<gpu::FramebufferPointer, float>;
using Config = BloomThresholdConfig; using Config = BloomThresholdConfig;
using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>; using JobModel = render::Job::ModelIO<BloomThreshold, Inputs, Outputs, Config>;
@ -71,21 +50,11 @@ private:
class BloomApplyConfig : public render::Job::Config { class BloomApplyConfig : public render::Job::Config {
Q_OBJECT Q_OBJECT
Q_PROPERTY(float intensity MEMBER intensity NOTIFY dirty)
Q_PROPERTY(float sigma MEMBER sigma NOTIFY dirty)
public:
float intensity{ 0.25f };
float sigma{ 1.0f };
signals:
void dirty();
}; };
class BloomApply { class BloomApply {
public: public:
using Inputs = render::VaryingSet4<gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer>; using Inputs = render::VaryingSet5<gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, gpu::FramebufferPointer, graphics::BloomPointer>;
using Config = BloomApplyConfig; using Config = BloomApplyConfig;
using JobModel = render::Job::ModelI<BloomApply, Inputs, Config>; using JobModel = render::Job::ModelI<BloomApply, Inputs, Config>;
@ -155,13 +124,13 @@ private:
DebugBloomConfig::Mode _mode; DebugBloomConfig::Mode _mode;
}; };
class Bloom { class BloomEffect {
public: public:
using Inputs = render::VaryingSet2<DeferredFrameTransformPointer, gpu::FramebufferPointer>; using Inputs = render::VaryingSet3<DeferredFrameTransformPointer, gpu::FramebufferPointer, graphics::BloomPointer>;
using Config = BloomConfig; using Config = BloomConfig;
using JobModel = render::Task::ModelI<Bloom, Inputs, Config>; using JobModel = render::Task::ModelI<BloomEffect, Inputs, Config>;
Bloom(); BloomEffect();
void configure(const Config& config); void configure(const Config& config);
void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs);

View file

@ -0,0 +1,79 @@
//
// BloomStage.cpp
//
// Created by Sam Gondelman on 8/7/2018
// 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 "BloomStage.h"
#include "DeferredLightingEffect.h"
#include <gpu/Context.h>
std::string BloomStage::_stageName { "BLOOM_STAGE"};
const BloomStage::Index BloomStage::INVALID_INDEX { render::indexed_container::INVALID_INDEX };
FetchBloomStage::FetchBloomStage() {
_bloom = std::make_shared<graphics::Bloom>();
}
void FetchBloomStage::configure(const Config& config) {
_bloom->setBloomIntensity(config.bloomIntensity);
_bloom->setBloomThreshold(config.bloomThreshold);
_bloom->setBloomSize(config.bloomSize);
}
BloomStage::Index BloomStage::findBloom(const BloomPointer& bloom) const {
auto found = _bloomMap.find(bloom);
if (found != _bloomMap.end()) {
return INVALID_INDEX;
} else {
return (*found).second;
}
}
BloomStage::Index BloomStage::addBloom(const BloomPointer& bloom) {
auto found = _bloomMap.find(bloom);
if (found == _bloomMap.end()) {
auto bloomId = _blooms.newElement(bloom);
// Avoid failing to allocate a bloom, just pass
if (bloomId != INVALID_INDEX) {
// Insert the bloom and its index in the reverse map
_bloomMap.insert(BloomMap::value_type(bloom, bloomId));
}
return bloomId;
} else {
return (*found).second;
}
}
BloomStage::BloomPointer BloomStage::removeBloom(Index index) {
BloomPointer removed = _blooms.freeElement(index);
if (removed) {
_bloomMap.erase(removed);
}
return removed;
}
BloomStageSetup::BloomStageSetup() {}
void BloomStageSetup::run(const render::RenderContextPointer& renderContext) {
auto stage = renderContext->_scene->getStage(BloomStage::getName());
if (!stage) {
renderContext->_scene->resetStage(BloomStage::getName(), std::make_shared<BloomStage>());
}
}
void FetchBloomStage::run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom) {
auto bloomStage = renderContext->_scene->getStage<BloomStage>();
assert(bloomStage);
bloom = nullptr;
if (bloomStage->_currentFrame._blooms.size() != 0) {
auto bloomId = bloomStage->_currentFrame._blooms.front();
bloom = bloomStage->getBloom(bloomId);
}
}

View file

@ -0,0 +1,118 @@
//
// BloomStage.h
// Created by Sam Gondelman on 8/7/2018
// 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
//
#ifndef hifi_render_utils_BloomStage_h
#define hifi_render_utils_BloomStage_h
#include <graphics/Stage.h>
#include <set>
#include <unordered_map>
#include <render/IndexedContainer.h>
#include <render/Stage.h>
#include <render/Forward.h>
#include <render/DrawTask.h>
#include <graphics/Bloom.h>
// Bloom stage to set up bloom-related rendering tasks
class BloomStage : public render::Stage {
public:
static std::string _stageName;
static const std::string& getName() { return _stageName; }
using Index = render::indexed_container::Index;
static const Index INVALID_INDEX;
static bool isIndexInvalid(Index index) { return index == INVALID_INDEX; }
using BloomPointer = graphics::BloomPointer;
using Blooms = render::indexed_container::IndexedPointerVector<graphics::Bloom>;
using BloomMap = std::unordered_map<BloomPointer, Index>;
using BloomIndices = std::vector<Index>;
Index findBloom(const BloomPointer& bloom) const;
Index addBloom(const BloomPointer& bloom);
BloomPointer removeBloom(Index index);
bool checkBloomId(Index index) const { return _blooms.checkIndex(index); }
Index getNumBlooms() const { return _blooms.getNumElements(); }
Index getNumFreeBlooms() const { return _blooms.getNumFreeIndices(); }
Index getNumAllocatedBlooms() const { return _blooms.getNumAllocatedIndices(); }
BloomPointer getBloom(Index bloomId) const {
return _blooms.get(bloomId);
}
Blooms _blooms;
BloomMap _bloomMap;
class Frame {
public:
Frame() {}
void clear() { _blooms.clear(); }
void pushBloom(BloomStage::Index index) { _blooms.emplace_back(index); }
BloomStage::BloomIndices _blooms;
};
Frame _currentFrame;
};
using BloomStagePointer = std::shared_ptr<BloomStage>;
class BloomStageSetup {
public:
using JobModel = render::Job::Model<BloomStageSetup>;
BloomStageSetup();
void run(const render::RenderContextPointer& renderContext);
protected:
};
class FetchBloomConfig : public render::Job::Config {
Q_OBJECT
Q_PROPERTY(float bloomIntensity MEMBER bloomIntensity WRITE setBloomIntensity NOTIFY dirty);
Q_PROPERTY(float bloomThreshold MEMBER bloomThreshold WRITE setBloomThreshold NOTIFY dirty);
Q_PROPERTY(float bloomSize MEMBER bloomSize WRITE setBloomSize NOTIFY dirty);
public:
FetchBloomConfig() : render::Job::Config() {}
float bloomIntensity { graphics::Bloom::INITIAL_BLOOM_INTENSITY };
float bloomThreshold { graphics::Bloom::INITIAL_BLOOM_THRESHOLD };
float bloomSize { graphics::Bloom::INITIAL_BLOOM_SIZE };
public slots:
void setBloomIntensity(const float value) { bloomIntensity = value; emit dirty(); }
void setBloomThreshold(const float value) { bloomThreshold = value; emit dirty(); }
void setBloomSize(const float value) { bloomSize = value; emit dirty(); }
signals:
void dirty();
};
class FetchBloomStage {
public:
using Config = FetchBloomConfig;
using JobModel = render::Job::ModelO<FetchBloomStage, graphics::BloomPointer, Config>;
FetchBloomStage();
void configure(const Config& config);
void run(const render::RenderContextPointer& renderContext, graphics::BloomPointer& bloom);
private:
graphics::BloomPointer _bloom;
};
#endif

View file

@ -76,6 +76,7 @@ void CauterizedModel::createRenderItemSet() {
// Run through all of the meshes, and place them into their segregated, but unsorted buckets // Run through all of the meshes, and place them into their segregated, but unsorted buckets
int shapeID = 0; int shapeID = 0;
uint32_t numMeshes = (uint32_t)meshes.size(); uint32_t numMeshes = (uint32_t)meshes.size();
const FBXGeometry& fbxGeometry = getFBXGeometry();
for (uint32_t i = 0; i < numMeshes; i++) { for (uint32_t i = 0; i < numMeshes; i++) {
const auto& mesh = meshes.at(i); const auto& mesh = meshes.at(i);
if (!mesh) { if (!mesh) {
@ -85,6 +86,10 @@ void CauterizedModel::createRenderItemSet() {
// Create the render payloads // Create the render payloads
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
if (!fbxGeometry.meshes[i].blendshapes.empty() && !_blendedVertexBuffers[i]) {
_blendedVertexBuffers[i] = std::make_shared<gpu::Buffer>();
_blendedVertexBuffers[i]->resize(fbxGeometry.meshes[i].vertices.size() * (sizeof(glm::vec3) + 2 * sizeof(NormalType)));
}
auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); auto ptr = std::make_shared<CauterizedMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
_modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr); _modelMeshRenderItems << std::static_pointer_cast<ModelMeshPartPayload>(ptr);
auto material = getGeometry()->getShapeMaterial(shapeID); auto material = getGeometry()->getShapeMaterial(shapeID);
@ -170,9 +175,10 @@ void CauterizedModel::updateClusterMatrices() {
} }
// post the blender if we're not currently waiting for one to finish // post the blender if we're not currently waiting for one to finish
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { auto modelBlender = DependencyManager::get<ModelBlender>();
if (modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
_blendedBlendshapeCoefficients = _blendshapeCoefficients; _blendedBlendshapeCoefficients = _blendshapeCoefficients;
DependencyManager::get<ModelBlender>()->noteRequiresBlend(getThisPointer()); modelBlender->noteRequiresBlend(getThisPointer());
} }
} }

View file

@ -163,6 +163,5 @@ public:
private: private:
graphics::HazePointer _haze; graphics::HazePointer _haze;
gpu::PipelinePointer _hazePipeline;
}; };
#endif #endif

View file

@ -208,7 +208,9 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning(); bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning();
_blendedVertexBuffer = model->_blendedVertexBuffers[_meshIndex]; if (!model->getFBXGeometry().meshes[meshIndex].blendshapes.isEmpty()) {
_blendedVertexBuffer = model->_blendedVertexBuffers[meshIndex];
}
auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex);
const Model::MeshState& state = model->getMeshState(_meshIndex); const Model::MeshState& state = model->getMeshState(_meshIndex);

View file

@ -44,6 +44,7 @@ using namespace std;
int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>(); int nakedModelPointerTypeId = qRegisterMetaType<ModelPointer>();
int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer>(); int weakGeometryResourceBridgePointerTypeId = qRegisterMetaType<Geometry::WeakPointer>();
int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>(); int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3>>();
int normalTypeVecTypeId = qRegisterMetaType<QVector<NormalType>>("QVector<NormalType>");
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f; float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
#define HTTP_INVALID_COM "http://invalid.com" #define HTTP_INVALID_COM "http://invalid.com"
@ -301,41 +302,52 @@ bool Model::updateGeometry() {
assert(_meshStates.empty()); assert(_meshStates.empty());
const FBXGeometry& fbxGeometry = getFBXGeometry(); const FBXGeometry& fbxGeometry = getFBXGeometry();
int i = 0;
foreach (const FBXMesh& mesh, fbxGeometry.meshes) { foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
MeshState state; MeshState state;
state.clusterDualQuaternions.resize(mesh.clusters.size()); state.clusterDualQuaternions.resize(mesh.clusters.size());
state.clusterMatrices.resize(mesh.clusters.size()); state.clusterMatrices.resize(mesh.clusters.size());
_meshStates.push_back(state); _meshStates.push_back(state);
// Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index
// later in ModelMeshPayload, however the vast majority of meshes will not have them.
// TODO? make _blendedVertexBuffers a map instead of vector and only add for meshes with blendshapes?
auto buffer = std::make_shared<gpu::Buffer>();
if (!mesh.blendshapes.isEmpty()) { if (!mesh.blendshapes.isEmpty()) {
std::vector<NormalType> normalsAndTangents; if (!_blendedVertexBuffers[i]) {
normalsAndTangents.reserve(mesh.normals.size() + mesh.tangents.size()); _blendedVertexBuffers[i] = std::make_shared<gpu::Buffer>();
}
const auto& buffer = _blendedVertexBuffers[i];
QVector<NormalType> normalsAndTangents;
normalsAndTangents.resize(2 * mesh.normals.size());
for (auto normalIt = mesh.normals.begin(), tangentIt = mesh.tangents.begin(); // Interleave normals and tangents
normalIt != mesh.normals.end(); // Parallel version for performance
tbb::parallel_for(tbb::blocked_range<int>(0, mesh.normals.size()), [&](const tbb::blocked_range<int>& range) {
auto normalsRange = std::make_pair(mesh.normals.begin() + range.begin(), mesh.normals.begin() + range.end());
auto tangentsRange = std::make_pair(mesh.tangents.begin() + range.begin(), mesh.tangents.begin() + range.end());
auto normalsAndTangentsIt = normalsAndTangents.begin() + 2 * range.begin();
for (auto normalIt = normalsRange.first, tangentIt = tangentsRange.first;
normalIt != normalsRange.second;
++normalIt, ++tangentIt) { ++normalIt, ++tangentIt) {
#if FBX_PACK_NORMALS #if FBX_PACK_NORMALS
glm::uint32 finalNormal; glm::uint32 finalNormal;
glm::uint32 finalTangent; glm::uint32 finalTangent;
buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent); buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent);
#else #else
const auto finalNormal = *normalIt; const auto& finalNormal = *normalIt;
const auto finalTangent = *tangentIt; const auto& finalTangent = *tangentIt;
#endif #endif
normalsAndTangents.push_back(finalNormal); *normalsAndTangentsIt = finalNormal;
normalsAndTangents.push_back(finalTangent); ++normalsAndTangentsIt;
*normalsAndTangentsIt = finalTangent;
++normalsAndTangentsIt;
} }
});
buffer->resize(mesh.vertices.size() * (sizeof(glm::vec3) + 2 * sizeof(NormalType))); const auto verticesSize = mesh.vertices.size() * sizeof(glm::vec3);
buffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (const gpu::Byte*) mesh.vertices.constData()); buffer->resize(mesh.vertices.size() * sizeof(glm::vec3) + normalsAndTangents.size() * sizeof(NormalType));
buffer->setSubData(mesh.vertices.size() * sizeof(glm::vec3), buffer->setSubData(0, verticesSize, (const gpu::Byte*) mesh.vertices.constData());
mesh.normals.size() * 2 * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data()); buffer->setSubData(verticesSize, 2 * mesh.normals.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data());
mesh.normalsAndTangents = normalsAndTangents;
} }
_blendedVertexBuffers.push_back(buffer); i++;
} }
needFullUpdate = true; needFullUpdate = true;
emit rigReady(); emit rigReady();
@ -432,7 +444,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
} }
if (sortedTriangleSets.size() > 1) { if (sortedTriangleSets.size() > 1) {
static auto comparator = [](const SortedTriangleSet& left, const SortedTriangleSet& right) { return left.distance > right.distance; }; static auto comparator = [](const SortedTriangleSet& left, const SortedTriangleSet& right) { return left.distance < right.distance; };
std::sort(sortedTriangleSets.begin(), sortedTriangleSets.end(), comparator); std::sort(sortedTriangleSets.begin(), sortedTriangleSets.end(), comparator);
} }
@ -575,7 +587,7 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co
} }
if (sortedTriangleSets.size() > 1) { if (sortedTriangleSets.size() > 1) {
static auto comparator = [](const SortedTriangleSet& left, const SortedTriangleSet& right) { return left.distance > right.distance; }; static auto comparator = [](const SortedTriangleSet& left, const SortedTriangleSet& right) { return left.distance < right.distance; };
std::sort(sortedTriangleSets.begin(), sortedTriangleSets.end(), comparator); std::sort(sortedTriangleSets.begin(), sortedTriangleSets.end(), comparator);
} }
@ -1327,20 +1339,21 @@ Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointe
void Blender::run() { void Blender::run() {
DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } }); DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } });
QVector<glm::vec3> vertices, normals, tangents; QVector<glm::vec3> vertices;
QVector<NormalType> normalsAndTangents;
if (_model) { if (_model) {
int offset = 0; int offset = 0;
int normalsAndTangentsOffset = 0;
foreach (const FBXMesh& mesh, _meshes) { foreach (const FBXMesh& mesh, _meshes) {
if (mesh.blendshapes.isEmpty()) { if (mesh.blendshapes.isEmpty()) {
continue; continue;
} }
vertices += mesh.vertices; vertices += mesh.vertices;
normals += mesh.normals; normalsAndTangents += mesh.normalsAndTangents;
tangents += mesh.tangents;
glm::vec3* meshVertices = vertices.data() + offset; glm::vec3* meshVertices = vertices.data() + offset;
glm::vec3* meshNormals = normals.data() + offset; NormalType* meshNormalsAndTangents = normalsAndTangents.data() + normalsAndTangentsOffset;
glm::vec3* meshTangents = tangents.data() + offset;
offset += mesh.vertices.size(); offset += mesh.vertices.size();
normalsAndTangentsOffset += mesh.normalsAndTangents.size();
const float NORMAL_COEFFICIENT_SCALE = 0.01f; const float NORMAL_COEFFICIENT_SCALE = 0.01f;
for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) { for (int i = 0, n = qMin(_blendshapeCoefficients.size(), mesh.blendshapes.size()); i < n; i++) {
float vertexCoefficient = _blendshapeCoefficients.at(i); float vertexCoefficient = _blendshapeCoefficients.at(i);
@ -1350,22 +1363,39 @@ void Blender::run() {
} }
float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE; float normalCoefficient = vertexCoefficient * NORMAL_COEFFICIENT_SCALE;
const FBXBlendshape& blendshape = mesh.blendshapes.at(i); const FBXBlendshape& blendshape = mesh.blendshapes.at(i);
for (int j = 0; j < blendshape.indices.size(); j++) { tbb::parallel_for(tbb::blocked_range<int>(0, blendshape.indices.size()), [&](const tbb::blocked_range<int>& range) {
for (auto j = range.begin(); j < range.end(); j++) {
int index = blendshape.indices.at(j); int index = blendshape.indices.at(j);
meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient; meshVertices[index] += blendshape.vertices.at(j) * vertexCoefficient;
meshNormals[index] += blendshape.normals.at(j) * normalCoefficient;
if (blendshape.tangents.size() > j) { glm::vec3 normal = mesh.normals.at(index) + blendshape.normals.at(j) * normalCoefficient;
meshTangents[index] += blendshape.tangents.at(j) * normalCoefficient; glm::vec3 tangent;
if (index < mesh.tangents.size()) {
tangent = mesh.tangents.at(index);
if ((int)j < blendshape.tangents.size()) {
tangent += blendshape.tangents.at(j) * normalCoefficient;
}
}
#if FBX_PACK_NORMALS
glm::uint32 finalNormal;
glm::uint32 finalTangent;
buffer_helpers::packNormalAndTangent(normal, tangent, finalNormal, finalTangent);
#else
const auto& finalNormal = normal;
const auto& finalTangent = tangent;
#endif
meshNormalsAndTangents[2 * index] = finalNormal;
meshNormalsAndTangents[2 * index + 1] = finalTangent;
}
});
} }
} }
} }
} // post the result to the ModelBlender, which will dispatch to the model if still alive
}
// post the result to the geometry cache, which will dispatch to the model if still alive
QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices", QMetaObject::invokeMethod(DependencyManager::get<ModelBlender>().data(), "setBlendedVertices",
Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber),
Q_ARG(const Geometry::WeakPointer&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices), Q_ARG(const Geometry::WeakPointer&, _geometry), Q_ARG(const QVector<glm::vec3>&, vertices),
Q_ARG(const QVector<glm::vec3>&, normals), Q_ARG(const QVector<glm::vec3>&, tangents)); Q_ARG(const QVector<NormalType>&, normalsAndTangents));
} }
void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) { void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions, bool forceRescale) {
@ -1525,9 +1555,10 @@ void Model::updateClusterMatrices() {
} }
// post the blender if we're not currently waiting for one to finish // post the blender if we're not currently waiting for one to finish
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { auto modelBlender = DependencyManager::get<ModelBlender>();
if (modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
_blendedBlendshapeCoefficients = _blendshapeCoefficients; _blendedBlendshapeCoefficients = _blendshapeCoefficients;
DependencyManager::get<ModelBlender>()->noteRequiresBlend(getThisPointer()); modelBlender->noteRequiresBlend(getThisPointer());
} }
} }
@ -1544,83 +1575,31 @@ bool Model::maybeStartBlender() {
} }
void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry, void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals, const QVector<glm::vec3>& tangents) { const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents) {
auto geometryRef = geometry.lock(); auto geometryRef = geometry.lock();
if (!geometryRef || _renderGeometry != geometryRef || _blendedVertexBuffers.empty() || blendNumber < _appliedBlendNumber) { if (!geometryRef || _renderGeometry != geometryRef || blendNumber < _appliedBlendNumber) {
return; return;
} }
_appliedBlendNumber = blendNumber; _appliedBlendNumber = blendNumber;
const FBXGeometry& fbxGeometry = getFBXGeometry(); const FBXGeometry& fbxGeometry = getFBXGeometry();
int index = 0; int index = 0;
std::vector<NormalType> normalsAndTangents; int normalAndTangentIndex = 0;
for (int i = 0; i < fbxGeometry.meshes.size(); i++) { for (int i = 0; i < fbxGeometry.meshes.size(); i++) {
const FBXMesh& mesh = fbxGeometry.meshes.at(i); const FBXMesh& mesh = fbxGeometry.meshes.at(i);
if (mesh.blendshapes.isEmpty()) { if (mesh.blendshapes.isEmpty()) {
continue; continue;
} }
gpu::BufferPointer& buffer = _blendedVertexBuffers[i];
const auto vertexCount = mesh.vertices.size(); const auto vertexCount = mesh.vertices.size();
const auto verticesSize = vertexCount * sizeof(glm::vec3); const auto verticesSize = vertexCount * sizeof(glm::vec3);
const auto offset = index * sizeof(glm::vec3); const auto& buffer = _blendedVertexBuffers[i];
assert(buffer);
normalsAndTangents.clear(); buffer->resize(mesh.vertices.size() * sizeof(glm::vec3) + mesh.normalsAndTangents.size() * sizeof(NormalType));
normalsAndTangents.resize(normals.size()+tangents.size()); buffer->setSubData(0, verticesSize, (gpu::Byte*) vertices.constData() + index * sizeof(glm::vec3));
// assert(normalsAndTangents.size() == 2 * vertexCount); buffer->setSubData(verticesSize, 2 * mesh.normals.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data() + normalAndTangentIndex * sizeof(NormalType));
// Interleave normals and tangents
#if 0
// Sequential version for debugging
auto normalsRange = std::make_pair(normals.begin() + index, normals.begin() + index + vertexCount);
auto tangentsRange = std::make_pair(tangents.begin() + index, tangents.begin() + index + vertexCount);
auto normalsAndTangentsIt = normalsAndTangents.begin();
for (auto normalIt = normalsRange.first, tangentIt = tangentsRange.first;
normalIt != normalsRange.second;
++normalIt, ++tangentIt) {
#if FBX_PACK_NORMALS
glm::uint32 finalNormal;
glm::uint32 finalTangent;
buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent);
#else
const auto finalNormal = *normalIt;
const auto finalTangent = *tangentIt;
#endif
*normalsAndTangentsIt = finalNormal;
++normalsAndTangentsIt;
*normalsAndTangentsIt = finalTangent;
++normalsAndTangentsIt;
}
#else
// Parallel version for performance
tbb::parallel_for(tbb::blocked_range<size_t>(index, index+vertexCount), [&](const tbb::blocked_range<size_t>& range) {
auto normalsRange = std::make_pair(normals.begin() + range.begin(), normals.begin() + range.end());
auto tangentsRange = std::make_pair(tangents.begin() + range.begin(), tangents.begin() + range.end());
auto normalsAndTangentsIt = normalsAndTangents.begin() + (range.begin()-index)*2;
for (auto normalIt = normalsRange.first, tangentIt = tangentsRange.first;
normalIt != normalsRange.second;
++normalIt, ++tangentIt) {
#if FBX_PACK_NORMALS
glm::uint32 finalNormal;
glm::uint32 finalTangent;
buffer_helpers::packNormalAndTangent(*normalIt, *tangentIt, finalNormal, finalTangent);
#else
const auto finalNormal = *normalIt;
const auto finalTangent = *tangentIt;
#endif
*normalsAndTangentsIt = finalNormal;
++normalsAndTangentsIt;
*normalsAndTangentsIt = finalTangent;
++normalsAndTangentsIt;
}
});
#endif
buffer->setSubData(0, verticesSize, (gpu::Byte*) vertices.constData() + offset);
buffer->setSubData(verticesSize, 2 * vertexCount * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data());
index += vertexCount; index += vertexCount;
normalAndTangentIndex += 2 * mesh.normals.size();
} }
} }
@ -1686,6 +1665,7 @@ void Model::createRenderItemSet() {
// Run through all of the meshes, and place them into their segregated, but unsorted buckets // Run through all of the meshes, and place them into their segregated, but unsorted buckets
int shapeID = 0; int shapeID = 0;
uint32_t numMeshes = (uint32_t)meshes.size(); uint32_t numMeshes = (uint32_t)meshes.size();
auto fbxGeometry = getFBXGeometry();
for (uint32_t i = 0; i < numMeshes; i++) { for (uint32_t i = 0; i < numMeshes; i++) {
const auto& mesh = meshes.at(i); const auto& mesh = meshes.at(i);
if (!mesh) { if (!mesh) {
@ -1695,6 +1675,9 @@ void Model::createRenderItemSet() {
// Create the render payloads // Create the render payloads
int numParts = (int)mesh->getNumParts(); int numParts = (int)mesh->getNumParts();
for (int partIndex = 0; partIndex < numParts; partIndex++) { for (int partIndex = 0; partIndex < numParts; partIndex++) {
if (fbxGeometry.meshes[i].blendshapes.empty() && !_blendedVertexBuffers[i]) {
_blendedVertexBuffers[i] = std::make_shared<gpu::Buffer>();
}
_modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset); _modelMeshRenderItems << std::make_shared<ModelMeshPartPayload>(shared_from_this(), i, partIndex, shapeID, transform, offset);
auto material = getGeometry()->getShapeMaterial(shapeID); auto material = getGeometry()->getShapeMaterial(shapeID);
_modelMeshMaterialNames.push_back(material ? material->getName() : ""); _modelMeshMaterialNames.push_back(material ? material->getName() : "");
@ -1808,10 +1791,9 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) {
} }
void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals, const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents) {
const QVector<glm::vec3>& tangents) {
if (model) { if (model) {
model->setBlendedVertices(blendNumber, geometry, vertices, normals, tangents); model->setBlendedVertices(blendNumber, geometry, vertices, normalsAndTangents);
} }
_pendingBlenders--; _pendingBlenders--;
{ {
@ -1827,4 +1809,3 @@ void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, const
} }
} }
} }

View file

@ -145,7 +145,7 @@ public:
/// Sets blended vertices computed in a separate thread. /// Sets blended vertices computed in a separate thread.
void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry, void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals, const QVector<glm::vec3>& tangents); const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents);
bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); } bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); }
bool isAddedToScene() const { return _addedToScene; } bool isAddedToScene() const { return _addedToScene; }
@ -423,7 +423,7 @@ protected:
QUrl _url; QUrl _url;
gpu::Buffers _blendedVertexBuffers; std::unordered_map<int, gpu::BufferPointer> _blendedVertexBuffers;
QVector<QVector<QSharedPointer<Texture> > > _dilatedTextures; QVector<QVector<QSharedPointer<Texture> > > _dilatedTextures;
@ -513,9 +513,12 @@ public:
/// Adds the specified model to the list requiring vertex blends. /// Adds the specified model to the list requiring vertex blends.
void noteRequiresBlend(ModelPointer model); void noteRequiresBlend(ModelPointer model);
bool shouldComputeBlendshapes() { return _computeBlendshapes; }
public slots: public slots:
void setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry, void setBlendedVertices(ModelPointer model, int blendNumber, const Geometry::WeakPointer& geometry,
const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals, const QVector<glm::vec3>& tangents); const QVector<glm::vec3>& vertices, const QVector<NormalType>& normalsAndTangents);
void setComputeBlendshapes(bool computeBlendshapes) { _computeBlendshapes = computeBlendshapes; }
private: private:
using Mutex = std::mutex; using Mutex = std::mutex;
@ -527,6 +530,8 @@ private:
std::set<ModelWeakPointer, std::owner_less<ModelWeakPointer>> _modelsRequiringBlends; std::set<ModelWeakPointer, std::owner_less<ModelWeakPointer>> _modelsRequiringBlends;
int _pendingBlenders; int _pendingBlenders;
Mutex _mutex; Mutex _mutex;
bool _computeBlendshapes { true };
}; };

View file

@ -45,6 +45,7 @@
#include "TextureCache.h" #include "TextureCache.h"
#include "ZoneRenderer.h" #include "ZoneRenderer.h"
#include "FadeEffect.h" #include "FadeEffect.h"
#include "BloomStage.h"
#include "RenderUtilsLogging.h" #include "RenderUtilsLogging.h"
#include "AmbientOcclusionEffect.h" #include "AmbientOcclusionEffect.h"
@ -173,7 +174,7 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto velocityBufferOutputs = task.addJob<VelocityBufferPass>("VelocityBuffer", velocityBufferInputs); const auto velocityBufferOutputs = task.addJob<VelocityBufferPass>("VelocityBuffer", velocityBufferInputs);
const auto velocityBuffer = velocityBufferOutputs.getN<VelocityBufferPass::Outputs>(0); const auto velocityBuffer = velocityBufferOutputs.getN<VelocityBufferPass::Outputs>(0);
// Clear Light, Haze and Skybox Stages and render zones from the general metas bucket // Clear Light, Haze, Bloom, and Skybox Stages and render zones from the general metas bucket
const auto zones = task.addJob<ZoneRendererTask>("ZoneRenderer", metas); const auto zones = task.addJob<ZoneRendererTask>("ZoneRenderer", metas);
// Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now.
@ -245,8 +246,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
task.addJob<Antialiasing>("Antialiasing", antialiasingInputs); task.addJob<Antialiasing>("Antialiasing", antialiasingInputs);
// Add bloom // Add bloom
const auto bloomInputs = Bloom::Inputs(deferredFrameTransform, lightingFramebuffer).asVarying(); const auto bloomModel = task.addJob<FetchBloomStage>("BloomModel");
task.addJob<Bloom>("Bloom", bloomInputs); const auto bloomInputs = BloomEffect::Inputs(deferredFrameTransform, lightingFramebuffer, bloomModel).asVarying();
task.addJob<BloomEffect>("Bloom", bloomInputs);
// Lighting Buffer ready for tone mapping // Lighting Buffer ready for tone mapping
const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying(); const auto toneMappingInputs = ToneMappingDeferred::Inputs(lightingFramebuffer, scaledPrimaryFramebuffer).asVarying();

View file

@ -77,8 +77,9 @@ void SoftAttachmentModel::updateClusterMatrices() {
} }
// post the blender if we're not currently waiting for one to finish // post the blender if we're not currently waiting for one to finish
if (geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { auto modelBlender = DependencyManager::get<ModelBlender>();
if (modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) {
_blendedBlendshapeCoefficients = _blendshapeCoefficients; _blendedBlendshapeCoefficients = _blendshapeCoefficients;
DependencyManager::get<ModelBlender>()->noteRequiresBlend(getThisPointer()); modelBlender->noteRequiresBlend(getThisPointer());
} }
} }

View file

@ -14,6 +14,7 @@
#include "LightStage.h" #include "LightStage.h"
#include "BackgroundStage.h" #include "BackgroundStage.h"
#include "HazeStage.h" #include "HazeStage.h"
#include "BloomStage.h"
#include <render/TransitionStage.h> #include <render/TransitionStage.h>
#include <render/HighlightStage.h> #include <render/HighlightStage.h>
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
@ -22,6 +23,7 @@ void UpdateSceneTask::build(JobModel& task, const render::Varying& input, render
task.addJob<LightStageSetup>("LightStageSetup"); task.addJob<LightStageSetup>("LightStageSetup");
task.addJob<BackgroundStageSetup>("BackgroundStageSetup"); task.addJob<BackgroundStageSetup>("BackgroundStageSetup");
task.addJob<HazeStageSetup>("HazeStageSetup"); task.addJob<HazeStageSetup>("HazeStageSetup");
task.addJob<BloomStageSetup>("BloomStageSetup");
task.addJob<render::TransitionStageSetup>("TransitionStageSetup"); task.addJob<render::TransitionStageSetup>("TransitionStageSetup");
task.addJob<render::HighlightStageSetup>("HighlightStageSetup"); task.addJob<render::HighlightStageSetup>("HighlightStageSetup");

View file

@ -21,11 +21,12 @@
#include "StencilMaskPass.h" #include "StencilMaskPass.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "render-utils/ShaderConstants.h" #include "render-utils/ShaderConstants.h"
#include "StencilMaskPass.h" #include "StencilMaskPass.h"
#include "DeferredLightingEffect.h" #include "DeferredLightingEffect.h"
#include "BloomStage.h"
namespace ru { namespace ru {
using render_utils::slot::texture::Texture; using render_utils::slot::texture::Texture;
using render_utils::slot::buffer::Buffer; using render_utils::slot::buffer::Buffer;
@ -63,7 +64,7 @@ void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& oupu
} }
void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) { void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs) {
// Grab light, background and haze stages and clear them // Grab light, background, haze, and bloom stages and clear them
auto lightStage = context->_scene->getStage<LightStage>(); auto lightStage = context->_scene->getStage<LightStage>();
assert(lightStage); assert(lightStage);
lightStage->_currentFrame.clear(); lightStage->_currentFrame.clear();
@ -76,6 +77,10 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs)
assert(hazeStage); assert(hazeStage);
hazeStage->_currentFrame.clear(); hazeStage->_currentFrame.clear();
auto bloomStage = context->_scene->getStage<BloomStage>();
assert(bloomStage);
bloomStage->_currentFrame.clear();
// call render over the zones to grab their components in the correct order first... // call render over the zones to grab their components in the correct order first...
render::renderItems(context, inputs); render::renderItems(context, inputs);
@ -84,6 +89,7 @@ void SetupZones::run(const RenderContextPointer& context, const Inputs& inputs)
lightStage->_currentFrame.pushAmbientLight(lightStage->getDefaultLight()); lightStage->_currentFrame.pushAmbientLight(lightStage->getDefaultLight());
backgroundStage->_currentFrame.pushBackground(0); backgroundStage->_currentFrame.pushBackground(0);
hazeStage->_currentFrame.pushHaze(0); hazeStage->_currentFrame.pushHaze(0);
bloomStage->_currentFrame.pushBloom(INVALID_INDEX);
} }
const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() { const gpu::PipelinePointer& DebugZoneLighting::getKeyLightPipeline() {

View file

@ -195,9 +195,7 @@ bool BlurInOutResource::updateResources(const gpu::FramebufferPointer& sourceFra
return true; return true;
} }
BlurGaussian::BlurGaussian(bool generateOutputFramebuffer, unsigned int downsampleFactor) : BlurGaussian::BlurGaussian() {
_inOutResources(generateOutputFramebuffer, downsampleFactor)
{
_parameters = std::make_shared<BlurParams>(); _parameters = std::make_shared<BlurParams>();
} }
@ -243,12 +241,17 @@ void BlurGaussian::configure(const Config& config) {
} }
void BlurGaussian::run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& blurredFramebuffer) { void BlurGaussian::run(const RenderContextPointer& renderContext, const Inputs& inputs, gpu::FramebufferPointer& blurredFramebuffer) {
assert(renderContext->args); assert(renderContext->args);
assert(renderContext->args->hasViewFrustum()); assert(renderContext->args->hasViewFrustum());
RenderArgs* args = renderContext->args; RenderArgs* args = renderContext->args;
const auto sourceFramebuffer = inputs.get0();
_inOutResources._generateOutputFramebuffer = inputs.get1();
_inOutResources._downsampleFactor = inputs.get2();
_parameters->setFilterGaussianTaps(inputs.get3(), inputs.get4());
BlurInOutResource::Resources blurringResources; BlurInOutResource::Resources blurringResources;
if (!_inOutResources.updateResources(sourceFramebuffer, blurringResources)) { if (!_inOutResources.updateResources(sourceFramebuffer, blurringResources)) {
// early exit if no valid blurring resources // early exit if no valid blurring resources

View file

@ -72,6 +72,7 @@ using BlurParamsPointer = std::shared_ptr<BlurParams>;
class BlurInOutResource { class BlurInOutResource {
public: public:
BlurInOutResource() {}
BlurInOutResource(bool generateOutputFramebuffer, unsigned int downsampleFactor); BlurInOutResource(bool generateOutputFramebuffer, unsigned int downsampleFactor);
struct Resources { struct Resources {
@ -113,13 +114,14 @@ protected:
class BlurGaussian { class BlurGaussian {
public: public:
using Inputs = VaryingSet5<gpu::FramebufferPointer, bool, unsigned int, int, float>;
using Config = BlurGaussianConfig; using Config = BlurGaussianConfig;
using JobModel = Job::ModelIO<BlurGaussian, gpu::FramebufferPointer, gpu::FramebufferPointer, Config>; using JobModel = Job::ModelIO<BlurGaussian, Inputs, gpu::FramebufferPointer, Config>;
BlurGaussian(bool generateOutputFramebuffer = false, unsigned int downsampleFactor = 1U); BlurGaussian();
void configure(const Config& config); void configure(const Config& config);
void run(const RenderContextPointer& renderContext, const gpu::FramebufferPointer& sourceFramebuffer, gpu::FramebufferPointer& blurredFramebuffer); void run(const RenderContextPointer& renderContext, const Inputs& inputs, gpu::FramebufferPointer& blurredFramebuffer);
BlurParamsPointer getParameters() const { return _parameters; } BlurParamsPointer getParameters() const { return _parameters; }

View file

@ -233,9 +233,8 @@ bool findRayAABoxIntersection(const glm::vec3& origin, const glm::vec3& directio
tmax = glm::min(tmax, newTmax); tmax = glm::min(tmax, newTmax);
} }
bool inside = tmin < 0.0f;
if (tmax >= glm::max(tmin, 0.0f)) { if (tmax >= glm::max(tmin, 0.0f)) {
if (inside) { if (tmin < 0.0f) {
distance = tmax; distance = tmax;
bool positiveDirection = direction[maxAxis] > 0.0f; bool positiveDirection = direction[maxAxis] > 0.0f;
surfaceNormal = glm::vec3(0.0f); surfaceNormal = glm::vec3(0.0f);

View file

@ -22,8 +22,8 @@ const float defaultAACubeSize = 1.0f;
const int MAX_PARENTING_CHAIN_SIZE = 30; const int MAX_PARENTING_CHAIN_SIZE = 30;
SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
_nestableType(nestableType),
_id(id), _id(id),
_nestableType(nestableType),
_transform() { _transform() {
// set flags in _transform // set flags in _transform
_transform.setTranslation(glm::vec3(0.0f)); _transform.setTranslation(glm::vec3(0.0f));

View file

@ -212,7 +212,6 @@ public:
virtual void parentDeleted() { } // called on children of a deleted parent virtual void parentDeleted() { } // called on children of a deleted parent
protected: protected:
const NestableType _nestableType; // EntityItem or an AvatarData
QUuid _id; QUuid _id;
mutable SpatiallyNestableWeakPointer _parent; mutable SpatiallyNestableWeakPointer _parent;
@ -232,6 +231,8 @@ protected:
quint64 _rotationChanged { 0 }; quint64 _rotationChanged { 0 };
private: private:
SpatiallyNestable() = delete;
const NestableType _nestableType; // EntityItem or an AvatarData
QUuid _parentID; // what is this thing's transform relative to? QUuid _parentID; // what is this thing's transform relative to?
quint16 _parentJointIndex { INVALID_JOINT_INDEX }; // which joint of the parent is this relative to? quint16 _parentJointIndex { INVALID_JOINT_INDEX }; // which joint of the parent is this relative to?

View file

@ -14,20 +14,11 @@ import "configSlider"
Item { Item {
id: root id: root
property var config: Render.getConfig("RenderMainView.Bloom")
property var configThreshold: Render.getConfig("RenderMainView.BloomThreshold")
property var configDebug: Render.getConfig("RenderMainView.DebugBloom") property var configDebug: Render.getConfig("RenderMainView.DebugBloom")
Column { Column {
spacing: 8 spacing: 8
CheckBox {
text: "Enable"
checked: root.config["enabled"]
onCheckedChanged: {
root.config["enabled"] = checked;
}
}
GroupBox { GroupBox {
title: "Debug" title: "Debug"
Row { Row {
@ -88,35 +79,5 @@ Item {
} }
} }
} }
ConfigSlider {
label: "Intensity"
integral: false
config: root.config
property: "intensity"
max: 1.0
min: 0.0
width: 280
height:38
}
ConfigSlider {
label: "Size"
integral: false
config: root.config
property: "size"
max: 1.0
min: 0.0
width: 280
height:38
}
ConfigSlider {
label: "Threshold"
integral: false
config: root.configThreshold
property: "threshold"
max: 2.0
min: 0.0
width: 280
height:38
}
} }
} }

View file

@ -15,6 +15,6 @@ var window = new OverlayWindow({
title: 'Bloom', title: 'Bloom',
source: qml, source: qml,
width: 285, width: 285,
height: 210, height: 40,
}); });
window.closed.connect(function() { Script.stop(); }); window.closed.connect(function() { Script.stop(); });

View file

@ -678,6 +678,52 @@
</div> </div>
</fieldset--> </fieldset-->
</fieldset> </fieldset>
<fieldset class="minor">
<legend class="sub-section-header zone-group zone-section">
Bloom
</legend>
<form>
<input type="radio" name="bloomMode" value="inherit" id="property-zone-bloom-mode-inherit" checked> Inherit
<input type="radio" name="bloomMode" value="disabled" id="property-zone-bloom-mode-disabled"> Off
<input type="radio" name="bloomMode" value="enabled" id="property-zone-bloom-mode-enabled"> On
</form>
<fieldset class="zone-group zone-section bloom-section property gen fstuple">
<div class="tuple">
<div>
<br>
<table>
<td><label>Bloom Intensity&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0</label></td>
<td><input type="range" class="slider" id="property-zone-bloom-intensity" min="0" max="1" step="0.01"></td>
<td><label>1</label>
</table>
</div>
</div>
</fieldset>
<fieldset class="zone-group zone-section bloom-section property gen fstuple">
<div class="tuple">
<div>
<br>
<table>
<td><label>Bloom Threshold&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0</label></td>
<td><input type="range" class="slider" id="property-zone-bloom-threshold" min="0" max="1" step="0.01"></td>
<td><label>1</label>
</table>
</div>
</div>
</fieldset>
<fieldset class="zone-group zone-section bloom-section property gen fstuple">
<div class="tuple">
<div>
<br>
<table>
<td><label>Bloom Size&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0</label></td>
<td><input type="range" class="slider" id="property-zone-bloom-size" min="0" max="2" step="0.01"></td>
<td><label>2</label>
</table>
</div>
</div>
</fieldset>
</fieldset>
</fieldset> </fieldset>
<fieldset id="text" class="major"> <fieldset id="text" class="major">
<legend class="section-header text-group text-section"> <legend class="section-header text-group text-section">

View file

@ -860,6 +860,15 @@ function loaded() {
var elZoneHazeBackgroundBlend = document.getElementById("property-zone-haze-background-blend"); var elZoneHazeBackgroundBlend = document.getElementById("property-zone-haze-background-blend");
// Bloom
var elZoneBloomModeInherit = document.getElementById("property-zone-bloom-mode-inherit");
var elZoneBloomModeDisabled = document.getElementById("property-zone-bloom-mode-disabled");
var elZoneBloomModeEnabled = document.getElementById("property-zone-bloom-mode-enabled");
var elZoneBloomIntensity = document.getElementById("property-zone-bloom-intensity");
var elZoneBloomThreshold = document.getElementById("property-zone-bloom-threshold");
var elZoneBloomSize = document.getElementById("property-zone-bloom-size");
var elZoneSkyboxColor = document.getElementById("property-zone-skybox-color"); var elZoneSkyboxColor = document.getElementById("property-zone-skybox-color");
var elZoneSkyboxColorRed = document.getElementById("property-zone-skybox-color-red"); var elZoneSkyboxColorRed = document.getElementById("property-zone-skybox-color-red");
var elZoneSkyboxColorGreen = document.getElementById("property-zone-skybox-color-green"); var elZoneSkyboxColorGreen = document.getElementById("property-zone-skybox-color-green");
@ -1069,6 +1078,9 @@ function loaded() {
elZoneHazeAltitudeEffect.checked = false; elZoneHazeAltitudeEffect.checked = false;
elZoneHazeBaseRef.value = ""; elZoneHazeBaseRef.value = "";
elZoneHazeCeiling.value = ""; elZoneHazeCeiling.value = "";
elZoneBloomIntensity.value = "";
elZoneBloomThreshold.value = "";
elZoneBloomSize.value = "";
elZoneSkyboxColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")"; elZoneSkyboxColor.style.backgroundColor = "rgb(" + 0 + "," + 0 + "," + 0 + ")";
elZoneSkyboxColorRed.value = ""; elZoneSkyboxColorRed.value = "";
elZoneSkyboxColorGreen.value = ""; elZoneSkyboxColorGreen.value = "";
@ -1078,6 +1090,7 @@ function loaded() {
showElements(document.getElementsByClassName('skybox-section'), true); showElements(document.getElementsByClassName('skybox-section'), true);
showElements(document.getElementsByClassName('ambient-section'), true); showElements(document.getElementsByClassName('ambient-section'), true);
showElements(document.getElementsByClassName('haze-section'), true); showElements(document.getElementsByClassName('haze-section'), true);
showElements(document.getElementsByClassName('bloom-section'), true);
// Text Properties // Text Properties
elTextText.value = ""; elTextText.value = "";
@ -1478,6 +1491,14 @@ function loaded() {
elZoneHazeBaseRef.value = properties.haze.hazeBaseRef.toFixed(0); elZoneHazeBaseRef.value = properties.haze.hazeBaseRef.toFixed(0);
elZoneHazeCeiling.value = properties.haze.hazeCeiling.toFixed(0); elZoneHazeCeiling.value = properties.haze.hazeCeiling.toFixed(0);
elZoneBloomModeInherit.checked = (properties.bloomMode === 'inherit');
elZoneBloomModeDisabled.checked = (properties.bloomMode === 'disabled');
elZoneBloomModeEnabled.checked = (properties.bloomMode === 'enabled');
elZoneBloomIntensity.value = properties.bloom.bloomIntensity.toFixed(2);
elZoneBloomThreshold.value = properties.bloom.bloomThreshold.toFixed(2);
elZoneBloomSize.value = properties.bloom.bloomSize.toFixed(2);
elShapeType.value = properties.shapeType; elShapeType.value = properties.shapeType;
elCompoundShapeURL.value = properties.compoundShapeURL; elCompoundShapeURL.value = properties.compoundShapeURL;
@ -1504,6 +1525,9 @@ function loaded() {
showElements(document.getElementsByClassName('haze-section'), showElements(document.getElementsByClassName('haze-section'),
elZoneHazeModeEnabled.checked); elZoneHazeModeEnabled.checked);
showElements(document.getElementsByClassName('bloom-section'),
elZoneBloomModeEnabled.checked);
} else if (properties.type === "PolyVox") { } else if (properties.type === "PolyVox") {
elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2); elVoxelVolumeSizeX.value = properties.voxelVolumeSize.x.toFixed(2);
elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2); elVoxelVolumeSizeY.value = properties.voxelVolumeSize.y.toFixed(2);
@ -2069,6 +2093,18 @@ function loaded() {
elZoneHazeBackgroundBlend.addEventListener('change', elZoneHazeBackgroundBlend.addEventListener('change',
createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBackgroundBlend')); createEmitGroupNumberPropertyUpdateFunction('haze', 'hazeBackgroundBlend'));
// Bloom
var bloomModeChanged = createZoneComponentModeChangedFunction('bloomMode',
elZoneBloomModeInherit, elZoneBloomModeDisabled, elZoneBloomModeEnabled);
elZoneBloomModeInherit.addEventListener('change', bloomModeChanged);
elZoneBloomModeDisabled.addEventListener('change', bloomModeChanged);
elZoneBloomModeEnabled.addEventListener('change', bloomModeChanged);
elZoneBloomIntensity.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomIntensity'));
elZoneBloomThreshold.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomThreshold'));
elZoneBloomSize.addEventListener('change', createEmitGroupNumberPropertyUpdateFunction('bloom', 'bloomSize'));
var zoneSkyboxColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('skybox', 'color', var zoneSkyboxColorChangeFunction = createEmitGroupColorPropertyUpdateFunction('skybox', 'color',
elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue); elZoneSkyboxColorRed, elZoneSkyboxColorGreen, elZoneSkyboxColorBlue);
elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction); elZoneSkyboxColorRed.addEventListener('change', zoneSkyboxColorChangeFunction);