mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-16 01:40:33 +02:00
Merge pull request #11804 from amantley/character_entity_fixes
Fixed Entity Animation Property not applying to FBXs
This commit is contained in:
commit
5087893097
7 changed files with 172 additions and 44 deletions
|
@ -402,6 +402,8 @@ void EntityTreeRenderer::update(bool simulate) {
|
|||
PerformanceTimer perfTimer("ETRupdate");
|
||||
if (_tree && !_shuttingDown) {
|
||||
EntityTreePointer tree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
|
||||
// here we update _currentFrame and _lastAnimated and sync with the server properties.
|
||||
tree->update(simulate);
|
||||
|
||||
// Update the rendereable entities as needed
|
||||
|
@ -736,7 +738,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) {
|
|||
PickRay ray = _viewState->computePickRay(event->x(), event->y());
|
||||
RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID);
|
||||
if (rayPickResult.intersects && rayPickResult.entity) {
|
||||
//qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||
// qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID;
|
||||
|
||||
glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult);
|
||||
PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID,
|
||||
|
|
|
@ -63,13 +63,17 @@ bool ModelEntityWrapper::isModelLoaded() const {
|
|||
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItemPointer entity(new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()),
|
||||
[](EntityItem* ptr) { ptr->deleteLater(); });
|
||||
|
||||
entity->setProperties(properties);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
|
||||
ModelEntityWrapper(entityItemID),
|
||||
_dimensionsInitialized(dimensionsInitialized) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
RenderableModelEntityItem::~RenderableModelEntityItem() { }
|
||||
|
@ -464,7 +468,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
// TODO: assert we never fall in here when model not fully loaded
|
||||
//assert(_model && _model->isLoaded());
|
||||
// assert(_model && _model->isLoaded());
|
||||
|
||||
updateModelBounds();
|
||||
model->updateGeometry();
|
||||
|
@ -974,9 +978,6 @@ void ModelEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entit
|
|||
entity->setModel({});
|
||||
}
|
||||
|
||||
bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
||||
if (!_animation || !_animation->isLoaded()) {
|
||||
|
@ -991,19 +992,12 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_lastAnimated) {
|
||||
_lastAnimated = usecTimestampNow();
|
||||
return;
|
||||
}
|
||||
|
||||
auto now = usecTimestampNow();
|
||||
auto interval = now - _lastAnimated;
|
||||
_lastAnimated = now;
|
||||
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
|
||||
_currentFrame += (deltaTime * _renderAnimationProperties.getFPS());
|
||||
|
||||
{
|
||||
int animationCurrentFrame = (int)(glm::floor(_currentFrame)) % frameCount;
|
||||
// the current frame is set on the server in update() in ModelEntityItem.cpp
|
||||
int animationCurrentFrame = (int)(glm::floor(entity->getAnimationCurrentFrame()));
|
||||
|
||||
// in the case where the last frame is greater than the framecount then clamp
|
||||
// it to the end of the animation until it loops around.
|
||||
if (animationCurrentFrame < 0 || animationCurrentFrame > frameCount) {
|
||||
animationCurrentFrame = 0;
|
||||
}
|
||||
|
@ -1039,10 +1033,10 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) {
|
|||
glm::mat4 translationMat;
|
||||
|
||||
if (allowTranslation) {
|
||||
if(index < translations.size()){
|
||||
if (index < translations.size()) {
|
||||
translationMat = glm::translate(translations[index]);
|
||||
}
|
||||
} else if (index < animationJointNames.size()){
|
||||
} else if (index < animationJointNames.size()) {
|
||||
QString jointName = fbxJoints[index].name; // Pushing this here so its not done on every entity, with the exceptions of those allowing for translation
|
||||
|
||||
if (originalFbxIndices.contains(jointName)) {
|
||||
|
@ -1317,25 +1311,17 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
if (model->getRenderItemsNeedUpdate()) {
|
||||
model->updateRenderItems();
|
||||
}
|
||||
|
||||
{
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "CheckAnimation");
|
||||
// make a copy of the animation properites
|
||||
auto newAnimationProperties = entity->getAnimationProperties();
|
||||
if (newAnimationProperties != _renderAnimationProperties) {
|
||||
withWriteLock([&] {
|
||||
_renderAnimationProperties = newAnimationProperties;
|
||||
_currentFrame = _renderAnimationProperties.getCurrentFrame();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The code to deal with the change of properties is now in ModelEntityItem.cpp
|
||||
// That is where _currentFrame and _lastAnimated were updated.
|
||||
if (_animating) {
|
||||
DETAILED_PROFILE_RANGE(simulation_physics, "Animate");
|
||||
if (!jointsMapped()) {
|
||||
mapJoints(entity, model->getJointNames());
|
||||
}
|
||||
animate(entity);
|
||||
if (!(entity->getAnimationFirstFrame() < 0) && !(entity->getAnimationFirstFrame() > entity->getAnimationLastFrame())) {
|
||||
animate(entity);
|
||||
}
|
||||
emit requestRenderUpdate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace render { namespace entities {
|
|||
class ModelEntityRenderer;
|
||||
} }
|
||||
|
||||
//#define MODEL_ENTITY_USE_FADE_EFFECT
|
||||
// #define MODEL_ENTITY_USE_FADE_EFFECT
|
||||
class ModelEntityWrapper : public ModelEntityItem {
|
||||
using Parent = ModelEntityItem;
|
||||
friend class render::entities::ModelEntityRenderer;
|
||||
|
@ -133,7 +133,7 @@ class ModelEntityRenderer : public TypedEntityRenderer<RenderableModelEntityItem
|
|||
friend class EntityRenderer;
|
||||
|
||||
public:
|
||||
ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { }
|
||||
ModelEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
|
||||
|
||||
protected:
|
||||
virtual void removeFromScene(const ScenePointer& scene, Transaction& transaction) override;
|
||||
|
@ -184,8 +184,6 @@ private:
|
|||
bool _shouldHighlight { false };
|
||||
bool _animating { false };
|
||||
uint64_t _lastAnimated { 0 };
|
||||
float _currentFrame { 0 };
|
||||
|
||||
};
|
||||
|
||||
} } // namespace
|
||||
|
|
|
@ -22,15 +22,28 @@ const float AnimationPropertyGroup::MAXIMUM_POSSIBLE_FRAME = 100000.0f;
|
|||
|
||||
bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||
return
|
||||
(a._url == b._url) &&
|
||||
|
||||
(a._currentFrame == b._currentFrame) &&
|
||||
(a._running == b._running) &&
|
||||
(a._loop == b._loop) &&
|
||||
(a._hold == b._hold) &&
|
||||
(a._firstFrame == b._firstFrame) &&
|
||||
(a._lastFrame == b._lastFrame) &&
|
||||
(a._hold == b._hold);
|
||||
(a._url == b._url);
|
||||
}
|
||||
|
||||
bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b) {
|
||||
return
|
||||
(a._currentFrame != b._currentFrame) ||
|
||||
(a._running != b._running) ||
|
||||
(a._loop != b._loop) ||
|
||||
(a._hold != b._hold) ||
|
||||
(a._firstFrame != b._firstFrame) ||
|
||||
(a._lastFrame != b._lastFrame) ||
|
||||
(a._url != b._url);
|
||||
}
|
||||
|
||||
|
||||
void AnimationPropertyGroup::copyToScriptValue(const EntityPropertyFlags& desiredProperties, QScriptValue& properties, QScriptEngine* engine, bool skipDefaults, EntityItemProperties& defaultEntityProperties) const {
|
||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_URL, Animation, animation, URL, url);
|
||||
COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(PROP_ANIMATION_ALLOW_TRANSLATION, Animation, animation, AllowTranslation, allowTranslation);
|
||||
|
@ -130,6 +143,7 @@ void AnimationPropertyGroup::setFromOldAnimationSettings(const QString& value) {
|
|||
allowTranslation = settingsMap["allowTranslation"].toBool();
|
||||
}
|
||||
|
||||
|
||||
setAllowTranslation(allowTranslation);
|
||||
setFPS(fps);
|
||||
setCurrentFrame(currentFrame);
|
||||
|
|
|
@ -89,6 +89,7 @@ public:
|
|||
|
||||
protected:
|
||||
friend bool operator==(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
||||
friend bool operator!=(const AnimationPropertyGroup& a, const AnimationPropertyGroup& b);
|
||||
void setFromOldAnimationSettings(const QString& value);
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,8 @@ EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const E
|
|||
|
||||
ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID) : EntityItem(entityItemID)
|
||||
{
|
||||
_lastAnimated = usecTimestampNow();
|
||||
// set the last animated when interface (re)starts
|
||||
_type = EntityTypes::Model;
|
||||
_lastKnownCurrentFrame = -1;
|
||||
_color[0] = _color[1] = _color[2] = 0;
|
||||
|
@ -186,6 +188,105 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
}
|
||||
|
||||
|
||||
|
||||
// added update function back for property fix
|
||||
void ModelEntityItem::update(const quint64& now) {
|
||||
|
||||
{
|
||||
auto currentAnimationProperties = this->getAnimationProperties();
|
||||
|
||||
if (_previousAnimationProperties != currentAnimationProperties) {
|
||||
withWriteLock([&] {
|
||||
// if we hit start animation or change the first or last frame then restart the animation
|
||||
if ((currentAnimationProperties.getFirstFrame() != _previousAnimationProperties.getFirstFrame()) ||
|
||||
(currentAnimationProperties.getLastFrame() != _previousAnimationProperties.getLastFrame()) ||
|
||||
(currentAnimationProperties.getRunning() && !_previousAnimationProperties.getRunning())) {
|
||||
|
||||
// when we start interface and the property is are set then the current frame is initialized to -1
|
||||
if (_currentFrame < 0) {
|
||||
// don't reset _lastAnimated here because we need the timestamp from the ModelEntityItem constructor for when the properties were set
|
||||
_currentFrame = currentAnimationProperties.getCurrentFrame();
|
||||
setAnimationCurrentFrame(_currentFrame);
|
||||
} else {
|
||||
_lastAnimated = usecTimestampNow();
|
||||
_currentFrame = currentAnimationProperties.getFirstFrame();
|
||||
setAnimationCurrentFrame(currentAnimationProperties.getFirstFrame());
|
||||
}
|
||||
} else if (!currentAnimationProperties.getRunning() && _previousAnimationProperties.getRunning()) {
|
||||
_currentFrame = currentAnimationProperties.getFirstFrame();
|
||||
setAnimationCurrentFrame(_currentFrame);
|
||||
} else if (currentAnimationProperties.getCurrentFrame() != _previousAnimationProperties.getCurrentFrame()) {
|
||||
// don't reset _lastAnimated here because the currentFrame was set with the previous setting of _lastAnimated
|
||||
_currentFrame = currentAnimationProperties.getCurrentFrame();
|
||||
}
|
||||
|
||||
});
|
||||
_previousAnimationProperties = this->getAnimationProperties();
|
||||
|
||||
}
|
||||
|
||||
if (isAnimatingSomething()) {
|
||||
if (!(getAnimationFirstFrame() < 0) && !(getAnimationFirstFrame() > getAnimationLastFrame())) {
|
||||
updateFrameCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityItem::update(now);
|
||||
}
|
||||
|
||||
bool ModelEntityItem::needsToCallUpdate() const {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModelEntityItem::updateFrameCount() {
|
||||
|
||||
if (_currentFrame < 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_lastAnimated) {
|
||||
_lastAnimated = usecTimestampNow();
|
||||
return;
|
||||
}
|
||||
|
||||
auto now = usecTimestampNow();
|
||||
|
||||
// update the interval since the last animation.
|
||||
auto interval = now - _lastAnimated;
|
||||
_lastAnimated = now;
|
||||
|
||||
// if fps is negative then increment timestamp and return.
|
||||
if (getAnimationFPS() < 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
int updatedFrameCount = getAnimationLastFrame() - getAnimationFirstFrame() + 1;
|
||||
|
||||
if (!getAnimationHold() && getAnimationIsPlaying()) {
|
||||
float deltaTime = (float)interval / (float)USECS_PER_SECOND;
|
||||
_currentFrame += (deltaTime * getAnimationFPS());
|
||||
if (_currentFrame > getAnimationLastFrame()) {
|
||||
if (getAnimationLoop()) {
|
||||
_currentFrame = getAnimationFirstFrame() + (int)(glm::floor(_currentFrame - getAnimationFirstFrame())) % (updatedFrameCount - 1);
|
||||
} else {
|
||||
_currentFrame = getAnimationLastFrame();
|
||||
}
|
||||
} else if (_currentFrame < getAnimationFirstFrame()) {
|
||||
if (getAnimationFirstFrame() < 0) {
|
||||
_currentFrame = 0;
|
||||
} else {
|
||||
_currentFrame = getAnimationFirstFrame();
|
||||
}
|
||||
}
|
||||
// qCDebug(entities) << "in update frame " << _currentFrame;
|
||||
setAnimationCurrentFrame(_currentFrame);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ModelEntityItem::debugDump() const {
|
||||
qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID();
|
||||
qCDebug(entities) << " edited ago:" << getEditedAgo();
|
||||
|
@ -538,6 +639,13 @@ void ModelEntityItem::setAnimationLoop(bool loop) {
|
|||
});
|
||||
}
|
||||
|
||||
bool ModelEntityItem::getAnimationLoop() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _animationProperties.getLoop();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void ModelEntityItem::setAnimationHold(bool hold) {
|
||||
withWriteLock([&] {
|
||||
_animationProperties.setHold(hold);
|
||||
|
@ -573,8 +681,9 @@ float ModelEntityItem::getAnimationLastFrame() const {
|
|||
return _animationProperties.getLastFrame();
|
||||
});
|
||||
}
|
||||
|
||||
bool ModelEntityItem::getAnimationIsPlaying() const {
|
||||
return resultWithReadLock<float>([&] {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _animationProperties.getRunning();
|
||||
});
|
||||
}
|
||||
|
@ -585,8 +694,15 @@ float ModelEntityItem::getAnimationCurrentFrame() const {
|
|||
});
|
||||
}
|
||||
|
||||
bool ModelEntityItem::isAnimatingSomething() const {
|
||||
float ModelEntityItem::getAnimationFPS() const {
|
||||
return resultWithReadLock<float>([&] {
|
||||
return _animationProperties.getFPS();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
bool ModelEntityItem::isAnimatingSomething() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return !_animationProperties.getURL().isEmpty() &&
|
||||
_animationProperties.getRunning() &&
|
||||
(_animationProperties.getFPS() != 0.0f);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <ThreadSafeValueCache.h>
|
||||
#include "AnimationPropertyGroup.h"
|
||||
|
||||
|
||||
class ModelEntityItem : public EntityItem {
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
@ -46,8 +47,11 @@ public:
|
|||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
|
||||
bool& somethingChanged) override;
|
||||
|
||||
//virtual void update(const quint64& now) override;
|
||||
//virtual bool needsToCallUpdate() const override;
|
||||
// update() and needstocallupdate() added back for the entity property fix
|
||||
virtual void update(const quint64& now) override;
|
||||
virtual bool needsToCallUpdate() const override;
|
||||
void updateFrameCount();
|
||||
|
||||
virtual void debugDump() const override;
|
||||
|
||||
void setShapeType(ShapeType type) override;
|
||||
|
@ -90,6 +94,7 @@ public:
|
|||
bool getAnimationAllowTranslation() const { return _animationProperties.getAllowTranslation(); };
|
||||
|
||||
void setAnimationLoop(bool loop);
|
||||
bool getAnimationLoop() const;
|
||||
|
||||
void setAnimationHold(bool hold);
|
||||
bool getAnimationHold() const;
|
||||
|
@ -102,6 +107,7 @@ public:
|
|||
|
||||
bool getAnimationIsPlaying() const;
|
||||
float getAnimationCurrentFrame() const;
|
||||
float getAnimationFPS() const;
|
||||
bool isAnimatingSomething() const;
|
||||
|
||||
static const QString DEFAULT_TEXTURES;
|
||||
|
@ -147,7 +153,7 @@ protected:
|
|||
};
|
||||
|
||||
QVector<ModelJointData> _localJointData;
|
||||
int _lastKnownCurrentFrame;
|
||||
int _lastKnownCurrentFrame{-1};
|
||||
|
||||
rgbColor _color;
|
||||
QString _modelURL;
|
||||
|
@ -160,6 +166,11 @@ protected:
|
|||
QString _textures;
|
||||
|
||||
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
||||
|
||||
private:
|
||||
uint64_t _lastAnimated{ 0 };
|
||||
AnimationPropertyGroup _previousAnimationProperties;
|
||||
float _currentFrame{ -1.0f };
|
||||
};
|
||||
|
||||
#endif // hifi_ModelEntityItem_h
|
||||
|
|
Loading…
Reference in a new issue