mirror of
https://github.com/overte-org/overte.git
synced 2025-04-07 12:53:44 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into tuneAvatarInfo
This commit is contained in:
commit
4c80422a73
21 changed files with 245 additions and 392 deletions
|
@ -38,7 +38,7 @@
|
|||
|
||||
static const float LOUDNESS_TO_DISTANCE_RATIO = 0.00001f;
|
||||
static const float DEFAULT_ATTENUATION_PER_DOUBLING_IN_DISTANCE = 0.5f; // attenuation = -6dB * log2(distance)
|
||||
static const float DEFAULT_NOISE_MUTING_THRESHOLD = 0.003f;
|
||||
static const float DEFAULT_NOISE_MUTING_THRESHOLD = 1.0f;
|
||||
static const QString AUDIO_MIXER_LOGGING_TARGET_NAME = "audio-mixer";
|
||||
static const QString AUDIO_ENV_GROUP_KEY = "audio_env";
|
||||
static const QString AUDIO_BUFFER_GROUP_KEY = "audio_buffer";
|
||||
|
@ -69,7 +69,7 @@ AudioMixer::AudioMixer(ReceivedMessage& message) :
|
|||
packetReceiver.registerListener(PacketType::KillAvatar, this, "handleKillAvatarPacket");
|
||||
packetReceiver.registerListener(PacketType::NodeMuteRequest, this, "handleNodeMuteRequestPacket");
|
||||
packetReceiver.registerListener(PacketType::RadiusIgnoreRequest, this, "handleRadiusIgnoreRequestPacket");
|
||||
packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket");
|
||||
packetReceiver.registerListener(PacketType::RequestsDomainListData, this, "handleRequestsDomainListDataPacket");
|
||||
packetReceiver.registerListener(PacketType::PerAvatarGainSet, this, "handlePerAvatarGainSetDataPacket");
|
||||
|
||||
connect(nodeList.data(), &NodeList::nodeKilled, this, &AudioMixer::handleNodeKilled);
|
||||
|
|
|
@ -1089,9 +1089,9 @@
|
|||
{
|
||||
"name": "noise_muting_threshold",
|
||||
"label": "Noise Muting Threshold",
|
||||
"help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute)",
|
||||
"placeholder": "0.003",
|
||||
"default": "0.003",
|
||||
"help": "Loudness value for noise background between 0 and 1.0 (0: mute everyone, 1.0: never mute). 0.003 is a typical setting to mute loud people.",
|
||||
"placeholder": "1.0",
|
||||
"default": "1.0",
|
||||
"advanced": false
|
||||
},
|
||||
{
|
||||
|
|
|
@ -85,19 +85,6 @@ namespace render {
|
|||
}
|
||||
}
|
||||
|
||||
static uint64_t timeProcessingJoints = 0;
|
||||
static int32_t numJointsProcessed = 0;
|
||||
|
||||
float Avatar::getNumJointsProcessedPerSecond() {
|
||||
float rate = 0.0f;
|
||||
if (timeProcessingJoints > 0) {
|
||||
rate = (float)(numJointsProcessed * USECS_PER_SECOND) / (float)timeProcessingJoints;
|
||||
}
|
||||
timeProcessingJoints = 0;
|
||||
numJointsProcessed = 0;
|
||||
return rate;
|
||||
}
|
||||
|
||||
Avatar::Avatar(RigPointer rig) :
|
||||
AvatarData(),
|
||||
_skeletonOffset(0.0f),
|
||||
|
@ -127,6 +114,7 @@ Avatar::Avatar(RigPointer rig) :
|
|||
_nameRectGeometryID = geometryCache->allocateID();
|
||||
_leftPointerGeometryID = geometryCache->allocateID();
|
||||
_rightPointerGeometryID = geometryCache->allocateID();
|
||||
_lastRenderUpdateTime = usecTimestampNow();
|
||||
}
|
||||
|
||||
Avatar::~Avatar() {
|
||||
|
@ -187,25 +175,35 @@ AABox Avatar::getBounds() const {
|
|||
}
|
||||
|
||||
void Avatar::animateScaleChanges(float deltaTime) {
|
||||
float currentScale = getUniformScale();
|
||||
auto desiredScale = getDomainLimitedScale();
|
||||
if (currentScale != desiredScale) {
|
||||
if (_isAnimatingScale) {
|
||||
float currentScale = getUniformScale();
|
||||
float desiredScale = getDomainLimitedScale();
|
||||
|
||||
// use exponential decay toward the domain limit clamped scale
|
||||
const float SCALE_ANIMATION_TIMESCALE = 0.5f;
|
||||
float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f);
|
||||
float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * desiredScale;
|
||||
|
||||
// snap to the end when we get close enough
|
||||
const float MIN_RELATIVE_SCALE_ERROR = 0.03f;
|
||||
if (fabsf(desiredScale - currentScale) / desiredScale < MIN_RELATIVE_SCALE_ERROR) {
|
||||
const float MIN_RELATIVE_ERROR = 0.03f;
|
||||
float relativeError = fabsf(desiredScale - currentScale) / desiredScale;
|
||||
if (relativeError < MIN_RELATIVE_ERROR) {
|
||||
animatedScale = desiredScale;
|
||||
_isAnimatingScale = false;
|
||||
}
|
||||
|
||||
setScale(glm::vec3(animatedScale)); // avatar scale is uniform
|
||||
|
||||
// TODO: rebuilding the shape constantly is somehwat expensive.
|
||||
// We should only rebuild after significant change.
|
||||
rebuildCollisionShape();
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::setTargetScale(float targetScale) {
|
||||
AvatarData::setTargetScale(targetScale);
|
||||
_isAnimatingScale = true;
|
||||
}
|
||||
|
||||
void Avatar::updateAvatarEntities() {
|
||||
PerformanceTimer perfTimer("attachments");
|
||||
// - if queueEditEntityMessage sees clientOnly flag it does _myAvatar->updateAvatarEntity()
|
||||
|
@ -302,63 +300,23 @@ void Avatar::updateAvatarEntities() {
|
|||
}
|
||||
}
|
||||
|
||||
void Avatar::setShouldDie() {
|
||||
// This will cause the avatar to be shrunk away and removed (the actual Avatar gets removed), but then it comes back.
|
||||
_owningAvatarMixer.clear();
|
||||
bool Avatar::shouldDie() const {
|
||||
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
|
||||
return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS;
|
||||
}
|
||||
|
||||
void Avatar::simulate(float deltaTime) {
|
||||
void Avatar::simulate(float deltaTime, bool inView) {
|
||||
PROFILE_RANGE(simulation, "simulate");
|
||||
PerformanceTimer perfTimer("simulate");
|
||||
|
||||
if (!isDead() && !_motionState) {
|
||||
DependencyManager::get<AvatarManager>()->addAvatarToSimulation(this);
|
||||
}
|
||||
animateScaleChanges(deltaTime);
|
||||
|
||||
bool avatarInView = false;
|
||||
{ // update the shouldAnimate flag to match whether or not we will render the avatar.
|
||||
PerformanceTimer perfTimer("cull");
|
||||
{
|
||||
// simple frustum check
|
||||
PerformanceTimer perfTimer("inView");
|
||||
ViewFrustum viewFrustum;
|
||||
qApp->copyDisplayViewFrustum(viewFrustum);
|
||||
avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius())
|
||||
|| viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound());
|
||||
}
|
||||
PerformanceTimer lodPerfTimer("LOD");
|
||||
if (avatarInView) {
|
||||
const float MINIMUM_VISIBILITY_FOR_ON = 0.4f;
|
||||
const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f;
|
||||
ViewFrustum viewFrustum;
|
||||
qApp->copyViewFrustum(viewFrustum);
|
||||
float visibility = calculateRenderAccuracy(viewFrustum.getPosition(),
|
||||
getBounds(), DependencyManager::get<LODManager>()->getOctreeSizeScale());
|
||||
if (!_shouldAnimate) {
|
||||
if (visibility > MINIMUM_VISIBILITY_FOR_ON) {
|
||||
_shouldAnimate = true;
|
||||
qCDebug(interfaceapp) << "Restoring" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility;
|
||||
}
|
||||
} else if (visibility < MAXIMUM_VISIBILITY_FOR_OFF) {
|
||||
_shouldAnimate = false;
|
||||
qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t start = usecTimestampNow();
|
||||
// CRUFT? _shouldSkipRender is never set 'true'
|
||||
if (_shouldAnimate && avatarInView && !_shouldSkipRender) {
|
||||
{
|
||||
PerformanceTimer perfTimer("skeleton");
|
||||
{
|
||||
PROFILE_RANGE(simulation, "updateJoints");
|
||||
if (inView && _hasNewJointData) {
|
||||
_skeletonModel->getRig()->copyJointsFromJointData(_jointData);
|
||||
_skeletonModel->simulate(deltaTime, _hasNewJointRotations || _hasNewJointTranslations);
|
||||
_skeletonModel->simulate(deltaTime, true);
|
||||
|
||||
locationChanged(); // joints changed, so if there are any children, update them.
|
||||
_hasNewJointRotations = false;
|
||||
_hasNewJointTranslations = false;
|
||||
}
|
||||
{
|
||||
PerformanceTimer perfTimer("head");
|
||||
_hasNewJointData = false;
|
||||
|
||||
glm::vec3 headPosition = getPosition();
|
||||
if (!_skeletonModel->getHeadPosition(headPosition)) {
|
||||
headPosition = getPosition();
|
||||
|
@ -366,16 +324,12 @@ void Avatar::simulate(float deltaTime) {
|
|||
Head* head = getHead();
|
||||
head->setPosition(headPosition);
|
||||
head->setScale(getUniformScale());
|
||||
head->simulate(deltaTime, false, !_shouldAnimate);
|
||||
head->simulate(deltaTime, false);
|
||||
} else {
|
||||
// a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated.
|
||||
_skeletonModel->simulate(deltaTime, false);
|
||||
}
|
||||
} else {
|
||||
// a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated.
|
||||
getHead()->setPosition(getPosition());
|
||||
PerformanceTimer perfTimer("skeleton");
|
||||
_skeletonModel->simulate(deltaTime, false);
|
||||
}
|
||||
timeProcessingJoints += usecTimestampNow() - start;
|
||||
numJointsProcessed += _jointData.size();
|
||||
|
||||
// update animation for display name fade in/out
|
||||
if ( _displayNameTargetAlpha != _displayNameAlpha) {
|
||||
|
@ -394,11 +348,13 @@ void Avatar::simulate(float deltaTime) {
|
|||
_displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha;
|
||||
}
|
||||
|
||||
measureMotionDerivatives(deltaTime);
|
||||
|
||||
simulateAttachments(deltaTime);
|
||||
updatePalms();
|
||||
updateAvatarEntities();
|
||||
{
|
||||
PROFILE_RANGE(simulation, "misc");
|
||||
measureMotionDerivatives(deltaTime);
|
||||
simulateAttachments(deltaTime);
|
||||
updatePalms();
|
||||
updateAvatarEntities();
|
||||
}
|
||||
}
|
||||
|
||||
bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const {
|
||||
|
@ -1106,7 +1062,7 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
if (_moving && _motionState) {
|
||||
_motionState->addDirtyFlags(Simulation::DIRTY_POSITION);
|
||||
}
|
||||
if (_moving || _hasNewJointRotations || _hasNewJointTranslations) {
|
||||
if (_moving || _hasNewJointData) {
|
||||
locationChanged();
|
||||
}
|
||||
|
||||
|
|
|
@ -58,8 +58,6 @@ class Avatar : public AvatarData {
|
|||
Q_PROPERTY(glm::vec3 skeletonOffset READ getSkeletonOffset WRITE setSkeletonOffset)
|
||||
|
||||
public:
|
||||
static float getNumJointsProcessedPerSecond();
|
||||
|
||||
explicit Avatar(RigPointer rig = nullptr);
|
||||
~Avatar();
|
||||
|
||||
|
@ -68,7 +66,7 @@ public:
|
|||
|
||||
void init();
|
||||
void updateAvatarEntities();
|
||||
void simulate(float deltaTime);
|
||||
void simulate(float deltaTime, bool inView);
|
||||
virtual void simulateAttachments(float deltaTime);
|
||||
|
||||
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPosition);
|
||||
|
@ -141,8 +139,6 @@ public:
|
|||
|
||||
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
||||
|
||||
Q_INVOKABLE bool getShouldRender() const { return !_shouldSkipRender; }
|
||||
|
||||
/// Scales a world space position vector relative to the avatar position and scale
|
||||
/// \param vector position to be scaled. Will store the result
|
||||
void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const;
|
||||
|
@ -179,7 +175,12 @@ public:
|
|||
glm::vec3 getUncachedRightPalmPosition() const;
|
||||
glm::quat getUncachedRightPalmRotation() const;
|
||||
|
||||
Q_INVOKABLE void setShouldDie();
|
||||
uint64_t getLastRenderUpdateTime() const { return _lastRenderUpdateTime; }
|
||||
void setLastRenderUpdateTime(uint64_t time) { _lastRenderUpdateTime = time; }
|
||||
|
||||
bool shouldDie() const;
|
||||
void animateScaleChanges(float deltaTime);
|
||||
void setTargetScale(float targetScale) override;
|
||||
|
||||
public slots:
|
||||
|
||||
|
@ -230,8 +231,6 @@ protected:
|
|||
// protected methods...
|
||||
bool isLookingAtMe(AvatarSharedPointer avatar) const;
|
||||
|
||||
virtual void animateScaleChanges(float deltaTime);
|
||||
|
||||
glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
|
||||
glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; }
|
||||
glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
||||
|
@ -261,14 +260,14 @@ protected:
|
|||
void ensureInScene(AvatarSharedPointer self);
|
||||
|
||||
private:
|
||||
uint64_t _lastRenderUpdateTime { 0 };
|
||||
int _leftPointerGeometryID { 0 };
|
||||
int _rightPointerGeometryID { 0 };
|
||||
int _nameRectGeometryID { 0 };
|
||||
bool _initialized;
|
||||
bool _shouldAnimate { true };
|
||||
bool _shouldSkipRender { false };
|
||||
bool _isLookAtTarget { false };
|
||||
bool _inScene { false };
|
||||
bool _isAnimatingScale { false };
|
||||
|
||||
float getBoundingRadius() const;
|
||||
|
||||
|
|
|
@ -137,53 +137,131 @@ float AvatarManager::getAvatarDataRate(const QUuid& sessionID, const QString& ra
|
|||
return avatar->getDataRate(rateName);
|
||||
}
|
||||
|
||||
class AvatarPriority {
|
||||
public:
|
||||
AvatarPriority(AvatarSharedPointer a, float p) : avatar(a), priority(p) {}
|
||||
AvatarSharedPointer avatar;
|
||||
float priority;
|
||||
// NOTE: we invert the less-than operator to sort high priorities to front
|
||||
bool operator<(const AvatarPriority& other) const { return priority > other.priority; }
|
||||
};
|
||||
|
||||
void AvatarManager::updateOtherAvatars(float deltaTime) {
|
||||
// lock the hash for read to check the size
|
||||
QReadLocker lock(&_hashLock);
|
||||
|
||||
if (_avatarHash.size() < 2 && _avatarFades.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
|
||||
|
||||
PerformanceTimer perfTimer("otherAvatars");
|
||||
render::PendingChanges pendingChanges;
|
||||
uint64_t startTime = usecTimestampNow();
|
||||
|
||||
// simulate avatars
|
||||
auto hashCopy = getHashCopy();
|
||||
auto avatarMap = getHashCopy();
|
||||
QList<AvatarSharedPointer> avatarList = avatarMap.values();
|
||||
ViewFrustum cameraView;
|
||||
qApp->copyDisplayViewFrustum(cameraView);
|
||||
glm::vec3 frustumCenter = cameraView.getPosition();
|
||||
|
||||
uint64_t start = usecTimestampNow();
|
||||
AvatarHash::iterator avatarIterator = hashCopy.begin();
|
||||
while (avatarIterator != hashCopy.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
||||
const float OUT_OF_VIEW_PENALTY = -10.0;
|
||||
|
||||
if (avatar == _myAvatar || !avatar->isInitialized()) {
|
||||
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
||||
// DO NOT update or fade out uninitialized Avatars
|
||||
++avatarIterator;
|
||||
} else if (avatar->shouldDie()) {
|
||||
removeAvatar(avatarIterator.key());
|
||||
++avatarIterator;
|
||||
} else {
|
||||
avatar->ensureInScene(avatar);
|
||||
avatar->simulate(deltaTime);
|
||||
++avatarIterator;
|
||||
std::priority_queue<AvatarPriority> sortedAvatars;
|
||||
{
|
||||
PROFILE_RANGE(simulation, "sort");
|
||||
for (int32_t i = 0; i < avatarList.size(); ++i) {
|
||||
const auto& avatar = std::static_pointer_cast<Avatar>(avatarList.at(i));
|
||||
if (avatar == _myAvatar || !avatar->isInitialized()) {
|
||||
// DO NOT update _myAvatar! Its update has already been done earlier in the main loop.
|
||||
// DO NOT update or fade out uninitialized Avatars
|
||||
continue;
|
||||
}
|
||||
if (avatar->shouldDie()) {
|
||||
removeAvatar(avatar->getID());
|
||||
continue;
|
||||
}
|
||||
if (avatar->isDead()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
avatar->updateRenderItem(pendingChanges);
|
||||
// priority = weighted linear combination of:
|
||||
// (a) apparentSize
|
||||
// (b) proximity to center of view
|
||||
// (c) time since last update
|
||||
// (d) TIME_PENALTY to help recently updated entries sort toward back
|
||||
glm::vec3 avatarPosition = avatar->getPosition();
|
||||
glm::vec3 offset = avatarPosition - frustumCenter;
|
||||
float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero
|
||||
float radius = avatar->getBoundingRadius();
|
||||
const glm::vec3& forward = cameraView.getDirection();
|
||||
float apparentSize = radius / distance;
|
||||
float cosineAngle = glm::length(offset - glm::dot(offset, forward) * forward) / distance;
|
||||
const float TIME_PENALTY = 0.080f; // seconds
|
||||
float age = (float)(startTime - avatar->getLastRenderUpdateTime()) / (float)(USECS_PER_SECOND) - TIME_PENALTY;
|
||||
// NOTE: we are adding values of different units to get a single measure of "priority".
|
||||
// Thus we multiply each component by a conversion "weight" that scales its units
|
||||
// relative to the others. These weights are pure magic tuning and are hard coded in the
|
||||
// relation below: (hint: unitary weights are not explicityly shown)
|
||||
float priority = apparentSize + 0.25f * cosineAngle + age;
|
||||
|
||||
// decrement priority of avatars outside keyhole
|
||||
if (distance > cameraView.getCenterRadius()) {
|
||||
if (!cameraView.sphereIntersectsFrustum(avatarPosition, radius)) {
|
||||
priority += OUT_OF_VIEW_PENALTY;
|
||||
}
|
||||
}
|
||||
sortedAvatars.push(AvatarPriority(avatar, priority));
|
||||
}
|
||||
}
|
||||
|
||||
render::PendingChanges pendingChanges;
|
||||
const uint64_t RENDER_UPDATE_BUDGET = 1500; // usec
|
||||
const uint64_t MAX_UPDATE_BUDGET = 2000; // usec
|
||||
uint64_t renderExpiry = startTime + RENDER_UPDATE_BUDGET;
|
||||
uint64_t maxExpiry = startTime + MAX_UPDATE_BUDGET;
|
||||
while (!sortedAvatars.empty()) {
|
||||
const AvatarPriority& sortData = sortedAvatars.top();
|
||||
const auto& avatar = std::static_pointer_cast<Avatar>(sortData.avatar);
|
||||
|
||||
// for ALL avatars...
|
||||
avatar->ensureInScene(avatar);
|
||||
if (!avatar->getMotionState()) {
|
||||
ShapeInfo shapeInfo;
|
||||
avatar->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||
if (shape) {
|
||||
// don't add to the simulation now, instead put it on a list to be added later
|
||||
AvatarMotionState* motionState = new AvatarMotionState(avatar.get(), shape);
|
||||
avatar->setMotionState(motionState);
|
||||
_motionStatesToAddToPhysics.insert(motionState);
|
||||
_motionStatesThatMightUpdate.insert(motionState);
|
||||
}
|
||||
}
|
||||
avatar->animateScaleChanges(deltaTime);
|
||||
|
||||
uint64_t now = usecTimestampNow();
|
||||
if (now < renderExpiry) {
|
||||
// we're within budget
|
||||
const float OUT_OF_VIEW_THRESHOLD = 0.5f * OUT_OF_VIEW_PENALTY;
|
||||
bool inView = sortData.priority > OUT_OF_VIEW_THRESHOLD;
|
||||
avatar->simulate(deltaTime, inView);
|
||||
avatar->updateRenderItem(pendingChanges);
|
||||
avatar->setLastRenderUpdateTime(startTime);
|
||||
} else if (now < maxExpiry) {
|
||||
// we've spent most of our time budget, but we still simulate() the avatar as it if were out of view
|
||||
// --> some avatars may freeze until their priority trickles up
|
||||
const bool inView = false;
|
||||
avatar->simulate(deltaTime, inView);
|
||||
} else {
|
||||
// we've spent ALL of our time budget --> bail on the rest of the avatar updates
|
||||
// --> some scale or fade animations may glitch
|
||||
// --> some avatar velocity measurements may be a little off
|
||||
break;
|
||||
}
|
||||
sortedAvatars.pop();
|
||||
}
|
||||
qApp->getMain3DScene()->enqueuePendingChanges(pendingChanges);
|
||||
|
||||
// simulate avatar fades
|
||||
simulateAvatarFades(deltaTime);
|
||||
|
||||
PROFILE_COUNTER(simulation_avatar, "NumAvatarsPerSec",
|
||||
{ { "NumAvatarsPerSec", (float)(size() * USECS_PER_SECOND) / (float)(usecTimestampNow() - start) } });
|
||||
PROFILE_COUNTER(simulation_avatar, "NumJointsPerSec", { { "NumJointsPerSec", Avatar::getNumJointsProcessedPerSecond() } });
|
||||
}
|
||||
|
||||
void AvatarManager::postUpdate(float deltaTime) {
|
||||
|
@ -206,6 +284,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
|
|||
while (fadingIterator != _avatarFades.end()) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(*fadingIterator);
|
||||
avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE);
|
||||
avatar->animateScaleChanges(deltaTime);
|
||||
if (avatar->getTargetScale() <= MIN_FADE_SCALE) {
|
||||
avatar->removeFromScene(*fadingIterator, scene, pendingChanges);
|
||||
// only remove from _avatarFades if we're sure its motionState has been removed from PhysicsEngine
|
||||
|
@ -215,7 +294,8 @@ void AvatarManager::simulateAvatarFades(float deltaTime) {
|
|||
++fadingIterator;
|
||||
}
|
||||
} else {
|
||||
avatar->simulate(deltaTime);
|
||||
const bool inView = true; // HACK
|
||||
avatar->simulate(deltaTime, inView);
|
||||
++fadingIterator;
|
||||
}
|
||||
}
|
||||
|
@ -391,21 +471,6 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarManager::addAvatarToSimulation(Avatar* avatar) {
|
||||
assert(!avatar->getMotionState());
|
||||
|
||||
ShapeInfo shapeInfo;
|
||||
avatar->computeShapeInfo(shapeInfo);
|
||||
btCollisionShape* shape = const_cast<btCollisionShape*>(ObjectMotionState::getShapeManager()->getShape(shapeInfo));
|
||||
if (shape) {
|
||||
// we don't add to the simulation now, we put it on a list to be added later
|
||||
AvatarMotionState* motionState = new AvatarMotionState(avatar, shape);
|
||||
avatar->setMotionState(motionState);
|
||||
_motionStatesToAddToPhysics.insert(motionState);
|
||||
_motionStatesThatMightUpdate.insert(motionState);
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) {
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars()) {
|
||||
for (auto avatarData : _avatarHash) {
|
||||
|
|
|
@ -69,8 +69,6 @@ public:
|
|||
void handleOutgoingChanges(const VectorOfMotionStates& motionStates);
|
||||
void handleCollisionEvents(const CollisionEvents& collisionEvents);
|
||||
|
||||
void addAvatarToSimulation(Avatar* avatar);
|
||||
|
||||
Q_INVOKABLE float getAvatarDataRate(const QUuid& sessionID, const QString& rateName = QString(""));
|
||||
Q_INVOKABLE RayToAvatarIntersectionResult findRayIntersection(const PickRay& ray,
|
||||
const QScriptValue& avatarIdsToInclude = QScriptValue(),
|
||||
|
|
|
@ -70,7 +70,7 @@ void Head::reset() {
|
|||
_baseYaw = _basePitch = _baseRoll = 0.0f;
|
||||
}
|
||||
|
||||
void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
||||
void Head::simulate(float deltaTime, bool isMine) {
|
||||
// Update audio trailing average for rendering facial animations
|
||||
const float AUDIO_AVERAGING_SECS = 0.05f;
|
||||
const float AUDIO_LONG_TERM_AVERAGING_SECS = 30.0f;
|
||||
|
@ -117,7 +117,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!(_isFaceTrackerConnected || billboard)) {
|
||||
if (!_isFaceTrackerConnected) {
|
||||
|
||||
if (!_isEyeTrackerConnected) {
|
||||
// Update eye saccades
|
||||
|
@ -220,7 +220,7 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
|
|||
_leftEyePosition = _rightEyePosition = getPosition();
|
||||
_eyePosition = getPosition();
|
||||
|
||||
if (!billboard && _owningAvatar) {
|
||||
if (_owningAvatar) {
|
||||
auto skeletonModel = static_cast<Avatar*>(_owningAvatar)->getSkeletonModel();
|
||||
if (skeletonModel) {
|
||||
skeletonModel->getEyePositions(_leftEyePosition, _rightEyePosition);
|
||||
|
@ -378,10 +378,6 @@ glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
|
|||
return rotationBetween(orientation * IDENTITY_FRONT, lookAtDelta + glm::length(lookAtDelta) * _saccade) * orientation;
|
||||
}
|
||||
|
||||
glm::vec3 Head::getScalePivot() const {
|
||||
return _position;
|
||||
}
|
||||
|
||||
void Head::setFinalPitch(float finalPitch) {
|
||||
_deltaPitch = glm::clamp(finalPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH) - _basePitch;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
|
||||
void init();
|
||||
void reset();
|
||||
void simulate(float deltaTime, bool isMine, bool billboard = false);
|
||||
void simulate(float deltaTime, bool isMine);
|
||||
void setScale(float scale);
|
||||
void setPosition(glm::vec3 position) { _position = position; }
|
||||
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
|
||||
|
@ -70,8 +70,6 @@ public:
|
|||
|
||||
bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
||||
float getAverageLoudness() const { return _averageLoudness; }
|
||||
/// \return the point about which scaling occurs.
|
||||
glm::vec3 getScalePivot() const;
|
||||
|
||||
void setDeltaPitch(float pitch) { _deltaPitch = pitch; }
|
||||
float getDeltaPitch() const { return _deltaPitch; }
|
||||
|
|
|
@ -220,15 +220,19 @@ void SkeletonModel::updateAttitude() {
|
|||
// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed),
|
||||
// but just before head has been simulated.
|
||||
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||
updateAttitude();
|
||||
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
|
||||
if (fullUpdate) {
|
||||
updateAttitude();
|
||||
setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients());
|
||||
|
||||
Model::simulate(deltaTime, fullUpdate);
|
||||
Model::simulate(deltaTime, fullUpdate);
|
||||
|
||||
// let rig compute the model offset
|
||||
glm::vec3 registrationPoint;
|
||||
if (_rig->getModelRegistrationPoint(registrationPoint)) {
|
||||
setOffset(registrationPoint);
|
||||
// let rig compute the model offset
|
||||
glm::vec3 registrationPoint;
|
||||
if (_rig->getModelRegistrationPoint(registrationPoint)) {
|
||||
setOffset(registrationPoint);
|
||||
}
|
||||
} else {
|
||||
Model::simulate(deltaTime, fullUpdate);
|
||||
}
|
||||
|
||||
if (!isActive() || !_owningAvatar->isMyAvatar()) {
|
||||
|
|
|
@ -253,6 +253,16 @@ int WindowScriptingInterface::createMessageBox(QString title, QString text, int
|
|||
void WindowScriptingInterface::updateMessageBox(int id, QString title, QString text, int buttons, int defaultButton) {
|
||||
auto messageBox = _messageBoxes.value(id);
|
||||
if (messageBox) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updateMessageBox",
|
||||
Q_ARG(int, id),
|
||||
Q_ARG(QString, title),
|
||||
Q_ARG(QString, text),
|
||||
Q_ARG(int, buttons),
|
||||
Q_ARG(int, defaultButton));
|
||||
return;
|
||||
}
|
||||
|
||||
messageBox->setProperty("title", title);
|
||||
messageBox->setProperty("text", text);
|
||||
messageBox->setProperty("buttons", buttons);
|
||||
|
@ -263,6 +273,12 @@ void WindowScriptingInterface::updateMessageBox(int id, QString title, QString t
|
|||
void WindowScriptingInterface::closeMessageBox(int id) {
|
||||
auto messageBox = _messageBoxes.value(id);
|
||||
if (messageBox) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "closeMessageBox",
|
||||
Q_ARG(int, id));
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect(messageBox);
|
||||
messageBox->setVisible(false);
|
||||
messageBox->deleteLater();
|
||||
|
|
|
@ -157,7 +157,7 @@ void setupPreferences() {
|
|||
}
|
||||
{
|
||||
auto getter = [=]()->float { return myAvatar->getUniformScale(); };
|
||||
auto setter = [=](float value) { myAvatar->setTargetScaleVerbose(value); }; // The hell?
|
||||
auto setter = [=](float value) { myAvatar->setTargetScale(value); };
|
||||
auto preference = new SpinnerPreference(AVATAR_TUNING, "Avatar scale (default is 1.0)", getter, setter);
|
||||
preference->setMin(0.01f);
|
||||
preference->setMax(99.9f);
|
||||
|
|
|
@ -1269,6 +1269,7 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
|||
|
||||
void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
||||
PerformanceTimer perfTimer("copyJoints");
|
||||
PROFILE_RANGE(simulation_animation_detail, "copyJoints");
|
||||
if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._relativePoses.size()) {
|
||||
// make a vector of rotations in absolute-geometry-frame
|
||||
const AnimPoseVec& absoluteDefaultPoses = _animSkeleton->getAbsoluteDefaultPoses();
|
||||
|
|
|
@ -63,8 +63,7 @@ AvatarData::AvatarData() :
|
|||
_handState(0),
|
||||
_keyState(NO_KEY_DOWN),
|
||||
_forceFaceTrackerConnected(false),
|
||||
_hasNewJointRotations(true),
|
||||
_hasNewJointTranslations(true),
|
||||
_hasNewJointData(true),
|
||||
_headData(NULL),
|
||||
_displayNameTargetAlpha(1.0f),
|
||||
_displayNameAlpha(1.0f),
|
||||
|
@ -134,11 +133,6 @@ void AvatarData::setTargetScale(float targetScale) {
|
|||
}
|
||||
}
|
||||
|
||||
void AvatarData::setTargetScaleVerbose(float targetScale) {
|
||||
setTargetScale(targetScale);
|
||||
qCDebug(avatars) << "Changed scale to " << _targetScale;
|
||||
}
|
||||
|
||||
glm::vec3 AvatarData::getHandPosition() const {
|
||||
return getOrientation() * _handPosition + getPosition();
|
||||
}
|
||||
|
@ -712,8 +706,9 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
glm::quat newOrientation;
|
||||
sourceBuffer += unpackOrientationQuatFromSixBytes(sourceBuffer, newOrientation);
|
||||
glm::quat currentOrientation = getLocalOrientation();
|
||||
|
||||
if (currentOrientation != newOrientation) {
|
||||
_hasNewJointRotations = true;
|
||||
_hasNewJointData = true;
|
||||
setLocalOrientation(newOrientation);
|
||||
}
|
||||
int numBytesRead = sourceBuffer - startSection;
|
||||
|
@ -978,7 +973,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
JointData& data = _jointData[i];
|
||||
if (validTranslations[i]) {
|
||||
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
||||
_hasNewJointTranslations = true;
|
||||
_hasNewJointData = true;
|
||||
data.translationSet = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,6 @@ const quint32 AVATAR_MOTION_SCRIPTABLE_BITS =
|
|||
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
|
||||
|
||||
|
||||
|
||||
// Bitset of state flags - we store the key state, hand state, Faceshift, eye tracking, and existence of
|
||||
// referential data in this bit set. The hand state is an octal, but is split into two sections to maintain
|
||||
// backward compatibility. The bits are ordered as such (0-7 left to right).
|
||||
|
@ -405,8 +404,7 @@ public:
|
|||
|
||||
// Scale
|
||||
float getTargetScale() const;
|
||||
void setTargetScale(float targetScale);
|
||||
void setTargetScaleVerbose(float targetScale);
|
||||
virtual void setTargetScale(float targetScale);
|
||||
|
||||
float getDomainLimitedScale() const { return glm::clamp(_targetScale, _domainMinimumScale, _domainMaximumScale); }
|
||||
|
||||
|
@ -513,8 +511,6 @@ public:
|
|||
|
||||
const glm::vec3& getTargetVelocity() const { return _targetVelocity; }
|
||||
|
||||
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
||||
|
||||
void clearRecordingBasis();
|
||||
TransformPointer getRecordingBasis() const;
|
||||
void setRecordingBasis(TransformPointer recordingBasis = TransformPointer());
|
||||
|
@ -600,8 +596,7 @@ protected:
|
|||
KeyState _keyState;
|
||||
|
||||
bool _forceFaceTrackerConnected;
|
||||
bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar
|
||||
bool _hasNewJointTranslations; // set in AvatarData, cleared in Avatar
|
||||
bool _hasNewJointData; // set in AvatarData, cleared in Avatar
|
||||
|
||||
HeadData* _headData;
|
||||
|
||||
|
|
|
@ -48,39 +48,18 @@ public:
|
|||
void update();
|
||||
uvec3 getPageCounts(const uvec3& dimensions) const;
|
||||
uint32_t getPageCount(const uvec3& dimensions) const;
|
||||
uint32_t getSize() const;
|
||||
|
||||
GL45Texture& texture;
|
||||
bool sparse { false };
|
||||
uvec3 pageDimensions { DEFAULT_PAGE_DIMENSION };
|
||||
GLuint maxSparseLevel { DEFAULT_MAX_SPARSE_LEVEL };
|
||||
uint32_t allocatedPages { 0 };
|
||||
uint32_t maxPages { 0 };
|
||||
uint32_t pageBytes { 0 };
|
||||
GLint pageDimensionsIndex { 0 };
|
||||
};
|
||||
|
||||
#if INCREMENTAL_TRANSFER
|
||||
struct TransferState {
|
||||
TransferState(GL45Texture& texture);
|
||||
uvec3 currentPageSize() const;
|
||||
void updateMip();
|
||||
void populatePage(std::vector<uint8_t>& dest);
|
||||
bool increment();
|
||||
|
||||
GL45Texture& texture;
|
||||
GLTexelFormat texelFormat;
|
||||
uint8_t face { 0 };
|
||||
uint16_t mipLevel { 0 };
|
||||
uint32_t bytesPerLine { 0 };
|
||||
uint32_t bytesPerPixel { 0 };
|
||||
uint32_t bytesPerPage { 0 };
|
||||
uvec3 mipDimensions;
|
||||
uvec3 mipOffset;
|
||||
const uint8_t* srcPointer { nullptr };
|
||||
};
|
||||
protected:
|
||||
TransferState _transferState;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
void updateMips() override;
|
||||
void stripToMip(uint16_t newMinMip);
|
||||
|
@ -98,8 +77,6 @@ public:
|
|||
void derez();
|
||||
|
||||
SparseInfo _sparseInfo;
|
||||
uint32_t _allocatedPages { 0 };
|
||||
uint32_t _lastMipAllocatedPages { 0 };
|
||||
uint16_t _mipOffset { 0 };
|
||||
friend class GL45Backend;
|
||||
};
|
||||
|
|
|
@ -116,6 +116,8 @@ void SparseInfo::maybeMakeSparse() {
|
|||
}
|
||||
}
|
||||
|
||||
#define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f
|
||||
|
||||
// This can only be called after we've established our storage size
|
||||
void SparseInfo::update() {
|
||||
if (!sparse) {
|
||||
|
@ -124,6 +126,9 @@ void SparseInfo::update() {
|
|||
glGetTextureParameterIuiv(texture._id, GL_NUM_SPARSE_LEVELS_ARB, &maxSparseLevel);
|
||||
pageBytes = texture._gpuObject.getTexelFormat().getSize();
|
||||
pageBytes *= pageDimensions.x * pageDimensions.y * pageDimensions.z;
|
||||
// Testing with a simple texture allocating app shows an estimated 20% GPU memory overhead for
|
||||
// sparse textures as compared to non-sparse, so we acount for that here.
|
||||
pageBytes = (uint32_t)(pageBytes * SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE);
|
||||
|
||||
for (uint16_t mipLevel = 0; mipLevel <= maxSparseLevel; ++mipLevel) {
|
||||
auto mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel);
|
||||
|
@ -146,6 +151,11 @@ uint32_t SparseInfo::getPageCount(const uvec3& dimensions) const {
|
|||
return pageCounts.x * pageCounts.y * pageCounts.z;
|
||||
}
|
||||
|
||||
|
||||
uint32_t SparseInfo::getSize() const {
|
||||
return allocatedPages * pageBytes;
|
||||
}
|
||||
|
||||
void GL45Backend::initTextureManagementStage() {
|
||||
// enable the Sparse Texture on gl45
|
||||
_textureManagement._sparseCapable = true;
|
||||
|
@ -160,93 +170,6 @@ void GL45Backend::initTextureManagementStage() {
|
|||
}
|
||||
}
|
||||
|
||||
#if INCREMENTAL_TRANSFER
|
||||
|
||||
using TransferState = GL45Backend::GL45Texture::TransferState;
|
||||
|
||||
TransferState::TransferState(GL45Texture& texture) : texture(texture) {
|
||||
}
|
||||
|
||||
void TransferState::updateMip() {
|
||||
mipDimensions = texture._gpuObject.evalMipDimensions(mipLevel);
|
||||
mipOffset = uvec3();
|
||||
if (!texture._gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
|
||||
srcPointer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto mip = texture._gpuObject.accessStoredMipFace(mipLevel, face);
|
||||
texelFormat = gl::GLTexelFormat::evalGLTexelFormat(texture._gpuObject.getTexelFormat(), mip->getFormat());
|
||||
srcPointer = mip->readData();
|
||||
bytesPerLine = (uint32_t)mip->getSize() / mipDimensions.y;
|
||||
bytesPerPixel = bytesPerLine / mipDimensions.x;
|
||||
}
|
||||
|
||||
bool TransferState::increment() {
|
||||
const SparseInfo& sparse = texture._sparseInfo;
|
||||
if ((mipOffset.x + sparse.pageDimensions.x) < mipDimensions.x) {
|
||||
mipOffset.x += sparse.pageDimensions.x;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((mipOffset.y + sparse.pageDimensions.y) < mipDimensions.y) {
|
||||
mipOffset.x = 0;
|
||||
mipOffset.y += sparse.pageDimensions.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mipOffset.z + sparse.pageDimensions.z < mipDimensions.z) {
|
||||
mipOffset.x = 0;
|
||||
mipOffset.y = 0;
|
||||
++mipOffset.z;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Done with this mip?, move on to the next mip
|
||||
if (mipLevel + 1 < texture.usedMipLevels()) {
|
||||
mipOffset = uvec3(0);
|
||||
++mipLevel;
|
||||
updateMip();
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t maxFace = (uint8_t)((texture._target == GL_TEXTURE_CUBE_MAP) ? GLTexture::CUBE_NUM_FACES : 1);
|
||||
uint8_t nextFace = face + 1;
|
||||
// Done with this face? Move on to the next
|
||||
if (nextFace < maxFace) {
|
||||
++face;
|
||||
mipOffset = uvec3(0);
|
||||
mipLevel = 0;
|
||||
updateMip();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TransferState::populatePage(std::vector<uint8_t>& buffer) {
|
||||
uvec3 pageSize = currentPageSize();
|
||||
auto bytesPerPageLine = bytesPerPixel * pageSize.x;
|
||||
if (0 != (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT)) {
|
||||
bytesPerPageLine += DEFAULT_GL_PIXEL_ALIGNMENT - (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT);
|
||||
assert(0 == (bytesPerPageLine % DEFAULT_GL_PIXEL_ALIGNMENT));
|
||||
}
|
||||
auto totalPageSize = bytesPerPageLine * pageSize.y;
|
||||
if (totalPageSize > buffer.size()) {
|
||||
buffer.resize(totalPageSize);
|
||||
}
|
||||
uint8_t* dst = &buffer[0];
|
||||
for (uint32_t y = 0; y < pageSize.y; ++y) {
|
||||
uint32_t srcOffset = (bytesPerLine * (mipOffset.y + y)) + (bytesPerPixel * mipOffset.x);
|
||||
uint32_t dstOffset = bytesPerPageLine * y;
|
||||
memcpy(dst + dstOffset, srcPointer + srcOffset, pageSize.x * bytesPerPixel);
|
||||
}
|
||||
}
|
||||
|
||||
uvec3 TransferState::currentPageSize() const {
|
||||
return glm::clamp(mipDimensions - mipOffset, uvec3(1), texture._sparseInfo.pageDimensions);
|
||||
}
|
||||
#endif
|
||||
|
||||
GLuint GL45Texture::allocate(const Texture& texture) {
|
||||
GLuint result;
|
||||
|
@ -260,17 +183,11 @@ GLuint GL45Backend::getTextureID(const TexturePointer& texture, bool transfer) {
|
|||
|
||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, GLuint externalId)
|
||||
: GLTexture(backend, texture, externalId), _sparseInfo(*this)
|
||||
#if INCREMENTAL_TRANSFER
|
||||
, _transferState(*this)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture, bool transferrable)
|
||||
: GLTexture(backend, texture, allocate(texture), transferrable), _sparseInfo(*this)
|
||||
#if INCREMENTAL_TRANSFER
|
||||
, _transferState(*this)
|
||||
#endif
|
||||
{
|
||||
|
||||
auto theBackend = _backend.lock();
|
||||
|
@ -316,12 +233,12 @@ GL45Texture::~GL45Texture() {
|
|||
});
|
||||
|
||||
auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace;
|
||||
assert(deallocatedPages <= _allocatedPages);
|
||||
_allocatedPages -= deallocatedPages;
|
||||
assert(deallocatedPages <= _sparseInfo.allocatedPages);
|
||||
_sparseInfo.allocatedPages -= deallocatedPages;
|
||||
}
|
||||
|
||||
if (0 != _allocatedPages) {
|
||||
qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _allocatedPages;
|
||||
if (0 != _sparseInfo.allocatedPages) {
|
||||
qCWarning(gpugl45logging) << "Allocated pages remaining " << _id << " " << _sparseInfo.allocatedPages;
|
||||
}
|
||||
|
||||
auto size = _size;
|
||||
|
@ -365,9 +282,9 @@ void GL45Texture::updateSize() const {
|
|||
}
|
||||
|
||||
if (_transferrable && _sparseInfo.sparse) {
|
||||
auto size = _allocatedPages * _sparseInfo.pageBytes;
|
||||
auto size = _sparseInfo.getSize();
|
||||
Backend::updateTextureGPUSparseMemoryUsage(_size, size);
|
||||
setSize(_allocatedPages * _sparseInfo.pageBytes);
|
||||
setSize(size);
|
||||
} else {
|
||||
setSize(_gpuObject.evalTotalSize(_mipOffset));
|
||||
}
|
||||
|
@ -376,20 +293,16 @@ void GL45Texture::updateSize() const {
|
|||
void GL45Texture::startTransfer() {
|
||||
Parent::startTransfer();
|
||||
_sparseInfo.update();
|
||||
#if INCREMENTAL_TRANSFER
|
||||
_transferState.updateMip();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool GL45Texture::continueTransfer() {
|
||||
#if !INCREMENTAL_TRANSFER
|
||||
size_t maxFace = GL_TEXTURE_CUBE_MAP == _target ? CUBE_NUM_FACES : 1;
|
||||
for (uint8_t face = 0; face < maxFace; ++face) {
|
||||
for (uint16_t mipLevel = _minMip; mipLevel <= _maxMip; ++mipLevel) {
|
||||
auto size = _gpuObject.evalMipDimensions(mipLevel);
|
||||
if (_sparseInfo.sparse && mipLevel <= _sparseInfo.maxSparseLevel) {
|
||||
glTexturePageCommitmentEXT(_id, mipLevel, 0, 0, face, size.x, size.y, 1, GL_TRUE);
|
||||
_allocatedPages += _sparseInfo.getPageCount(size);
|
||||
_sparseInfo.allocatedPages += _sparseInfo.getPageCount(size);
|
||||
}
|
||||
if (_gpuObject.isStoredMipFaceAvailable(mipLevel, face)) {
|
||||
auto mip = _gpuObject.accessStoredMipFace(mipLevel, face);
|
||||
|
@ -413,58 +326,6 @@ bool GL45Texture::continueTransfer() {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
static std::vector<uint8_t> buffer;
|
||||
if (buffer.empty()) {
|
||||
buffer.resize(DEFAULT_PAGE_BUFFER_SIZE);
|
||||
}
|
||||
const uvec3 pageSize = _transferState.currentPageSize();
|
||||
const uvec3& offset = _transferState.mipOffset;
|
||||
|
||||
if (_sparseInfo.sparse && _transferState.mipLevel <= _sparseInfo.maxSparseLevel) {
|
||||
if (_allocatedPages > _sparseInfo.maxPages) {
|
||||
qCWarning(gpugl45logging) << "Exceeded max page allocation!";
|
||||
}
|
||||
glTexturePageCommitmentEXT(_id, _transferState.mipLevel,
|
||||
offset.x, offset.y, _transferState.face,
|
||||
pageSize.x, pageSize.y, pageSize.z,
|
||||
GL_TRUE);
|
||||
++_allocatedPages;
|
||||
}
|
||||
|
||||
if (_transferState.srcPointer) {
|
||||
// Transfer the mip data
|
||||
_transferState.populatePage(buffer);
|
||||
if (GL_TEXTURE_2D == _target) {
|
||||
glTextureSubImage2D(_id, _transferState.mipLevel,
|
||||
offset.x, offset.y,
|
||||
pageSize.x, pageSize.y,
|
||||
_transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]);
|
||||
} else if (GL_TEXTURE_CUBE_MAP == _target) {
|
||||
auto target = CUBE_FACE_LAYOUT[_transferState.face];
|
||||
// DSA ARB does not work on AMD, so use EXT
|
||||
// glTextureSubImage3D(_id, mipLevel, 0, 0, face, size.x, size.y, 1, texelFormat.format, texelFormat.type, mip->readData());
|
||||
glTextureSubImage2DEXT(_id, target, _transferState.mipLevel,
|
||||
offset.x, offset.y,
|
||||
pageSize.x, pageSize.y,
|
||||
_transferState.texelFormat.format, _transferState.texelFormat.type, &buffer[0]);
|
||||
}
|
||||
}
|
||||
|
||||
serverWait();
|
||||
auto currentMip = _transferState.mipLevel;
|
||||
auto result = _transferState.increment();
|
||||
if (_sparseInfo.sparse && _transferState.mipLevel != currentMip && currentMip <= _sparseInfo.maxSparseLevel) {
|
||||
auto mipDimensions = _gpuObject.evalMipDimensions(currentMip);
|
||||
auto mipExpectedPages = _sparseInfo.getPageCount(mipDimensions);
|
||||
auto newPages = _allocatedPages - _lastMipAllocatedPages;
|
||||
if (newPages != mipExpectedPages) {
|
||||
qCWarning(gpugl45logging) << "Unexpected page allocation size... " << newPages << " " << mipExpectedPages;
|
||||
}
|
||||
_lastMipAllocatedPages = _allocatedPages;
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GL45Texture::finishTransfer() {
|
||||
|
@ -545,8 +406,8 @@ void GL45Texture::stripToMip(uint16_t newMinMip) {
|
|||
});
|
||||
|
||||
auto deallocatedPages = _sparseInfo.getPageCount(mipDimensions) * maxFace;
|
||||
assert(deallocatedPages < _allocatedPages);
|
||||
_allocatedPages -= deallocatedPages;
|
||||
assert(deallocatedPages < _sparseInfo.allocatedPages);
|
||||
_sparseInfo.allocatedPages -= deallocatedPages;
|
||||
}
|
||||
_minMip = newMinMip;
|
||||
} else {
|
||||
|
|
|
@ -272,8 +272,6 @@ void Model::reset() {
|
|||
}
|
||||
|
||||
bool Model::updateGeometry() {
|
||||
PROFILE_RANGE(render_detail, __FUNCTION__);
|
||||
PerformanceTimer perfTimer("Model::updateGeometry");
|
||||
bool needFullUpdate = false;
|
||||
|
||||
if (!isLoaded()) {
|
||||
|
@ -1128,7 +1126,9 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|
|||
if (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint) {
|
||||
snapToRegistrationPoint();
|
||||
}
|
||||
simulateInternal(deltaTime);
|
||||
// update the world space transforms for all joints
|
||||
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset);
|
||||
updateRig(deltaTime, parentTransform);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1138,12 +1138,6 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
_rig->updateAnimations(deltaTime, parentTransform);
|
||||
}
|
||||
|
||||
void Model::simulateInternal(float deltaTime) {
|
||||
// update the world space transforms for all joints
|
||||
glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset);
|
||||
updateRig(deltaTime, parentTransform);
|
||||
}
|
||||
|
||||
// virtual
|
||||
void Model::updateClusterMatrices() {
|
||||
PerformanceTimer perfTimer("Model::updateClusterMatrices");
|
||||
|
|
|
@ -312,7 +312,6 @@ protected:
|
|||
void scaleToFit();
|
||||
void snapToRegistrationPoint();
|
||||
|
||||
void simulateInternal(float deltaTime);
|
||||
virtual void updateRig(float deltaTime, glm::mat4 parentTransform);
|
||||
|
||||
/// Restores the indexed joint to its default position.
|
||||
|
|
|
@ -26,6 +26,8 @@ using SpatiallyNestableWeakConstPointer = std::weak_ptr<const SpatiallyNestable>
|
|||
using SpatiallyNestablePointer = std::shared_ptr<SpatiallyNestable>;
|
||||
using SpatiallyNestableConstPointer = std::shared_ptr<const SpatiallyNestable>;
|
||||
|
||||
static const uint16_t INVALID_JOINT_INDEX = -1;
|
||||
|
||||
enum class NestableType {
|
||||
Entity,
|
||||
Avatar,
|
||||
|
@ -184,7 +186,7 @@ protected:
|
|||
const NestableType _nestableType; // EntityItem or an AvatarData
|
||||
QUuid _id;
|
||||
QUuid _parentID; // what is this thing's transform relative to?
|
||||
quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to?
|
||||
quint16 _parentJointIndex { INVALID_JOINT_INDEX }; // which joint of the parent is this relative to?
|
||||
|
||||
mutable SpatiallyNestableWeakPointer _parent;
|
||||
|
||||
|
|
|
@ -729,7 +729,7 @@ void ViewFrustum::evalProjectionMatrix(glm::mat4& proj) const {
|
|||
glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar) const {
|
||||
|
||||
// make sure range near far make sense
|
||||
assert(rangeNear > 0.0);
|
||||
assert(rangeNear > 0.0f);
|
||||
assert(rangeFar > rangeNear);
|
||||
|
||||
// recreate a projection matrix for only a range of depth of this frustum.
|
||||
|
@ -738,7 +738,7 @@ glm::mat4 ViewFrustum::evalProjectionMatrixRange(float rangeNear, float rangeFar
|
|||
glm::mat4 rangeProj = _projection;
|
||||
|
||||
float A = -(rangeFar + rangeNear) / (rangeFar - rangeNear);
|
||||
float B = -2 * rangeFar*rangeNear / ((rangeFar - rangeNear));
|
||||
float B = -2.0f * rangeFar*rangeNear / ((rangeFar - rangeNear));
|
||||
|
||||
rangeProj[2][2] = A;
|
||||
rangeProj[3][2] = B;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
var canWriteAssets = false;
|
||||
var xmlHttpRequest = null;
|
||||
var isDownloading = false; // Explicitly track download request status.
|
||||
var isPreparing = false; // Explicitly track download request status.
|
||||
|
||||
function injectCommonCode(isDirectoryPage) {
|
||||
|
||||
|
@ -139,7 +139,7 @@
|
|||
function startAutoDownload() {
|
||||
|
||||
// One file request at a time.
|
||||
if (isDownloading) {
|
||||
if (isPreparing) {
|
||||
console.log("WARNIKNG: Clara.io FBX: Prepare only one download at a time");
|
||||
return;
|
||||
}
|
||||
|
@ -178,7 +178,7 @@
|
|||
var message = this.responseText.slice(responseTextIndex);
|
||||
var statusMessage = "";
|
||||
|
||||
if (isDownloading) { // Ignore messages in flight after finished/cancelled.
|
||||
if (isPreparing) { // Ignore messages in flight after finished/cancelled.
|
||||
var lines = message.split(/[\n\r]+/);
|
||||
|
||||
for (var i = 0, length = lines.length; i < length; i++) {
|
||||
|
@ -222,33 +222,30 @@
|
|||
xmlHttpRequest.onload = function () {
|
||||
var statusMessage = "";
|
||||
|
||||
if (!isDownloading) {
|
||||
if (!isPreparing) {
|
||||
return;
|
||||
}
|
||||
|
||||
isPreparing = false;
|
||||
|
||||
var HTTP_OK = 200;
|
||||
if (this.status !== HTTP_OK) {
|
||||
statusMessage = "Zip file request terminated with " + this.status + " " + this.statusText;
|
||||
console.log("ERROR: Clara.io FBX: " + statusMessage);
|
||||
EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (zipFileURL.slice(-4) !== ".zip") {
|
||||
} else if (zipFileURL.slice(-4) !== ".zip") {
|
||||
statusMessage = "Error creating zip file for download.";
|
||||
console.log("ERROR: Clara.io FBX: " + statusMessage + ": " + zipFileURL);
|
||||
EventBridge.emitWebEvent(CLARA_IO_STATUS + " " + statusMessage);
|
||||
return;
|
||||
} else {
|
||||
EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL);
|
||||
console.log("Clara.io FBX: File download initiated for " + zipFileURL);
|
||||
}
|
||||
|
||||
EventBridge.emitWebEvent(CLARA_IO_DOWNLOAD + " " + zipFileURL);
|
||||
console.log("Clara.io FBX: File download initiated for " + zipFileURL);
|
||||
|
||||
xmlHttpRequest = null;
|
||||
isDownloading = false;
|
||||
}
|
||||
|
||||
isDownloading = true;
|
||||
isPreparing = true;
|
||||
|
||||
console.log("Clara.io FBX: Request zip file for " + uuid);
|
||||
EventBridge.emitWebEvent(CLARA_IO_STATUS + " Initiating download");
|
||||
|
@ -301,7 +298,7 @@
|
|||
}
|
||||
|
||||
function cancelClaraDownload() {
|
||||
isDownloading = false;
|
||||
isPreparing = false;
|
||||
|
||||
if (xmlHttpRequest) {
|
||||
xmlHttpRequest.abort();
|
||||
|
|
Loading…
Reference in a new issue