Merge pull request #11804 from amantley/character_entity_fixes

Fixed Entity Animation Property not applying to FBXs
This commit is contained in:
Brad Hefta-Gaub 2017-12-15 15:31:11 -08:00 committed by GitHub
commit 5087893097
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 172 additions and 44 deletions

View file

@ -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,

View file

@ -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();
}
}

View file

@ -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

View file

@ -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);

View file

@ -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);
};

View file

@ -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);

View file

@ -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