mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 09:44:21 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into red
This commit is contained in:
commit
da158bcd85
27 changed files with 331 additions and 143 deletions
40
examples/moving-platform.js
Normal file
40
examples/moving-platform.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
var platform;
|
||||
|
||||
function init() {
|
||||
platform = Entities.addEntity({
|
||||
name: "platform",
|
||||
type: "Box",
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
dimensions: { x: 10, y: 2, z: 10 },
|
||||
color: { red: 0, green: 0, blue: 255 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
visible: true,
|
||||
locked: false,
|
||||
lifetime: 6000,
|
||||
velocity: { x: 1.0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
isDynamic: false
|
||||
});
|
||||
if (platform) {
|
||||
if (MyAvatar.getParentID() != platform) {
|
||||
MyAvatar.position = { x: 0, y: 3, z: 0 };
|
||||
MyAvatar.setParentID(platform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
if (platform) {
|
||||
MyAvatar.setParentID(0);
|
||||
Entities.deleteEntity(platform);
|
||||
}
|
||||
}
|
||||
|
||||
Script.setTimeout(init, 3000);
|
||||
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(shutdown);
|
|
@ -12,13 +12,13 @@
|
|||
#include "Application.h"
|
||||
|
||||
#include <gl/Config.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/component_wise.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <Qt>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QJsonDocument>
|
||||
#include <QtCore/QJsonObject>
|
||||
|
@ -27,6 +27,7 @@
|
|||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QAbstractNativeEventFilter>
|
||||
#include <QtCore/QMimeData>
|
||||
#include <QtCore/QThreadPool>
|
||||
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/QImage>
|
||||
|
@ -419,6 +420,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
|
||||
_lastFaceTrackerUpdate(0)
|
||||
{
|
||||
// FIXME this may be excessivly conservative. On the other hand
|
||||
// maybe I'm used to having an 8-core machine
|
||||
// Perhaps find the ideal thread count and subtract 2 or 3
|
||||
// (main thread, present thread, random OS load)
|
||||
// More threads == faster concurrent loads, but also more concurrent
|
||||
// load on the GPU until we can serialize GPU transfers (off the main thread)
|
||||
QThreadPool::globalInstance()->setMaxThreadCount(2);
|
||||
thread()->setPriority(QThread::HighPriority);
|
||||
thread()->setObjectName("Main Thread");
|
||||
|
||||
setInstance(this);
|
||||
|
@ -1287,6 +1296,9 @@ void Application::initializeUi() {
|
|||
}
|
||||
|
||||
void Application::paintGL() {
|
||||
|
||||
|
||||
|
||||
// paintGL uses a queued connection, so we can get messages from the queue even after we've quit
|
||||
// and the plugins have shutdown
|
||||
if (_aboutToQuit) {
|
||||
|
@ -4762,8 +4774,11 @@ void Application::updateDisplayMode() {
|
|||
foreach(auto displayPlugin, standard) {
|
||||
addDisplayPluginToMenu(displayPlugin, first);
|
||||
// This must be a queued connection to avoid a deadlock
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender,
|
||||
this, &Application::paintGL, Qt::QueuedConnection);
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, [=] {
|
||||
postEvent(this, new LambdaEvent([=] {
|
||||
paintGL();
|
||||
}), Qt::HighEventPriority);
|
||||
});
|
||||
|
||||
QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) {
|
||||
resizeGL();
|
||||
|
|
|
@ -86,9 +86,7 @@ Avatar::Avatar(RigPointer rig) :
|
|||
_positionDeltaAccumulator(0.0f),
|
||||
_lastVelocity(0.0f),
|
||||
_acceleration(0.0f),
|
||||
_angularVelocity(0.0f),
|
||||
_lastAngularVelocity(0.0f),
|
||||
_angularAcceleration(0.0f),
|
||||
_lastOrientation(),
|
||||
_leanScale(0.5f),
|
||||
_worldUpDirection(DEFAULT_UP_DIRECTION),
|
||||
|
@ -235,9 +233,6 @@ void Avatar::simulate(float deltaTime) {
|
|||
_displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha;
|
||||
}
|
||||
|
||||
// NOTE: we shouldn't extrapolate an Avatar instance forward in time...
|
||||
// until velocity is included in AvatarData update message.
|
||||
//_position += _velocity * deltaTime;
|
||||
measureMotionDerivatives(deltaTime);
|
||||
|
||||
simulateAttachments(deltaTime);
|
||||
|
@ -255,7 +250,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const {
|
|||
void Avatar::slamPosition(const glm::vec3& newPosition) {
|
||||
setPosition(newPosition);
|
||||
_positionDeltaAccumulator = glm::vec3(0.0f);
|
||||
_velocity = glm::vec3(0.0f);
|
||||
setVelocity(glm::vec3(0.0f));
|
||||
_lastVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
|
@ -269,15 +264,17 @@ void Avatar::measureMotionDerivatives(float deltaTime) {
|
|||
float invDeltaTime = 1.0f / deltaTime;
|
||||
// Floating point error prevents us from computing velocity in a naive way
|
||||
// (e.g. vel = (pos - oldPos) / dt) so instead we use _positionOffsetAccumulator.
|
||||
_velocity = _positionDeltaAccumulator * invDeltaTime;
|
||||
glm::vec3 velocity = _positionDeltaAccumulator * invDeltaTime;
|
||||
_positionDeltaAccumulator = glm::vec3(0.0f);
|
||||
_acceleration = (_velocity - _lastVelocity) * invDeltaTime;
|
||||
_lastVelocity = _velocity;
|
||||
_acceleration = (velocity - _lastVelocity) * invDeltaTime;
|
||||
_lastVelocity = velocity;
|
||||
setVelocity(velocity);
|
||||
|
||||
// angular
|
||||
glm::quat orientation = getOrientation();
|
||||
glm::quat delta = glm::inverse(_lastOrientation) * orientation;
|
||||
_angularVelocity = safeEulerAngles(delta) * invDeltaTime;
|
||||
_angularAcceleration = (_angularVelocity - _lastAngularVelocity) * invDeltaTime;
|
||||
glm::vec3 angularVelocity = glm::axis(delta) * glm::angle(delta) * invDeltaTime;
|
||||
setAngularVelocity(angularVelocity);
|
||||
_lastOrientation = getOrientation();
|
||||
}
|
||||
|
||||
|
|
|
@ -135,8 +135,6 @@ public:
|
|||
Q_INVOKABLE glm::vec3 getNeckPosition() const;
|
||||
|
||||
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
||||
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
||||
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
||||
|
||||
Q_INVOKABLE bool getShouldRender() const { return !_shouldSkipRender; }
|
||||
|
||||
|
|
|
@ -383,6 +383,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
EntityTreeRenderer* entityTreeRenderer = qApp->getEntities();
|
||||
EntityTreePointer entityTree = entityTreeRenderer ? entityTreeRenderer->getTree() : nullptr;
|
||||
if (entityTree) {
|
||||
auto now = usecTimestampNow();
|
||||
EntityEditPacketSender* packetSender = qApp->getEntityEditPacketSender();
|
||||
MovingEntitiesOperator moveOperator(entityTree);
|
||||
forEachDescendant([&](SpatiallyNestablePointer object) {
|
||||
|
@ -397,6 +398,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
if (packetSender) {
|
||||
EntityItemProperties properties = entity->getProperties();
|
||||
properties.setQueryAACubeDirty();
|
||||
properties.setLastEdited(now);
|
||||
packetSender->queueEditEntityMessage(PacketType::EntityEdit, entity->getID(), properties);
|
||||
entity->setLastBroadcast(usecTimestampNow());
|
||||
}
|
||||
|
@ -1078,6 +1080,15 @@ void MyAvatar::rebuildCollisionShape() {
|
|||
|
||||
void MyAvatar::prepareForPhysicsSimulation() {
|
||||
relayDriveKeysToCharacterController();
|
||||
|
||||
bool success;
|
||||
glm::vec3 parentVelocity = getParentVelocity(success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning: getParentVelocity failed" << getID();
|
||||
parentVelocity = glm::vec3();
|
||||
}
|
||||
_characterController.setParentVelocity(parentVelocity);
|
||||
|
||||
_characterController.setTargetVelocity(getTargetVelocity());
|
||||
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
||||
if (qApp->isHMDMode()) {
|
||||
|
|
|
@ -67,6 +67,7 @@ void MyCharacterController::updateShapeIfNecessary() {
|
|||
_rigidBody->setAngularFactor(0.0f);
|
||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
|
||||
glmToBullet(_avatar->getPosition())));
|
||||
_rigidBody->setDamping(0.0f, 0.0f);
|
||||
if (_state == State::Hover) {
|
||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
} else {
|
||||
|
|
|
@ -148,7 +148,11 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
_rig->updateFromHandParameters(handParams, deltaTime);
|
||||
|
||||
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
|
||||
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState);
|
||||
|
||||
auto velocity = myAvatar->getLocalVelocity();
|
||||
auto position = myAvatar->getLocalPosition();
|
||||
auto orientation = myAvatar->getLocalOrientation();
|
||||
_rig->computeMotionAnimationState(deltaTime, position, velocity, orientation, ccState);
|
||||
|
||||
// evaluate AnimGraph animation and update jointStates.
|
||||
Model::updateRig(deltaTime, parentTransform);
|
||||
|
|
|
@ -47,6 +47,11 @@ AnimationReader::AnimationReader(const QUrl& url, const QByteArray& data) :
|
|||
}
|
||||
|
||||
void AnimationReader::run() {
|
||||
auto originalPriority = QThread::currentThread()->priority();
|
||||
if (originalPriority == QThread::InheritPriority) {
|
||||
originalPriority = QThread::NormalPriority;
|
||||
}
|
||||
QThread::currentThread()->setPriority(QThread::LowPriority);
|
||||
try {
|
||||
if (_data.isEmpty()) {
|
||||
throw QString("Reply is NULL ?!");
|
||||
|
@ -73,6 +78,7 @@ void AnimationReader::run() {
|
|||
} catch (const QString& error) {
|
||||
emit onError(299, error);
|
||||
}
|
||||
QThread::currentThread()->setPriority(originalPriority);
|
||||
}
|
||||
|
||||
bool Animation::isLoaded() const {
|
||||
|
|
|
@ -507,32 +507,7 @@ static const std::vector<float> LATERAL_SPEEDS = { 0.2f, 0.65f }; // m/s
|
|||
void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState) {
|
||||
|
||||
glm::vec3 front = worldRotation * IDENTITY_FRONT;
|
||||
|
||||
// It can be more accurate/smooth to use velocity rather than position,
|
||||
// but some modes (e.g., hmd standing) update position without updating velocity.
|
||||
// It's very hard to debug hmd standing. (Look down at yourself, or have a second person observe. HMD third person is a bit undefined...)
|
||||
// So, let's create our own workingVelocity from the worldPosition...
|
||||
glm::vec3 workingVelocity = _lastVelocity;
|
||||
glm::vec3 positionDelta = worldPosition - _lastPosition;
|
||||
|
||||
// Don't trust position delta if deltaTime is 'small'.
|
||||
// NOTE: This is mostly just a work around for an issue in oculus 0.7 runtime, where
|
||||
// Application::idle() is being called more frequently and with smaller dt's then expected.
|
||||
const float SMALL_DELTA_TIME = 0.006f; // 6 ms
|
||||
if (deltaTime > SMALL_DELTA_TIME) {
|
||||
workingVelocity = positionDelta / deltaTime;
|
||||
}
|
||||
|
||||
#if !WANT_DEBUG
|
||||
// But for smoothest (non-hmd standing) results, go ahead and use velocity:
|
||||
if (!positionDelta.x && !positionDelta.y && !positionDelta.z) {
|
||||
workingVelocity = worldVelocity;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (deltaTime > SMALL_DELTA_TIME) {
|
||||
_lastVelocity = workingVelocity;
|
||||
}
|
||||
glm::vec3 workingVelocity = worldVelocity;
|
||||
|
||||
{
|
||||
glm::vec3 localVel = glm::inverse(worldRotation) * workingVelocity;
|
||||
|
@ -809,7 +784,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
|||
|
||||
// compute blend based on velocity
|
||||
const float JUMP_SPEED = 3.5f;
|
||||
float alpha = glm::clamp(-_lastWorldVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f;
|
||||
float alpha = glm::clamp(-_lastVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f;
|
||||
_animVars.set("inAirAlpha", alpha);
|
||||
}
|
||||
|
||||
|
@ -827,7 +802,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
|||
|
||||
_lastFront = front;
|
||||
_lastPosition = worldPosition;
|
||||
_lastWorldVelocity = worldVelocity;
|
||||
_lastVelocity = workingVelocity;
|
||||
}
|
||||
|
||||
// Allow script to add/remove handlers and report results, from within their thread.
|
||||
|
|
|
@ -267,7 +267,6 @@ public:
|
|||
glm::vec3 _lastFront;
|
||||
glm::vec3 _lastPosition;
|
||||
glm::vec3 _lastVelocity;
|
||||
glm::vec3 _lastWorldVelocity;
|
||||
glm::vec3 _eyesInRootFrame { Vectors::ZERO };
|
||||
|
||||
QUrl _animGraphURL;
|
||||
|
|
|
@ -64,7 +64,6 @@ AvatarData::AvatarData() :
|
|||
_billboard(),
|
||||
_errorLogExpiry(0),
|
||||
_owningAvatarMixer(),
|
||||
_velocity(0.0f),
|
||||
_targetVelocity(0.0f),
|
||||
_localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE)
|
||||
{
|
||||
|
|
|
@ -151,6 +151,9 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
|||
Q_PROPERTY(float headYaw READ getHeadYaw WRITE setHeadYaw)
|
||||
Q_PROPERTY(float headRoll READ getHeadRoll WRITE setHeadRoll)
|
||||
|
||||
Q_PROPERTY(glm::vec3 velocity READ getVelocity WRITE setVelocity)
|
||||
Q_PROPERTY(glm::vec3 angularVelocity READ getAngularVelocity WRITE setAngularVelocity)
|
||||
|
||||
Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness)
|
||||
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
|
||||
|
||||
|
@ -334,8 +337,6 @@ public:
|
|||
int getAverageBytesReceivedPerSecond() const;
|
||||
int getReceiveRate() const;
|
||||
|
||||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
||||
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
||||
const glm::vec3& getTargetVelocity() const { return _targetVelocity; }
|
||||
|
||||
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
||||
|
@ -406,7 +407,6 @@ protected:
|
|||
/// Loads the joint indices, names from the FST file (if any)
|
||||
virtual void updateJointMappings();
|
||||
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _targetVelocity;
|
||||
|
||||
AABox _localAABox;
|
||||
|
|
|
@ -28,6 +28,11 @@
|
|||
#include <GLMHelpers.h>
|
||||
|
||||
#if THREADED_PRESENT
|
||||
|
||||
// FIXME, for display plugins that don't block on something like vsync, just
|
||||
// cap the present rate at 200
|
||||
// const static unsigned int MAX_PRESENT_RATE = 200;
|
||||
|
||||
class PresentThread : public QThread, public Dependency {
|
||||
using Mutex = std::mutex;
|
||||
using Condition = std::condition_variable;
|
||||
|
@ -66,8 +71,10 @@ public:
|
|||
_context->moveToThread(this);
|
||||
}
|
||||
|
||||
|
||||
virtual void run() override {
|
||||
OpenGLDisplayPlugin* currentPlugin{ nullptr };
|
||||
thread()->setPriority(QThread::HighestPriority);
|
||||
Q_ASSERT(_context);
|
||||
while (!_shutdown) {
|
||||
if (_pendingMainThreadOperation) {
|
||||
|
@ -450,4 +457,4 @@ void OpenGLDisplayPlugin::enableDeactivate() {
|
|||
_uncustomized = true;
|
||||
_deactivateWait.notify_one();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -41,6 +41,8 @@ void EntityEditPacketSender::queueEditEntityMessage(PacketType type, EntityItemI
|
|||
return; // bail early
|
||||
}
|
||||
|
||||
assert(properties.getLastEdited() > 0);
|
||||
|
||||
QByteArray bufferOut(NLPacket::maxPayloadSize(type), 0);
|
||||
|
||||
if (EntityItemProperties::encodeEntityEditPacket(type, modelID, properties, bufferOut)) {
|
||||
|
|
|
@ -49,7 +49,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA),
|
||||
_density(ENTITY_ITEM_DEFAULT_DENSITY),
|
||||
_volumeMultiplier(1.0f),
|
||||
_velocity(ENTITY_ITEM_DEFAULT_VELOCITY),
|
||||
_gravity(ENTITY_ITEM_DEFAULT_GRAVITY),
|
||||
_acceleration(ENTITY_ITEM_DEFAULT_ACCELERATION),
|
||||
_damping(ENTITY_ITEM_DEFAULT_DAMPING),
|
||||
|
@ -60,7 +59,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_scriptTimestamp(ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP),
|
||||
_collisionSoundURL(ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
|
||||
_registrationPoint(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
|
||||
_angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
|
||||
_angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
|
||||
_visible(ENTITY_ITEM_DEFAULT_VISIBLE),
|
||||
_collisionless(ENTITY_ITEM_DEFAULT_COLLISIONLESS),
|
||||
|
@ -78,6 +76,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_physicsInfo(nullptr),
|
||||
_simulated(false)
|
||||
{
|
||||
setVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
|
||||
setAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
||||
// explicitly set transform parts to set dirty flags used by batch rendering
|
||||
setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||
quint64 now = usecTimestampNow();
|
||||
|
@ -470,7 +470,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
Q_ASSERT(parser.offset() == (unsigned int) bytesRead);
|
||||
}
|
||||
#endif
|
||||
quint64 lastEditedFromBufferAdjusted = lastEditedFromBuffer - clockSkew;
|
||||
quint64 lastEditedFromBufferAdjusted = lastEditedFromBuffer == 0 ? 0 : lastEditedFromBuffer - clockSkew;
|
||||
if (lastEditedFromBufferAdjusted > now) {
|
||||
lastEditedFromBufferAdjusted = now;
|
||||
}
|
||||
|
@ -886,41 +886,45 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) {
|
|||
}
|
||||
|
||||
if (hasAngularVelocity()) {
|
||||
glm::vec3 angularVelocity = getAngularVelocity();
|
||||
|
||||
// angular damping
|
||||
if (_angularDamping > 0.0f) {
|
||||
_angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
|
||||
angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(entities) << " angularDamping :" << _angularDamping;
|
||||
qCDebug(entities) << " newAngularVelocity:" << _angularVelocity;
|
||||
qCDebug(entities) << " newAngularVelocity:" << angularVelocity;
|
||||
#endif
|
||||
}
|
||||
|
||||
float angularSpeed = glm::length(_angularVelocity);
|
||||
float angularSpeed = glm::length(angularVelocity);
|
||||
|
||||
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec
|
||||
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
|
||||
if (setFlags && angularSpeed > 0.0f) {
|
||||
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
}
|
||||
_angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
// for improved agreement with the way Bullet integrates rotations we use an approximation
|
||||
// and break the integration into bullet-sized substeps
|
||||
glm::quat rotation = getRotation();
|
||||
float dt = timeElapsed;
|
||||
while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) {
|
||||
glm::quat dQ = computeBulletRotationStep(_angularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
glm::quat dQ = computeBulletRotationStep(angularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
rotation = glm::normalize(dQ * rotation);
|
||||
dt -= PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||
}
|
||||
// NOTE: this final partial substep can drift away from a real Bullet simulation however
|
||||
// it only becomes significant for rapidly rotating objects
|
||||
// (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec).
|
||||
glm::quat dQ = computeBulletRotationStep(_angularVelocity, dt);
|
||||
glm::quat dQ = computeBulletRotationStep(angularVelocity, dt);
|
||||
rotation = glm::normalize(dQ * rotation);
|
||||
|
||||
setRotation(rotation);
|
||||
}
|
||||
|
||||
setAngularVelocity(angularVelocity);
|
||||
}
|
||||
|
||||
if (hasVelocity()) {
|
||||
|
@ -1077,9 +1081,9 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
|
|||
void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const {
|
||||
// a TerseUpdate includes the transform and its derivatives
|
||||
properties._position = getLocalPosition();
|
||||
properties._velocity = _velocity;
|
||||
properties._velocity = getLocalVelocity();
|
||||
properties._rotation = getLocalOrientation();
|
||||
properties._angularVelocity = _angularVelocity;
|
||||
properties._angularVelocity = getLocalAngularVelocity();
|
||||
properties._acceleration = _acceleration;
|
||||
|
||||
properties._positionChanged = true;
|
||||
|
@ -1406,13 +1410,15 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
|
|||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
if (_velocity != value) {
|
||||
glm::vec3 velocity = getLocalVelocity();
|
||||
if (velocity != value) {
|
||||
const float MIN_LINEAR_SPEED = 0.001f;
|
||||
if (glm::length(value) < MIN_LINEAR_SPEED) {
|
||||
_velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
_velocity = value;
|
||||
velocity = value;
|
||||
}
|
||||
setLocalVelocity(velocity);
|
||||
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
||||
}
|
||||
}
|
||||
|
@ -1436,13 +1442,15 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) {
|
|||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
if (_angularVelocity != value) {
|
||||
glm::vec3 angularVelocity = getLocalAngularVelocity();
|
||||
if (angularVelocity != value) {
|
||||
const float MIN_ANGULAR_SPEED = 0.0002f;
|
||||
if (glm::length(value) < MIN_ANGULAR_SPEED) {
|
||||
_angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
_angularVelocity = value;
|
||||
angularVelocity = value;
|
||||
}
|
||||
setLocalAngularVelocity(angularVelocity);
|
||||
_dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,9 +193,7 @@ public:
|
|||
|
||||
float getDensity() const { return _density; }
|
||||
|
||||
const glm::vec3& getVelocity() const { return _velocity; } /// get velocity in meters
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters
|
||||
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
bool hasVelocity() const { return getVelocity() != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
|
||||
|
@ -255,9 +253,7 @@ public:
|
|||
void setRegistrationPoint(const glm::vec3& value)
|
||||
{ _registrationPoint = glm::clamp(value, 0.0f, 1.0f); requiresRecalcBoxes(); }
|
||||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; }
|
||||
bool hasAngularVelocity() const { return _angularVelocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
bool hasAngularVelocity() const { return getAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
float getAngularDamping() const { return _angularDamping; }
|
||||
void setAngularDamping(float value) { _angularDamping = value; }
|
||||
|
@ -435,7 +431,6 @@ protected:
|
|||
// rather than in all of the derived classes. If we ever collapse these classes to one we could do it a
|
||||
// different way.
|
||||
float _volumeMultiplier = 1.0f;
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _gravity;
|
||||
glm::vec3 _acceleration;
|
||||
float _damping;
|
||||
|
@ -446,7 +441,6 @@ protected:
|
|||
quint64 _scriptTimestamp;
|
||||
QString _collisionSoundURL;
|
||||
glm::vec3 _registrationPoint;
|
||||
glm::vec3 _angularVelocity;
|
||||
float _angularDamping;
|
||||
bool _visible;
|
||||
bool _collisionless;
|
||||
|
|
|
@ -345,6 +345,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties&
|
|||
EntityItemPointer entityDescendant = std::static_pointer_cast<EntityItem>(descendant);
|
||||
EntityItemProperties newQueryCubeProperties;
|
||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
|
||||
queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
|
||||
entityDescendant->setLastBroadcast(usecTimestampNow());
|
||||
}
|
||||
|
|
|
@ -815,6 +815,14 @@ void EntityTree::fixupTerseEditLogging(EntityItemProperties& properties, QList<Q
|
|||
changedProperties[index] = QString("jointTranslations:") + QString::number((int)value);
|
||||
}
|
||||
}
|
||||
if (properties.queryAACubeChanged()) {
|
||||
int index = changedProperties.indexOf("queryAACube");
|
||||
glm::vec3 center = properties.getQueryAACube().calcCenter();
|
||||
changedProperties[index] = QString("queryAACube:") +
|
||||
QString::number((int)center.x) + "," +
|
||||
QString::number((int)center.y) + "," +
|
||||
QString::number((int)center.z);
|
||||
}
|
||||
}
|
||||
|
||||
int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned char* editData, int maxLength,
|
||||
|
|
|
@ -459,6 +459,7 @@ bool EntityTreeElement::bestFitEntityBounds(EntityItemPointer entity) const {
|
|||
bool success;
|
||||
auto queryCube = entity->getQueryAACube(success);
|
||||
if (!success) {
|
||||
qDebug() << "EntityTreeElement::bestFitEntityBounds couldn't get queryCube for" << entity->getName() << entity->getID();
|
||||
return false;
|
||||
}
|
||||
return bestFitBounds(queryCube);
|
||||
|
|
|
@ -50,6 +50,11 @@ GeometryReader::GeometryReader(const QUrl& url, const QByteArray& data, const QV
|
|||
}
|
||||
|
||||
void GeometryReader::run() {
|
||||
auto originalPriority = QThread::currentThread()->priority();
|
||||
if (originalPriority == QThread::InheritPriority) {
|
||||
originalPriority = QThread::NormalPriority;
|
||||
}
|
||||
QThread::currentThread()->setPriority(QThread::LowPriority);
|
||||
try {
|
||||
if (_data.isEmpty()) {
|
||||
throw QString("Reply is NULL ?!");
|
||||
|
@ -82,6 +87,8 @@ void GeometryReader::run() {
|
|||
qCDebug(modelnetworking) << "Error reading " << _url << ": " << error;
|
||||
emit onError(NetworkGeometry::ModelParseError, error);
|
||||
}
|
||||
|
||||
QThread::currentThread()->setPriority(originalPriority);
|
||||
}
|
||||
|
||||
NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
|
||||
|
|
|
@ -268,6 +268,12 @@ void ImageReader::listSupportedImageFormats() {
|
|||
}
|
||||
|
||||
void ImageReader::run() {
|
||||
auto originalPriority = QThread::currentThread()->priority();
|
||||
if (originalPriority == QThread::InheritPriority) {
|
||||
originalPriority = QThread::NormalPriority;
|
||||
}
|
||||
QThread::currentThread()->setPriority(QThread::LowPriority);
|
||||
|
||||
auto texture = _texture.toStrongRef();
|
||||
if (!texture) {
|
||||
qCWarning(modelnetworking) << "Could not get strong ref";
|
||||
|
@ -306,6 +312,7 @@ void ImageReader::run() {
|
|||
Q_ARG(const QImage&, image),
|
||||
Q_ARG(void*, theTexture),
|
||||
Q_ARG(int, originalWidth), Q_ARG(int, originalHeight));
|
||||
QThread::currentThread()->setPriority(originalPriority);
|
||||
}
|
||||
|
||||
void NetworkTexture::setImage(const QImage& image, void* voidTexture, int originalWidth,
|
||||
|
|
|
@ -50,88 +50,49 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// FIXME why is this in the model library? Move to GPU or GPU_GL
|
||||
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
int opaquePixels = 0;
|
||||
int translucentPixels = 0;
|
||||
//bool isTransparent = false;
|
||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
}
|
||||
}
|
||||
if (imageArea > 0) {
|
||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
||||
}
|
||||
} else {
|
||||
bool validAlpha = false;
|
||||
if (image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// check for translucency/false transparency
|
||||
// int opaquePixels = 0;
|
||||
// int translucentPixels = 0;
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
int alpha = qAlpha(rgb);
|
||||
alphaTotal += alpha;
|
||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
||||
opaquePixels++;
|
||||
} else if (alpha != 0) {
|
||||
translucentPixels++;
|
||||
// Actual alpha channel?
|
||||
for (int y = 0; y < image.height(); ++y) {
|
||||
const QRgb* data = reinterpret_cast<const QRgb*>(image.constScanLine(y));
|
||||
for (int x = 0; x < image.width(); ++x) {
|
||||
auto alpha = qAlpha(data[x]);
|
||||
if (alpha != 255) {
|
||||
validAlpha = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
averageColor = QColor(redTotal / imageArea,
|
||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
||||
|
||||
//isTransparent = (translucentPixels >= imageArea / 2);
|
||||
}
|
||||
|
||||
if (!validAlpha && image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
|
||||
// FIXME queue for transfer to GPU and block on completion
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
|
|
|
@ -54,7 +54,7 @@ CharacterController::CharacterController() {
|
|||
|
||||
_floorDistance = MAX_FALL_HEIGHT;
|
||||
|
||||
_walkVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||
_targetVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||
_followDesiredBodyTransform.setIdentity();
|
||||
_followTimeRemaining = 0.0f;
|
||||
_jumpSpeed = JUMP_SPEED;
|
||||
|
@ -166,12 +166,12 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
|||
|
||||
const btScalar MIN_SPEED = 0.001f;
|
||||
|
||||
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
|
||||
btVector3 actualVelocity = _rigidBody->getLinearVelocity() - _parentVelocity;
|
||||
if (actualVelocity.length() < MIN_SPEED) {
|
||||
actualVelocity = btVector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
btVector3 desiredVelocity = _walkVelocity;
|
||||
btVector3 desiredVelocity = _targetVelocity;
|
||||
if (desiredVelocity.length() < MIN_SPEED) {
|
||||
desiredVelocity = btVector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
|||
break;
|
||||
}
|
||||
|
||||
_rigidBody->setLinearVelocity(finalVelocity);
|
||||
_rigidBody->setLinearVelocity(finalVelocity + _parentVelocity);
|
||||
|
||||
// Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform.
|
||||
// Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal.
|
||||
|
@ -383,8 +383,11 @@ void CharacterController::getPositionAndOrientation(glm::vec3& position, glm::qu
|
|||
}
|
||||
|
||||
void CharacterController::setTargetVelocity(const glm::vec3& velocity) {
|
||||
//_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
|
||||
_walkVelocity = glmToBullet(velocity);
|
||||
_targetVelocity = glmToBullet(velocity);
|
||||
}
|
||||
|
||||
void CharacterController::setParentVelocity(const glm::vec3& velocity) {
|
||||
_parentVelocity = glmToBullet(velocity);
|
||||
}
|
||||
|
||||
void CharacterController::setFollowParameters(const glm::mat4& desiredWorldBodyMatrix, float timeRemaining) {
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
|
||||
|
||||
void setTargetVelocity(const glm::vec3& velocity);
|
||||
void setParentVelocity(const glm::vec3& parentVelocity);
|
||||
void setFollowParameters(const glm::mat4& desiredWorldMatrix, float timeRemaining);
|
||||
float getFollowTime() const { return _followTime; }
|
||||
glm::vec3 getFollowLinearDisplacement() const;
|
||||
|
@ -105,7 +106,8 @@ protected:
|
|||
|
||||
protected:
|
||||
btVector3 _currentUp;
|
||||
btVector3 _walkVelocity;
|
||||
btVector3 _targetVelocity;
|
||||
btVector3 _parentVelocity;
|
||||
btTransform _followDesiredBodyTransform;
|
||||
btScalar _followTimeRemaining;
|
||||
btTransform _characterBodyTransform;
|
||||
|
|
|
@ -527,6 +527,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
|
|||
if (descendant->computePuffedQueryAACube()) {
|
||||
EntityItemProperties newQueryCubeProperties;
|
||||
newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube());
|
||||
newQueryCubeProperties.setLastEdited(properties.getLastEdited());
|
||||
entityPacketSender->queueEditEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties);
|
||||
entityDescendant->setLastBroadcast(usecTimestampNow());
|
||||
}
|
||||
|
|
|
@ -391,6 +391,96 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) {
|
|||
#endif
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getVelocity(bool& success) const {
|
||||
glm::vec3 parentVelocity = getParentVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
glm::vec3 result;
|
||||
_velocityLock.withReadLock([&] {
|
||||
// TODO: take parent angularVelocity into account.
|
||||
result = parentVelocity + parentTransform.getRotation() * _velocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getVelocity() const {
|
||||
bool success;
|
||||
glm::vec3 result = getVelocity(success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- setVelocity failed" << getID();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setVelocity(const glm::vec3& velocity, bool& success) {
|
||||
glm::vec3 parentVelocity = getParentVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
_velocityLock.withWriteLock([&] {
|
||||
// TODO: take parent angularVelocity into account.
|
||||
_velocity = glm::inverse(parentTransform.getRotation()) * velocity - parentVelocity;
|
||||
});
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setVelocity(const glm::vec3& velocity) {
|
||||
bool success;
|
||||
setVelocity(velocity, success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- setVelocity failed" << getID();
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getParentVelocity(bool& success) const {
|
||||
glm::vec3 result;
|
||||
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||
if (success && parent) {
|
||||
result = parent->getVelocity(success);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const {
|
||||
glm::vec3 parentAngularVelocity = getParentAngularVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
glm::vec3 result;
|
||||
_angularVelocityLock.withReadLock([&] {
|
||||
result = parentAngularVelocity + parentTransform.getRotation() * _angularVelocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getAngularVelocity() const {
|
||||
bool success;
|
||||
glm::vec3 result = getAngularVelocity(success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- getAngularVelocity failed" << getID();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity, bool& success) {
|
||||
glm::vec3 parentAngularVelocity = getParentAngularVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
_angularVelocityLock.withWriteLock([&] {
|
||||
_angularVelocity = glm::inverse(parentTransform.getRotation()) * angularVelocity - parentAngularVelocity;
|
||||
});
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity) {
|
||||
bool success;
|
||||
setAngularVelocity(angularVelocity, success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- setAngularVelocity failed" << getID();
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getParentAngularVelocity(bool& success) const {
|
||||
glm::vec3 result;
|
||||
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||
if (success && parent) {
|
||||
result = parent->getAngularVelocity(success);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const Transform SpatiallyNestable::getTransform(bool& success) const {
|
||||
// return a world-space transform for this object's location
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
|
@ -519,6 +609,34 @@ void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) {
|
|||
locationChanged();
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalVelocity() const {
|
||||
glm::vec3 result(glm::vec3::_null);
|
||||
_velocityLock.withReadLock([&] {
|
||||
result = _velocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalVelocity(const glm::vec3& velocity) {
|
||||
_velocityLock.withWriteLock([&] {
|
||||
_velocity = velocity;
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalAngularVelocity() const {
|
||||
glm::vec3 result(glm::vec3::_null);
|
||||
_angularVelocityLock.withReadLock([&] {
|
||||
result = _angularVelocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalAngularVelocity(const glm::vec3& angularVelocity) {
|
||||
_angularVelocityLock.withWriteLock([&] {
|
||||
_angularVelocity = angularVelocity;
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalScale() const {
|
||||
// TODO: scale
|
||||
glm::vec3 result;
|
||||
|
|
|
@ -68,6 +68,18 @@ public:
|
|||
virtual void setOrientation(const glm::quat& orientation, bool& success);
|
||||
virtual void setOrientation(const glm::quat& orientation);
|
||||
|
||||
virtual glm::vec3 getVelocity(bool& success) const;
|
||||
virtual glm::vec3 getVelocity() const;
|
||||
virtual void setVelocity(const glm::vec3& velocity, bool& success);
|
||||
virtual void setVelocity(const glm::vec3& velocity);
|
||||
virtual glm::vec3 getParentVelocity(bool& success) const;
|
||||
|
||||
virtual glm::vec3 getAngularVelocity(bool& success) const;
|
||||
virtual glm::vec3 getAngularVelocity() const;
|
||||
virtual void setAngularVelocity(const glm::vec3& angularVelocity, bool& success);
|
||||
virtual void setAngularVelocity(const glm::vec3& angularVelocity);
|
||||
virtual glm::vec3 getParentAngularVelocity(bool& success) const;
|
||||
|
||||
virtual AACube getMaximumAACube(bool& success) const;
|
||||
virtual bool computePuffedQueryAACube();
|
||||
|
||||
|
@ -94,6 +106,12 @@ public:
|
|||
virtual glm::quat getLocalOrientation() const;
|
||||
virtual void setLocalOrientation(const glm::quat& orientation);
|
||||
|
||||
virtual glm::vec3 getLocalVelocity() const;
|
||||
virtual void setLocalVelocity(const glm::vec3& velocity);
|
||||
|
||||
virtual glm::vec3 getLocalAngularVelocity() const;
|
||||
virtual void setLocalAngularVelocity(const glm::vec3& angularVelocity);
|
||||
|
||||
virtual glm::vec3 getLocalScale() const;
|
||||
virtual void setLocalScale(const glm::vec3& scale);
|
||||
|
||||
|
@ -126,6 +144,7 @@ protected:
|
|||
QUuid _parentID; // what is this thing's transform relative to?
|
||||
quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to?
|
||||
SpatiallyNestablePointer getParentPointer(bool& success) const;
|
||||
|
||||
mutable SpatiallyNestableWeakPointer _parent;
|
||||
|
||||
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const;
|
||||
|
@ -146,7 +165,11 @@ protected:
|
|||
private:
|
||||
mutable ReadWriteLockable _transformLock;
|
||||
mutable ReadWriteLockable _idLock;
|
||||
mutable ReadWriteLockable _velocityLock;
|
||||
mutable ReadWriteLockable _angularVelocityLock;
|
||||
Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform.
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _angularVelocity;
|
||||
mutable bool _parentKnowsMe { false };
|
||||
bool _isDead { false };
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue