void ModelEntityItem::setAnimationSettings(const QString& value) { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, currentFrame, or running, those values will be parsed out and // will over ride the regular animation settings QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); if (settingsMap.contains("fps")) { float fps = settingsMap["fps"].toFloat(); setAnimationFPS(fps); } // old settings used frameIndex if (settingsMap.contains("frameIndex")) { float currentFrame = settingsMap["frameIndex"].toFloat(); #ifdef WANT_DEBUG if (isAnimatingSomething()) { qCDebug(entities) << "ModelEntityItem::setAnimationSettings() calling setAnimationFrameIndex()..."; qCDebug(entities) << " model URL:" << getModelURL(); qCDebug(entities) << " animation URL:" << getAnimationURL(); qCDebug(entities) << " settings:" << value; qCDebug(entities) << " settingsMap[frameIndex]:" << settingsMap["frameIndex"]; qCDebug(entities" currentFrame: %20.5f", currentFrame); } #endif setAnimationCurrentFrame(currentFrame); } if (settingsMap.contains("running")) { bool running = settingsMap["running"].toBool(); if (running != getAnimationIsPlaying()) { setAnimationIsPlaying(running); } } if (settingsMap.contains("firstFrame")) { float firstFrame = settingsMap["firstFrame"].toFloat(); setAnimationFirstFrame(firstFrame); } if (settingsMap.contains("lastFrame")) { float lastFrame = settingsMap["lastFrame"].toFloat(); setAnimationLastFrame(lastFrame); } if (settingsMap.contains("loop")) { bool loop = settingsMap["loop"].toBool(); setAnimationLoop(loop); } if (settingsMap.contains("hold")) { bool hold = settingsMap["hold"].toBool(); setAnimationHold(hold); } _dirtyFlags |= Simulation::DIRTY_UPDATEABLE; }
void ParticleEffectEntityItem::setAnimationFrameIndex(float value) { #ifdef WANT_DEBUG if (isAnimatingSomething()) { qCDebug(entities) << "ParticleEffectEntityItem::setAnimationFrameIndex()"; qCDebug(entities) << " value:" << value; qCDebug(entities) << " was:" << _animationLoop.getFrameIndex(); } #endif _animationLoop.setFrameIndex(value); }
void ParticleEffectEntityItem::update(const quint64& now) { float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND; _lastAnimated = now; // only advance the frame index if we're playing if (getAnimationIsPlaying()) { _animationLoop.simulate(deltaTime); } if (isAnimatingSomething()) { stepSimulation(deltaTime); } EntityItem::update(now); // let our base class handle it's updates... }
void RenderableModelEntityItem::updateModelBounds() { if (!hasModel() || !_model) { return; } bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething(); glm::vec3 dimensions = getDimensions(); if ((movingOrAnimating || _needsInitialSimulation || _needsJointSimulation || _model->getTranslation() != getPosition() || _model->getScaleToFitDimensions() != dimensions || _model->getRotation() != getRotation() || _model->getRegistrationPoint() != getRegistrationPoint()) && _model->isActive() && _dimensionsInitialized) { doInitialModelSimulation(); _needsJointSimulation = false; } }
void ParticleEffectEntityItem::update(const quint64& now) { float deltaTime = (float)(now - _lastAnimated) / (float)USECS_PER_SECOND; _lastAnimated = now; // only advance the frame index if we're playing if (getAnimationIsPlaying()) { _animationLoop.simulate(deltaTime); } if (isAnimatingSomething()) { stepSimulation(deltaTime); // update the dimensions glm::vec3 dims; dims.x = glm::max(glm::abs(_particleMinBound.x), glm::abs(_particleMaxBound.x)) * 2.0f; dims.y = glm::max(glm::abs(_particleMinBound.y), glm::abs(_particleMaxBound.y)) * 2.0f; dims.z = glm::max(glm::abs(_particleMinBound.z), glm::abs(_particleMaxBound.z)) * 2.0f; setDimensions(dims); } EntityItem::update(now); // let our base class handle it's updates... }
void ParticleEffectEntityItem::setAnimationSettings(const QString& value) { // the animations setting is a JSON string that may contain various animation settings. // if it includes fps, frameIndex, or running, those values will be parsed out and // will over ride the regular animation settings QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8()); QJsonObject settingsAsJsonObject = settingsAsJson.object(); QVariantMap settingsMap = settingsAsJsonObject.toVariantMap(); if (settingsMap.contains("fps")) { float fps = settingsMap["fps"].toFloat(); setAnimationFPS(fps); } if (settingsMap.contains("frameIndex")) { float frameIndex = settingsMap["frameIndex"].toFloat(); #ifdef WANT_DEBUG if (isAnimatingSomething()) { qCDebug(entities) << "ParticleEffectEntityItem::setAnimationSettings() calling setAnimationFrameIndex()..."; qCDebug(entities) << " settings:" << value; qCDebug(entities) << " settingsMap[frameIndex]:" << settingsMap["frameIndex"]; qCDebug(entities, " frameIndex: %20.5f", frameIndex); } #endif setAnimationFrameIndex(frameIndex); } if (settingsMap.contains("running")) { bool running = settingsMap["running"].toBool(); if (running != getAnimationIsPlaying()) { setAnimationIsPlaying(running); } } if (settingsMap.contains("firstFrame")) { float firstFrame = settingsMap["firstFrame"].toFloat(); setAnimationFirstFrame(firstFrame); } if (settingsMap.contains("lastFrame")) { float lastFrame = settingsMap["lastFrame"].toFloat(); setAnimationLastFrame(lastFrame); } if (settingsMap.contains("loop")) { bool loop = settingsMap["loop"].toBool(); setAnimationLoop(loop); } if (settingsMap.contains("hold")) { bool hold = settingsMap["hold"].toBool(); setAnimationHold(hold); } if (settingsMap.contains("startAutomatically")) { bool startAutomatically = settingsMap["startAutomatically"].toBool(); setAnimationStartAutomatically(startAutomatically); } _animationSettings = value; _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; }
void ModelOverlay::update(float deltatime) { if (_updateModel) { _updateModel = false; _model->setSnapModelToCenter(true); Transform transform = evalRenderTransform(); if (_scaleToFit) { _model->setScaleToFit(true, transform.getScale() * getDimensions()); } else { _model->setScale(transform.getScale()); } _model->setRotation(transform.getRotation()); _model->setTranslation(transform.getTranslation()); _model->setURL(_url); _model->simulate(deltatime, true); } else { _model->simulate(deltatime); } _isLoaded = _model->isActive(); if (isAnimatingSomething()) { if (!jointsMapped()) { mapAnimationJoints(_model->getJointNames()); } animate(); } // check to see if when we added our model to the scene they were ready, if they were not ready, then // fix them up in the scene render::ScenePointer scene = qApp->getMain3DScene(); render::Transaction transaction; if (_model->needsFixupInScene()) { emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelRemovedFromScene(getID(), NestableType::Overlay, _model); _model->removeFromScene(scene, transaction); _model->addToScene(scene, transaction); auto newRenderItemIDs{ _model->fetchRenderItemIDs() }; transaction.updateItem<Overlay>(getRenderItemID(), [newRenderItemIDs](Overlay& data) { auto modelOverlay = static_cast<ModelOverlay*>(&data); modelOverlay->setSubRenderItemIDs(newRenderItemIDs); }); processMaterials(); emit DependencyManager::get<scriptable::ModelProviderFactory>()->modelAddedToScene(getID(), NestableType::Overlay, _model); } if (_visibleDirty) { _visibleDirty = false; // don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0 | (_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE), false); } if (_drawInFrontDirty) { _drawInFrontDirty = false; _model->setLayeredInFront(getDrawInFront(), scene); } if (_drawInHUDDirty) { _drawInHUDDirty = false; _model->setLayeredInHUD(getDrawHUDLayer(), scene); } scene->enqueueTransaction(transaction); if (!_texturesLoaded && _model->getGeometry() && _model->getGeometry()->areTexturesLoaded()) { _texturesLoaded = true; _model->updateRenderItems(); } }
void RenderableModelEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RMEIrender"); assert(getType() == EntityTypes::Model); bool drawAsModel = hasModel(); glm::vec3 position = getPosition() * (float)TREE_SCALE; float size = getSize() * (float)TREE_SCALE; glm::vec3 dimensions = getDimensions() * (float)TREE_SCALE; if (drawAsModel) { remapTextures(); glPushMatrix(); { float alpha = getLocalRenderAlpha(); if (!_model || _needsModelReload) { // TODO: this getModel() appears to be about 3% of model render time. We should optimize PerformanceTimer perfTimer("getModel"); EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer); getModel(renderer); } if (_model) { // handle animations.. if (hasAnimation()) { if (!jointsMapped()) { QStringList modelJointNames = _model->getJointNames(); mapJoints(modelJointNames); } if (jointsMapped()) { QVector<glm::quat> frameData = getAnimationFrame(); for (int i = 0; i < frameData.size(); i++) { _model->setJointState(i, true, frameData[i]); } } } glm::quat rotation = getRotation(); if (needsToCallUpdate() && _model->isActive()) { _model->setScaleToFit(true, dimensions); _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); _model->setRotation(rotation); _model->setTranslation(position); // make sure to simulate so everything gets set up correctly for rendering { PerformanceTimer perfTimer("_model->simulate"); _model->simulate(0.0f); } _needsInitialSimulation = false; } if (_model->isActive()) { // TODO: this is the majority of model render time. And rendering of a cube model vs the basic Box render // is significantly more expensive. Is there a way to call this that doesn't cost us as much? PerformanceTimer perfTimer("model->render"); // filter out if not needed to render if (args && (args->_renderMode == RenderArgs::SHADOW_RENDER_MODE)) { if (isMoving() || isAnimatingSomething()) { _model->renderInScene(alpha, args); } } else { _model->renderInScene(alpha, args); } } else { // if we couldn't get a model, then just draw a cube glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); glPushMatrix(); glTranslatef(position.x, position.y, position.z); DependencyManager::get<DeferredLightingEffect>()->renderWireCube(size); glPopMatrix(); } } else { // if we couldn't get a model, then just draw a cube glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); glPushMatrix(); glTranslatef(position.x, position.y, position.z); DependencyManager::get<DeferredLightingEffect>()->renderWireCube(size); glPopMatrix(); } } glPopMatrix(); } else { glColor3ub(getColor()[RED_INDEX],getColor()[GREEN_INDEX],getColor()[BLUE_INDEX]); glPushMatrix(); glTranslatef(position.x, position.y, position.z); DependencyManager::get<DeferredLightingEffect>()->renderWireCube(size); glPopMatrix(); } }
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles // the per frame simulation/update that might be required if the models properties changed. void RenderableModelEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RMEIrender"); assert(getType() == EntityTypes::Model); if (hasModel()) { if (_model) { // check if the URL has changed auto& currentURL = getParsedModelURL(); if (currentURL != _model->getURL()) { qCDebug(entitiesrenderer).noquote() << "Updating model URL: " << currentURL.toDisplayString(); _model->setURL(currentURL); } render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene bool shouldShowCollisionHull = (args->_debugFlags & (int)RenderArgs::RENDER_DEBUG_HULLS) > 0; if (_model->needsFixupInScene() || _showCollisionHull != shouldShowCollisionHull) { _showCollisionHull = shouldShowCollisionHull; render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(getThisPointer(), statusGetters); _model->addToScene(scene, pendingChanges, statusGetters, _showCollisionHull); scene->enqueuePendingChanges(pendingChanges); } // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state // so most of the time we don't do anything in this function. _model->setVisibleInScene(getVisible(), scene); } remapTextures(); { // float alpha = getLocalRenderAlpha(); if (!_model || _needsModelReload) { // TODO: this getModel() appears to be about 3% of model render time. We should optimize PerformanceTimer perfTimer("getModel"); EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer); getModel(renderer); } if (_model) { if (hasAnimation()) { if (!jointsMapped()) { QStringList modelJointNames = _model->getJointNames(); mapJoints(modelJointNames); } } _jointDataLock.withWriteLock([&] { getAnimationFrame(); // relay any inbound joint changes from scripts/animation/network to the model/rig for (int index = 0; index < _absoluteJointRotationsInObjectFrame.size(); index++) { if (_absoluteJointRotationsInObjectFrameDirty[index]) { glm::quat rotation = _absoluteJointRotationsInObjectFrame[index]; _model->setJointRotation(index, true, rotation, 1.0f); _absoluteJointRotationsInObjectFrameDirty[index] = false; } } for (int index = 0; index < _absoluteJointTranslationsInObjectFrame.size(); index++) { if (_absoluteJointTranslationsInObjectFrameDirty[index]) { glm::vec3 translation = _absoluteJointTranslationsInObjectFrame[index]; _model->setJointTranslation(index, true, translation, 1.0f); _absoluteJointTranslationsInObjectFrameDirty[index] = false; } } }); bool movingOrAnimating = isMoving() || isAnimatingSomething(); if ((movingOrAnimating || _needsInitialSimulation || _model->getTranslation() != getPosition() || _model->getRotation() != getRotation() || _model->getRegistrationPoint() != getRegistrationPoint()) && _model->isActive() && _dimensionsInitialized) { _model->setScaleToFit(true, getDimensions()); _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); _model->setRotation(getRotation()); _model->setTranslation(getPosition()); // make sure to simulate so everything gets set up correctly for rendering { PerformanceTimer perfTimer("_model->simulate"); _model->simulate(0.0f); } _needsInitialSimulation = false; } } } } else { static glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); gpu::Batch& batch = *args->_batch; bool success; auto shapeTransform = getTransformToCenter(success); if (success) { batch.setModelTransform(Transform()); // we want to include the scale as well DependencyManager::get<GeometryCache>()->renderWireCubeInstance(batch, shapeTransform, greenColor); } } }
bool ModelEntityItem::needsToCallUpdate() const { return isAnimatingSomething() || EntityItem::needsToCallUpdate(); }
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles // the per frame simulation/update that might be required if the models properties changed. void RenderableModelEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RMEIrender"); assert(getType() == EntityTypes::Model); if (hasModel()) { if (_model) { if (getModelURL() != _model->getURL().toString()) { qDebug() << "Updating model URL: " << getModelURL(); _model->setURL(getModelURL()); } render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene if (_model->needsFixupInScene()) { render::PendingChanges pendingChanges; _model->removeFromScene(scene, pendingChanges); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(this, statusGetters); _model->addToScene(scene, pendingChanges, statusGetters); scene->enqueuePendingChanges(pendingChanges); } // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state // so most of the time we don't do anything in this function. _model->setVisibleInScene(getVisible(), scene); } remapTextures(); { // float alpha = getLocalRenderAlpha(); if (!_model || _needsModelReload) { // TODO: this getModel() appears to be about 3% of model render time. We should optimize PerformanceTimer perfTimer("getModel"); EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer); getModel(renderer); } if (_model) { // handle animations.. if (hasAnimation()) { if (!jointsMapped()) { QStringList modelJointNames = _model->getJointNames(); mapJoints(modelJointNames); } if (jointsMapped()) { bool newFrame; QVector<glm::quat> frameDataRotations; QVector<glm::vec3> frameDataTranslations; getAnimationFrame(newFrame, frameDataRotations, frameDataTranslations); assert(frameDataRotations.size() == frameDataTranslations.size()); if (newFrame) { for (int i = 0; i < frameDataRotations.size(); i++) { _model->setJointState(i, true, frameDataRotations[i], frameDataTranslations[i], 1.0f); } } } } bool movingOrAnimating = isMoving() || isAnimatingSomething(); if ((movingOrAnimating || _needsInitialSimulation) && _model->isActive() && _dimensionsInitialized) { _model->setScaleToFit(true, getDimensions()); _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); _model->setRotation(getRotation()); _model->setTranslation(getPosition()); // make sure to simulate so everything gets set up correctly for rendering { PerformanceTimer perfTimer("_model->simulate"); _model->simulate(0.0f); } _needsInitialSimulation = false; } } } } else { glm::vec4 greenColor(0.0f, 1.0f, 0.0f, 1.0f); RenderableDebugableEntityItem::renderBoundingBox(this, args, 0.0f, greenColor); } RenderableDebugableEntityItem::render(this, args); }
bool ParticleEffectEntityItem::needsToCallUpdate() const { return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate(); }