Working avater enter/leaves + manual threshold

This commit is contained in:
Olivier Prat 2017-07-03 12:40:58 +02:00
parent 87833abd31
commit af7957491b
5 changed files with 85 additions and 47 deletions

View file

@ -66,14 +66,14 @@ float evalFadeNoiseGradient(vec3 position) {
vec4 maskXY = mix(maskLowZ, maskHighZ, noisePositionFraction.z); vec4 maskXY = mix(maskLowZ, maskHighZ, noisePositionFraction.z);
vec2 maskY = mix(maskXY.xy, maskXY.zw, noisePositionFraction.x); vec2 maskY = mix(maskXY.xy, maskXY.zw, noisePositionFraction.x);
return mix(maskY.x, maskY.y, noisePositionFraction.y) * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.w; float noise = mix(maskY.x, maskY.y, noisePositionFraction.y);
noise -= 0.5; // Center on value 0
return noise * fadeParameters[fadeCategory]._noiseInvSizeAndLevel.w;
} }
float evalFadeBaseGradient(vec3 position) { float evalFadeBaseGradient(vec3 position) {
float gradient = length((position - fadeBaseOffset) * fadeParameters[fadeCategory]._baseInvSizeAndLevel.xyz); float gradient = length((position - fadeBaseOffset) * fadeParameters[fadeCategory]._baseInvSizeAndLevel.xyz);
if (fadeParameters[fadeCategory]._invertBase!=0) { gradient = mod(gradient, 1.0)-0.5; // Center on value 0.5
gradient = 1.0 - gradient;
}
gradient *= fadeParameters[fadeCategory]._baseInvSizeAndLevel.w; gradient *= fadeParameters[fadeCategory]._baseInvSizeAndLevel.w;
return gradient; return gradient;
} }
@ -81,17 +81,15 @@ float evalFadeBaseGradient(vec3 position) {
float evalFadeGradient(vec3 position) { float evalFadeGradient(vec3 position) {
float baseGradient = evalFadeBaseGradient(position); float baseGradient = evalFadeBaseGradient(position);
float noiseGradient = evalFadeNoiseGradient(position); float noiseGradient = evalFadeNoiseGradient(position);
float gradient = (noiseGradient-0.5*fadeParameters[fadeCategory]._baseInvSizeAndLevel.w); float gradient = noiseGradient+baseGradient+0.5;
// This is to be sure the noise is zero at the start of the gradient
gradient *= (1-baseGradient*baseGradient);
gradient += baseGradient;
return gradient; return gradient;
} }
float evalFadeAlpha(vec3 position) { float evalFadeAlpha(vec3 position) {
float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x; //float edgeWidth = fadeParameters[fadeCategory]._edgeWidthInvWidth.x;
float cutoff = mix(-edgeWidth, 1.0+edgeWidth, fadeThreshold); //float cutoff = mix(-edgeWidth, 1.0+edgeWidth, fadeThreshold);
float cutoff = fadeThreshold;
return evalFadeGradient(position)-cutoff; return evalFadeGradient(position)-cutoff;
} }
@ -104,6 +102,10 @@ void applyFadeClip(vec3 position) {
void applyFade(vec3 position, out vec3 emissive) { void applyFade(vec3 position, out vec3 emissive) {
float alpha = evalFadeAlpha(position); float alpha = evalFadeAlpha(position);
if (fadeParameters[fadeCategory]._invertBase!=0) {
alpha = -alpha;
}
if (alpha < 0) { if (alpha < 0) {
discard; discard;
} }
@ -111,12 +113,12 @@ void applyFade(vec3 position, out vec3 emissive) {
float edgeMask = alpha * fadeParameters[fadeCategory]._edgeWidthInvWidth.y; float edgeMask = alpha * fadeParameters[fadeCategory]._edgeWidthInvWidth.y;
float edgeAlpha = 1.0-clamp(edgeMask, 0, 1); float edgeAlpha = 1.0-clamp(edgeMask, 0, 1);
//edgeMask = step(edgeMask, 1.f); edgeMask = step(edgeMask, 1.f);
edgeMask = edgeMask > 1.f ? 0.f : 1.f;
edgeAlpha *= edgeAlpha; // Square to have a nice ease out edgeAlpha *= edgeAlpha; // Square to have a nice ease out
vec4 color = mix(fadeParameters[fadeCategory]._innerEdgeColor, fadeParameters[fadeCategory]._outerEdgeColor, edgeAlpha); vec4 color = mix(fadeParameters[fadeCategory]._innerEdgeColor, fadeParameters[fadeCategory]._outerEdgeColor, edgeAlpha);
emissive = color.rgb * edgeMask * color.a; emissive = color.rgb * edgeMask * color.a;
} }
<@endfunc@> <@endfunc@>
<@endif@> <@endif@>

View file

@ -250,6 +250,9 @@ FadeConfigureJob::FadeConfigureJob(FadeCommonParameters::Pointer commonParams) :
void FadeConfigureJob::configure(const Config& config) { void FadeConfigureJob::configure(const Config& config) {
assert(_parameters); assert(_parameters);
_parameters->_editedCategory = config.editedCategory; _parameters->_editedCategory = config.editedCategory;
_parameters->_isManualThresholdEnabled = config.manualFade;
_parameters->_manualThreshold = config.manualThreshold;
for (auto i = 0; i < FadeJobConfig::EVENT_CATEGORY_COUNT; i++) { for (auto i = 0; i < FadeJobConfig::EVENT_CATEGORY_COUNT; i++) {
auto& configuration = _configurations[i]; auto& configuration = _configurations[i];
@ -267,6 +270,7 @@ void FadeConfigureJob::configure(const Config& config) {
configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x; configuration._edgeWidthInvWidth.y = 1.f / configuration._edgeWidthInvWidth.x;
configuration._innerEdgeColor = config.edgeInnerColor[i]; configuration._innerEdgeColor = config.edgeInnerColor[i];
configuration._outerEdgeColor = config.edgeOuterColor[i]; configuration._outerEdgeColor = config.edgeOuterColor[i];
_parameters->_thresholdScale[i] = 1.f + 2.f*(configuration._edgeWidthInvWidth.x + std::max(0.f, (config.noiseLevel[i] + config.baseLevel[i])*0.5f-0.5f));
} }
_isBufferDirty = true; _isBufferDirty = true;
} }
@ -276,7 +280,7 @@ void FadeConfigureJob::run(const render::RenderContextPointer& renderContext, co
auto& configurations = output.edit1().edit(); auto& configurations = output.edit1().edit();
std::copy(_configurations, _configurations + FadeJobConfig::EVENT_CATEGORY_COUNT, configurations.parameters); std::copy(_configurations, _configurations + FadeJobConfig::EVENT_CATEGORY_COUNT, configurations.parameters);
if (_parameters->_editedCategory == FadeJobConfig::USER_ENTER_LEAVE_DOMAIN) { if (_parameters->_editedCategory == FadeJobConfig::USER_ENTER_LEAVE_DOMAIN) {
configurations.parameters[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._baseInvSizeAndLevel.y = 2.f / input.getDimensions().y; configurations.parameters[FadeJobConfig::USER_ENTER_LEAVE_DOMAIN]._baseInvSizeAndLevel.y = 1.0f / input.getDimensions().y;
} }
_isBufferDirty = false; _isBufferDirty = false;
} }
@ -314,10 +318,10 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const
// Update interactive edit effect // Update interactive edit effect
if (_parameters->_isEditEnabled) { if (_parameters->_isEditEnabled) {
updateFadeEdit(inItems.front()); updateFadeEdit(renderContext, inItems.front());
} }
else { else {
_editStartTime = 0; _editPreviousTime = 0;
} }
// Setup camera, projection and viewport for all items // Setup camera, projection and viewport for all items
@ -362,9 +366,10 @@ void FadeRenderJob::run(const render::RenderContextPointer& renderContext, const
} }
} }
float FadeRenderJob::computeElementEnterThreshold(double time) const { float FadeRenderJob::computeElementEnterThreshold(double time, const double period) const {
assert(period > 0.0);
float fadeAlpha = 1.0f; float fadeAlpha = 1.0f;
const double INV_FADE_PERIOD = 1.0 / (double)(_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]); const double INV_FADE_PERIOD = 1.0 / period;
double fraction = time * INV_FADE_PERIOD; double fraction = time * INV_FADE_PERIOD;
fraction = std::max(fraction, 0.0); fraction = std::max(fraction, 0.0);
if (fraction < 1.0) { if (fraction < 1.0) {
@ -376,31 +381,35 @@ float FadeRenderJob::computeElementEnterThreshold(double time) const {
float FadeRenderJob::computeFadePercent(quint64 startTime) { float FadeRenderJob::computeFadePercent(quint64 startTime) {
const double time = (double)(int64_t(usecTimestampNow()) - int64_t(startTime)) / (double)(USECS_PER_SECOND); const double time = (double)(int64_t(usecTimestampNow()) - int64_t(startTime)) / (double)(USECS_PER_SECOND);
assert(_currentInstance); assert(_currentInstance);
return _currentInstance->computeElementEnterThreshold(time); return _currentInstance->computeElementEnterThreshold(time, _currentInstance->_parameters->_durations[FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN]);
} }
void FadeRenderJob::updateFadeEdit(const render::ItemBound& itemBounds) { void FadeRenderJob::updateFadeEdit(const render::RenderContextPointer& renderContext, const render::ItemBound& itemBounds) {
if (_editStartTime == 0) { if (_editPreviousTime == 0) {
_editStartTime = usecTimestampNow(); _editPreviousTime = usecTimestampNow();
_editTime = 0.0;
} }
const double time = (int64_t(usecTimestampNow()) - int64_t(_editStartTime)) / double(USECS_PER_SECOND); uint64_t now = usecTimestampNow();
const double deltaTime = (int64_t(now) - int64_t(_editPreviousTime)) / double(USECS_PER_SECOND);
const float eventDuration = _parameters->_durations[_parameters->_editedCategory]; const float eventDuration = _parameters->_durations[_parameters->_editedCategory];
const double waitTime = 0.5; // Wait between fade in and out
double cycleTime = fmod(_editTime, (eventDuration + waitTime) * 2.0);
_editTime += deltaTime;
_editPreviousTime = now;
switch (_parameters->_editedCategory) { switch (_parameters->_editedCategory) {
case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN: case FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN:
{ {
const double waitTime = 0.5; // Wait between fade in and out
double cycleTime = fmod(time, (eventDuration+waitTime) * 2.0);
if (cycleTime < eventDuration) { if (cycleTime < eventDuration) {
_editThreshold = 1.f-computeElementEnterThreshold(cycleTime); _editThreshold = 1.f-computeElementEnterThreshold(cycleTime, eventDuration);
} }
else if (cycleTime < (eventDuration + waitTime)) { else if (cycleTime < (eventDuration + waitTime)) {
_editThreshold = 0.f; _editThreshold = 0.f;
} }
else if (cycleTime < (2 * eventDuration + waitTime)) { else if (cycleTime < (2 * eventDuration + waitTime)) {
_editThreshold = computeElementEnterThreshold(cycleTime- (eventDuration + waitTime)); _editThreshold = computeElementEnterThreshold(cycleTime- (eventDuration + waitTime), eventDuration);
} }
else { else {
_editThreshold = 1.f; _editThreshold = 1.f;
@ -416,28 +425,21 @@ void FadeRenderJob::updateFadeEdit(const render::ItemBound& itemBounds) {
case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN: case FadeJobConfig::USER_ENTER_LEAVE_DOMAIN:
{ {
const double waitTime = 0.5; // Wait between fade in and out _editNoiseOffset.x = _editTime*0.5;
double cycleTime = fmod(time, (eventDuration + waitTime) * 2.0);
_editNoiseOffset.x = time*0.5;
_editNoiseOffset.y = 0.f; _editNoiseOffset.y = 0.f;
_editNoiseOffset.z = time*0.75; _editNoiseOffset.z = _editTime*0.75;
_editBaseOffset.x = 0.f; _editBaseOffset = itemBounds.bound.calcCenter();
_editBaseOffset.y = -itemBounds.bound.getDimensions().y; _editBaseOffset.y -= itemBounds.bound.getDimensions().y/2.f;
_editBaseOffset.z = 0.f;
{
}
if (cycleTime < eventDuration) { if (cycleTime < eventDuration) {
_editThreshold = 1.f - computeElementEnterThreshold(cycleTime); _editThreshold = 1.f - computeElementEnterThreshold(cycleTime, eventDuration);
} }
else if (cycleTime < (eventDuration + waitTime)) { else if (cycleTime < (eventDuration + waitTime)) {
_editThreshold = 0.f; _editThreshold = 0.f;
} }
else if (cycleTime < (2 * eventDuration + waitTime)) { else if (cycleTime < (2 * eventDuration + waitTime)) {
_editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime)); _editThreshold = computeElementEnterThreshold(cycleTime - (eventDuration + waitTime), eventDuration);
} }
else { else {
_editThreshold = 1.f; _editThreshold = 1.f;
@ -451,6 +453,10 @@ void FadeRenderJob::updateFadeEdit(const render::ItemBound& itemBounds) {
default: default:
assert(false); assert(false);
} }
if (_parameters->_isManualThresholdEnabled) {
_editThreshold = _parameters->_manualThreshold;
}
} }
void FadeRenderJob::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation) { void FadeRenderJob::bindPerBatch(gpu::Batch& batch, int fadeMaskMapLocation, int fadeBufferLocation) {
@ -496,9 +502,12 @@ bool FadeRenderJob::bindPerItem(gpu::Batch& batch, const gpu::Pipeline* pipeline
eventCategory = _currentInstance->_parameters->_editedCategory; eventCategory = _currentInstance->_parameters->_editedCategory;
threshold = _currentInstance->_editThreshold; threshold = _currentInstance->_editThreshold;
noiseOffset += _currentInstance->_editNoiseOffset; noiseOffset += _currentInstance->_editNoiseOffset;
baseOffset += _currentInstance->_editBaseOffset; // This works supposing offset is the world position of the object that is fading.
baseOffset = _currentInstance->_editBaseOffset - offset;
} }
threshold = (threshold-0.5f)*_currentInstance->_parameters->_thresholdScale[eventCategory] + 0.5f;
batch._glUniform1i(fadeCategoryLocation, eventCategory); batch._glUniform1i(fadeCategoryLocation, eventCategory);
batch._glUniform1f(fadeThresholdLocation, threshold); batch._glUniform1f(fadeThresholdLocation, threshold);
// This is really temporary // This is really temporary

View file

@ -52,6 +52,8 @@ class FadeJobConfig : public render::Job::Config {
Q_PROPERTY(float edgeOuterColorG READ getEdgeOuterColorG WRITE setEdgeOuterColorG NOTIFY dirty) Q_PROPERTY(float edgeOuterColorG READ getEdgeOuterColorG WRITE setEdgeOuterColorG NOTIFY dirty)
Q_PROPERTY(float edgeOuterColorB READ getEdgeOuterColorB WRITE setEdgeOuterColorB NOTIFY dirty) Q_PROPERTY(float edgeOuterColorB READ getEdgeOuterColorB WRITE setEdgeOuterColorB NOTIFY dirty)
Q_PROPERTY(float edgeOuterIntensity READ getEdgeOuterIntensity WRITE setEdgeOuterIntensity NOTIFY dirty) Q_PROPERTY(float edgeOuterIntensity READ getEdgeOuterIntensity WRITE setEdgeOuterIntensity NOTIFY dirty)
Q_PROPERTY(bool manualFade MEMBER manualFade NOTIFY dirty)
Q_PROPERTY(float manualThreshold MEMBER manualThreshold NOTIFY dirty)
public: public:
@ -125,9 +127,11 @@ public:
void setEdgeOuterIntensity(float value); void setEdgeOuterIntensity(float value);
float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; } float getEdgeOuterIntensity() const { return edgeOuterColor[editedCategory].a; }
bool manualFade{ false };
float manualThreshold{ 0.f };
int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN }; int editedCategory{ ELEMENT_ENTER_LEAVE_DOMAIN };
glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{ glm::vec3 noiseSize[EVENT_CATEGORY_COUNT]{
{ 1.f, 1.f, 1.f }, // ELEMENT_ENTER_LEAVE_DOMAIN { 0.75f, 0.75f, 0.75f }, // ELEMENT_ENTER_LEAVE_DOMAIN
{ 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_OWNER
{ 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER { 0.4f, 0.4f, 0.4f }, // BUBBLE_ISECT_TRESPASSER
{ 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN { 10.f, 0.01f, 10.0f }, // USER_ENTER_LEAVE_DOMAIN
@ -201,6 +205,9 @@ struct FadeCommonParameters
using Pointer = std::shared_ptr<FadeCommonParameters>; using Pointer = std::shared_ptr<FadeCommonParameters>;
bool _isEditEnabled{ false }; bool _isEditEnabled{ false };
bool _isManualThresholdEnabled{ false };
float _manualThreshold{ 0.f };
float _thresholdScale[FadeJobConfig::EVENT_CATEGORY_COUNT];
int _editedCategory{ FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN }; int _editedCategory{ FadeJobConfig::ELEMENT_ENTER_LEAVE_DOMAIN };
float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]{ float _durations[FadeJobConfig::EVENT_CATEGORY_COUNT]{
30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN 30.0f, // ELEMENT_ENTER_LEAVE_DOMAIN
@ -312,15 +319,16 @@ private:
render::ShapePlumberPointer _shapePlumber; render::ShapePlumberPointer _shapePlumber;
FadeCommonParameters::Pointer _parameters; FadeCommonParameters::Pointer _parameters;
float computeElementEnterThreshold(double time) const; float computeElementEnterThreshold(double time, const double period) const;
// Everything needed for interactive edition // Everything needed for interactive edition
uint64_t _editStartTime{ 0 }; uint64_t _editPreviousTime{ 0 };
double _editTime{ 0.0 };
float _editThreshold{ 0.f }; float _editThreshold{ 0.f };
glm::vec3 _editNoiseOffset{ 0.f, 0.f, 0.f }; glm::vec3 _editNoiseOffset{ 0.f, 0.f, 0.f };
glm::vec3 _editBaseOffset{ 0.f, 0.f, 0.f }; glm::vec3 _editBaseOffset{ 0.f, 0.f, 0.f };
void updateFadeEdit(const render::ItemBound& itemBounds); void updateFadeEdit(const render::RenderContextPointer& renderContext, const render::ItemBound& itemBounds);
}; };
#endif // hifi_FadeEffect_h #endif // hifi_FadeEffect_h

View file

@ -66,7 +66,7 @@ void main(void) {
albedo, albedo,
roughness, roughness,
getMaterialMetallic(mat), getMaterialMetallic(mat),
emissive, emissive+fadeEmissive,
occlusionTex, occlusionTex,
scattering); scattering);
} }

View file

@ -46,6 +46,25 @@ Column {
} }
} }
} }
Row {
CheckBox {
text: "Manual"
checked: root.config["manualFade"]
onCheckedChanged: {
root.config["manualFade"] = checked;
}
}
ConfigSlider {
label: "Threshold"
integral: false
config: root.config
property: "manualThreshold"
max: 1.0
min: 0.0
width: 400
}
}
Component { Component {
id: paramWidgets id: paramWidgets