mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-06-07 02:41:13 +02:00
cleanup model fade logic
This commit is contained in:
parent
b7c1bfaf58
commit
10cdea9cd8
6 changed files with 58 additions and 57 deletions
|
@ -225,9 +225,6 @@ void CauterizedModel::updateRenderItems() {
|
||||||
foreach (auto itemID, keys) {
|
foreach (auto itemID, keys) {
|
||||||
pendingChanges.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) {
|
pendingChanges.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, deleteGeometryCounter](CauterizedMeshPartPayload& data) {
|
||||||
if (data._model && data._model->isLoaded()) {
|
if (data._model && data._model->isLoaded()) {
|
||||||
if (!data.hasStartedFade() && data._model->getGeometry()->areTexturesLoaded()) {
|
|
||||||
data.startFade();
|
|
||||||
}
|
|
||||||
// Ensure the model geometry was not reset between frames
|
// Ensure the model geometry was not reset between frames
|
||||||
if (deleteGeometryCounter == data._model->getGeometryCounter()) {
|
if (deleteGeometryCounter == data._model->getGeometryCounter()) {
|
||||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
||||||
|
|
|
@ -402,7 +402,7 @@ ItemKey ModelMeshPartPayload::getKey() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_hasFinishedFade) {
|
if (_fadeState != FADE_COMPLETE) {
|
||||||
builder.withTransparent();
|
builder.withTransparent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeKey::Builder builder;
|
ShapeKey::Builder builder;
|
||||||
if (isTranslucent || !_hasFinishedFade) {
|
if (isTranslucent || _fadeState != FADE_COMPLETE) {
|
||||||
builder.withTranslucent();
|
builder.withTranslucent();
|
||||||
}
|
}
|
||||||
if (hasTangents) {
|
if (hasTangents) {
|
||||||
|
@ -513,9 +513,10 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
float fadeRatio = _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f;
|
if (_fadeState != FADE_COMPLETE) {
|
||||||
if (!_hasColorAttrib || fadeRatio < 1.0f) {
|
batch._glColor4f(1.0f, 1.0f, 1.0f, computeFadeAlpha());
|
||||||
batch._glColor4f(1.0f, 1.0f, 1.0f, fadeRatio);
|
} else if (!_hasColorAttrib) {
|
||||||
|
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -528,17 +529,23 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline:
|
||||||
batch.setModelTransform(_transform);
|
batch.setModelTransform(_transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelMeshPartPayload::startFade() {
|
float ModelMeshPartPayload::computeFadeAlpha() const {
|
||||||
bool shouldFade = EntityItem::getEntitiesShouldFadeFunction()();
|
if (_fadeState == FADE_WAITING_TO_START) {
|
||||||
if (shouldFade) {
|
return 0.0f;
|
||||||
_fadeStartTime = usecTimestampNow();
|
|
||||||
_hasStartedFade = true;
|
|
||||||
_hasFinishedFade = false;
|
|
||||||
} else {
|
|
||||||
_isFading = true;
|
|
||||||
_hasStartedFade = true;
|
|
||||||
_hasFinishedFade = true;
|
|
||||||
}
|
}
|
||||||
|
float fadeAlpha = 1.0f;
|
||||||
|
const float INV_FADE_PERIOD = 1.0f / (float)(1 * USECS_PER_SECOND);
|
||||||
|
float fraction = (float)(usecTimestampNow() - _fadeStartTime) * INV_FADE_PERIOD;
|
||||||
|
if (fraction < 1.0f) {
|
||||||
|
fadeAlpha = Interpolate::simpleNonLinearBlend(fraction);
|
||||||
|
}
|
||||||
|
if (fadeAlpha >= 1.0f) {
|
||||||
|
_fadeState = FADE_COMPLETE;
|
||||||
|
// when fade-in completes we flag model for one last "render item update"
|
||||||
|
_model->setRenderItemsNeedUpdate();
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
return Interpolate::simpleNonLinearBlend(fadeAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelMeshPartPayload::render(RenderArgs* args) const {
|
void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
|
@ -548,33 +555,28 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
return; // bail asap
|
return; // bail asap
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't start the fade in, check if we are ready to now....
|
if (_fadeState == FADE_WAITING_TO_START) {
|
||||||
if (!_hasStartedFade && _model->isLoaded() && _model->getGeometry()->areTexturesLoaded()) {
|
if (_model->isLoaded() && _model->getGeometry()->areTexturesLoaded()) {
|
||||||
const_cast<ModelMeshPartPayload&>(*this).startFade();
|
if (EntityItem::getEntitiesShouldFadeFunction()()) {
|
||||||
|
_fadeStartTime = usecTimestampNow();
|
||||||
|
_fadeState = FADE_IN_PROGRESS;
|
||||||
|
} else {
|
||||||
|
_fadeState = FADE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
_model->setRenderItemsNeedUpdate();
|
||||||
// If we still didn't start the fade in, bail
|
} else {
|
||||||
if (!_hasStartedFade) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When an individual mesh parts like this finishes its fade, we will mark the Model as
|
|
||||||
// having render items that need updating
|
|
||||||
bool nextIsFading = _isFading ? isStillFading() : false;
|
|
||||||
bool startFading = !_isFading && !_hasFinishedFade && _hasStartedFade;
|
|
||||||
bool endFading = _isFading && !nextIsFading;
|
|
||||||
if (startFading || endFading) {
|
|
||||||
_isFading = startFading;
|
|
||||||
_hasFinishedFade = endFading;
|
|
||||||
_model->setRenderItemsNeedUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Batch& batch = *(args->_batch);
|
if (!args) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!getShapeKey().isValid()) {
|
if (!getShapeKey().isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpu::Batch& batch = *(args->_batch);
|
||||||
auto locations = args->_pipeline->locations;
|
auto locations = args->_pipeline->locations;
|
||||||
assert(locations);
|
assert(locations);
|
||||||
|
|
||||||
|
@ -588,9 +590,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
// apply material properties
|
// apply material properties
|
||||||
bindMaterial(batch, locations);
|
bindMaterial(batch, locations);
|
||||||
|
|
||||||
if (args) {
|
|
||||||
args->_details._materialSwitches++;
|
args->_details._materialSwitches++;
|
||||||
}
|
|
||||||
|
|
||||||
// Draw!
|
// Draw!
|
||||||
{
|
{
|
||||||
|
@ -598,8 +598,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
drawCall(batch);
|
drawCall(batch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args) {
|
|
||||||
const int INDICES_PER_TRIANGLE = 3;
|
const int INDICES_PER_TRIANGLE = 3;
|
||||||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
|
|
||||||
#include <model/Geometry.h>
|
#include <model/Geometry.h>
|
||||||
|
|
||||||
|
const uint8_t FADE_WAITING_TO_START = 0;
|
||||||
|
const uint8_t FADE_IN_PROGRESS = 1;
|
||||||
|
const uint8_t FADE_COMPLETE = 2;
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
|
|
||||||
class MeshPartPayload {
|
class MeshPartPayload {
|
||||||
|
@ -87,10 +91,7 @@ public:
|
||||||
void updateTransformForSkinnedMesh(const Transform& transform,
|
void updateTransformForSkinnedMesh(const Transform& transform,
|
||||||
const QVector<glm::mat4>& clusterMatrices);
|
const QVector<glm::mat4>& clusterMatrices);
|
||||||
|
|
||||||
// Entity fade in
|
float computeFadeAlpha() const;
|
||||||
void startFade();
|
|
||||||
bool hasStartedFade() { return _hasStartedFade; }
|
|
||||||
bool isStillFading() const { return Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f; }
|
|
||||||
|
|
||||||
// Render Item interface
|
// Render Item interface
|
||||||
render::ItemKey getKey() const override;
|
render::ItemKey getKey() const override;
|
||||||
|
@ -113,10 +114,8 @@ public:
|
||||||
bool _isBlendShaped{ false };
|
bool _isBlendShaped{ false };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
quint64 _fadeStartTime { 0 };
|
mutable quint64 _fadeStartTime { 0 };
|
||||||
bool _hasStartedFade { false };
|
mutable uint8_t _fadeState { FADE_WAITING_TO_START };
|
||||||
mutable bool _hasFinishedFade { false };
|
|
||||||
mutable bool _isFading { false };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
|
@ -227,9 +227,6 @@ void Model::updateRenderItems() {
|
||||||
foreach (auto itemID, self->_modelMeshRenderItems.keys()) {
|
foreach (auto itemID, self->_modelMeshRenderItems.keys()) {
|
||||||
pendingChanges.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, deleteGeometryCounter](ModelMeshPartPayload& data) {
|
pendingChanges.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, deleteGeometryCounter](ModelMeshPartPayload& data) {
|
||||||
if (data._model && data._model->isLoaded()) {
|
if (data._model && data._model->isLoaded()) {
|
||||||
if (!data.hasStartedFade() && data._model->getGeometry()->areTexturesLoaded()) {
|
|
||||||
data.startFade();
|
|
||||||
}
|
|
||||||
// Ensure the model geometry was not reset between frames
|
// Ensure the model geometry was not reset between frames
|
||||||
if (deleteGeometryCounter == data._model->_deleteGeometryCounter) {
|
if (deleteGeometryCounter == data._model->_deleteGeometryCounter) {
|
||||||
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
// lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box.
|
||||||
|
@ -1450,7 +1447,6 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) {
|
||||||
|
|
||||||
{
|
{
|
||||||
Lock lock(_mutex);
|
Lock lock(_mutex);
|
||||||
|
|
||||||
_modelsRequiringBlends.insert(model);
|
_modelsRequiringBlends.insert(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,13 @@ float Interpolate::interpolate3Points(float y1, float y2, float y3, float u) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Interpolate::simpleNonLinearBlend(float fraction) {
|
||||||
|
// uses arctan() to map a linear distribution in domain [0,1] to a non-linear blend (slow out, slow in) in range [0,1]
|
||||||
|
const float WIDTH = 20.0f;
|
||||||
|
const float INV_ARCTAN_WIDTH = 0.339875327433f; // 1 / (2 * atan(WIDTH/2))
|
||||||
|
return 0.5f + atanf(WIDTH * (fraction - 0.5f)) * INV_ARCTAN_WIDTH;
|
||||||
|
}
|
||||||
|
|
||||||
float Interpolate::calculateFadeRatio(quint64 start) {
|
float Interpolate::calculateFadeRatio(quint64 start) {
|
||||||
const float FADE_TIME = 1.0f;
|
const float FADE_TIME = 1.0f;
|
||||||
float t = 2.0f * std::min(((float)(usecTimestampNow() - start)) / ((float)(FADE_TIME * USECS_PER_SECOND)), 1.0f);
|
float t = 2.0f * std::min(((float)(usecTimestampNow() - start)) / ((float)(FADE_TIME * USECS_PER_SECOND)), 1.0f);
|
||||||
|
|
|
@ -25,6 +25,10 @@ public:
|
||||||
// pass through all three y values. Return value lies wholly within the range of y values passed in.
|
// pass through all three y values. Return value lies wholly within the range of y values passed in.
|
||||||
static float interpolate3Points(float y1, float y2, float y3, float u);
|
static float interpolate3Points(float y1, float y2, float y3, float u);
|
||||||
|
|
||||||
|
// returns smooth in and out blend between 0 and 1
|
||||||
|
// DANGER: assumes fraction is properly inside range [0, 1]
|
||||||
|
static float simpleNonLinearBlend(float fraction);
|
||||||
|
|
||||||
static float calculateFadeRatio(quint64 start);
|
static float calculateFadeRatio(quint64 start);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue