Skip to content

Commit

Permalink
change: Fix fade interpolated alpha
Browse files Browse the repository at this point in the history
I previous didn't properly account for duration when interpolation calculation occurs
  • Loading branch information
FlashyReese committed May 23, 2024
1 parent c7e3992 commit 4b0f3ec
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public abstract class AbstractSkybox implements NuitSkybox {
protected Conditions conditions = Conditions.DEFAULT;
protected Decorations decorations = Decorations.DEFAULT;

private final Map<Long, Float> cachedFadeValues = new Long2FloatArrayMap((int) this.properties.getFade().getDuration());
private final Map<Long, Float> cachedFadeValues = new Long2FloatArrayMap();

protected boolean unexpectedConditionTransition = false;
protected long lastTime = -2;
Expand Down Expand Up @@ -83,12 +83,12 @@ public float updateAlpha() {
if (this.properties.getFade().isAlwaysOn()) {
this.conditionAlpha = Utils.calculateConditionAlphaValue(1f, 0f, this.conditionAlpha, condition ? this.properties.getTransitionInDuration() : this.properties.getTransitionOutDuration(), condition);
} else {
Float cachedFadeValue = this.cachedFadeValues.getOrDefault(currentTime, null);
Float cachedFadeValue = this.cachedFadeValues.getOrDefault(currentTime, this.properties.getFade().getKeyFrames().getOrDefault(currentTime, null));
if (cachedFadeValue != null) {
fadeAlpha = this.cachedFadeValues.get(currentTime);
} else {
Tuple<Long, Long> keyFrames = Utils.findClosestKeyframes(this.properties.getFade().getKeyFrames(), currentTime);
fadeAlpha = Utils.calculateInterpolatedAlpha(currentTime, keyFrames.getA(), keyFrames.getB(), this.properties.getFade().getKeyFrames().get(keyFrames.getA()), this.properties.getFade().getKeyFrames().get(keyFrames.getB()));
fadeAlpha = Utils.calculateInterpolatedAlpha(currentTime, this.properties.getFade().getDuration(), keyFrames.getA(), keyFrames.getB(), this.properties.getFade().getKeyFrames().get(keyFrames.getA()), this.properties.getFade().getKeyFrames().get(keyFrames.getB()));
this.cachedFadeValues.put(currentTime, fadeAlpha);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,40 @@ public static float calculateFadeAlphaValue(float maxAlpha, float minAlpha, int
* Calculates the interpolated alpha value between two keyframes.
*
* @param currentTime The current time.
* @param duration The duration of the keyframes.
* @param currentKeyFrame The timestamp of the current keyframe.
* @param nextKeyFrame The timestamp of the next keyframe.
* @param currentKeyFrameValue The alpha value at the current keyframe.
* @param nextKeyFrameValue The alpha value at the next keyframe.
* @return The interpolated alpha value based on the current time and keyframes.
*/
public static float calculateInterpolatedAlpha(long currentTime, long currentKeyFrame, long nextKeyFrame, float currentKeyFrameValue, float nextKeyFrameValue) {
if (currentKeyFrameValue == nextKeyFrameValue) {
public static float calculateInterpolatedAlpha(long currentTime, long duration, long currentKeyFrame, long nextKeyFrame, float currentKeyFrameValue, float nextKeyFrameValue) {
// Check if no interpolation is needed
if (currentKeyFrameValue == nextKeyFrameValue || currentKeyFrame == nextKeyFrame) {
return nextKeyFrameValue;
} else {
long duration = nextKeyFrame - currentKeyFrame;
long timePassedSinceKeyFrame = currentTime - currentKeyFrame;
return currentKeyFrameValue + ((float) timePassedSinceKeyFrame / duration) * (nextKeyFrameValue - currentKeyFrameValue);
}

// Handle cyclical keyframes
if (currentKeyFrame > nextKeyFrame) {
// Calculate time remaining in the cycle
long timeRemainingInCycle = duration - currentKeyFrame;
// Calculate total time in the cycle
long timeInCycle = timeRemainingInCycle + nextKeyFrame;

// Adjust nextKeyFrame and currentTime if needed
nextKeyFrame = currentKeyFrame + timeInCycle;
if (currentTime > nextKeyFrame && currentTime > currentKeyFrame || currentTime == 0) {
long timePassed = timeRemainingInCycle + currentTime;
currentTime = currentKeyFrame + timePassed;
}
}

// Calculate duration between keyframes and time passed since currentKeyFrame
long durationBetween = nextKeyFrame - currentKeyFrame;
long timePassedSinceKeyFrame = currentTime - currentKeyFrame;

// Perform interpolation calculation
return currentKeyFrameValue + ((float) timePassedSinceKeyFrame / durationBetween) * (nextKeyFrameValue - currentKeyFrameValue);
}

/**
Expand All @@ -200,19 +220,18 @@ public static Tuple<Long, Long> findClosestKeyframes(Map<Long, Float> keyFrames,
long closestLowerKeyFrame = Long.MIN_VALUE;
long closestHigherKeyFrame = Long.MAX_VALUE;

for (Map.Entry<Long, Float> entry : keyFrames.entrySet()) {
long keyFrame = entry.getKey();
for (long keyFrame : keyFrames.keySet()) {
if (keyFrame <= currentTime && keyFrame > closestLowerKeyFrame) {
closestLowerKeyFrame = keyFrame;
} else if (keyFrame > currentTime && keyFrame < closestHigherKeyFrame) {
}
if (keyFrame > currentTime && keyFrame < closestHigherKeyFrame) {
closestHigherKeyFrame = keyFrame;
}
}

if (closestHigherKeyFrame == Long.MAX_VALUE || closestLowerKeyFrame == Long.MIN_VALUE) {
closestHigherKeyFrame = keyFrames.keySet().stream().max(Long::compare).orElse(Long.MAX_VALUE);
closestLowerKeyFrame = keyFrames.keySet().stream().min(Long::compare).orElse(Long.MIN_VALUE);
return new Tuple<>(closestHigherKeyFrame, closestLowerKeyFrame);
}

return new Tuple<>(closestLowerKeyFrame, closestHigherKeyFrame);
Expand All @@ -237,36 +256,32 @@ public static int calculateCyclicTimeDistance(int startTime, int endTime) {
* @return The final blended fog color.
*/
public static FogRGBA alphaBlendFogColors(List<Skybox> skyboxList, RGBA initialFogColor) {
List<FogRGBA> activeColors = skyboxList.stream()
.filter(Skybox::isActive) // check if active
.filter(NuitSkybox.class::isInstance) // check if our own skybox impl
.map(NuitSkybox.class::cast) // cast to our own skybox impl
.filter(nuitSkybox -> nuitSkybox.getProperties().isChangeFog())// check if fog is changed
.map(nuitSkybox -> new FogRGBA(nuitSkybox.getProperties().getFogColors().getRed(),
FogRGBA destination = new FogRGBA(initialFogColor);

for (Skybox skybox : skyboxList) {
if (skybox.isActive() && skybox instanceof NuitSkybox nuitSkybox && nuitSkybox.getProperties().isChangeFog()) {
FogRGBA source = new FogRGBA(
nuitSkybox.getProperties().getFogColors().getRed(),
nuitSkybox.getProperties().getFogColors().getGreen(),
nuitSkybox.getProperties().getFogColors().getBlue(),
nuitSkybox.getAlpha(),
nuitSkybox.getProperties().isChangeFogDensity(),
nuitSkybox.getProperties().getFogColors().getAlpha()))
.toList(); // map RGB fog colors and A to skybox alpha
if (activeColors.isEmpty()) {
return null;
} else {
FogRGBA destination = new FogRGBA(initialFogColor);
for (FogRGBA source : activeColors) {
// Alpha blending
float sourceAlphaInv = 1f - source.getAlpha();

float red = (source.getRed() * source.getAlpha()) + (destination.getRed() * sourceAlphaInv);
float green = (source.getGreen() * source.getAlpha()) + (destination.getGreen() * sourceAlphaInv);
float blue = (source.getBlue() * source.getAlpha()) + (destination.getBlue() * sourceAlphaInv);
float alpha = (source.getAlpha() * source.getAlpha()) + (destination.getAlpha() * sourceAlphaInv);
float density = (source.getDensity() * source.getAlpha()) + (destination.getDensity() * sourceAlphaInv);
nuitSkybox.getProperties().getFogColors().getAlpha()
);

destination = new FogRGBA(red, green, blue, alpha, source.isModifyDensity(), density);
float sourceAlphaInv = 1f - source.getAlpha();
destination = new FogRGBA(
(source.getRed() * source.getAlpha()) + (destination.getRed() * sourceAlphaInv),
(source.getGreen() * source.getAlpha()) + (destination.getGreen() * sourceAlphaInv),
(source.getBlue() * source.getAlpha()) + (destination.getBlue() * sourceAlphaInv),
(source.getAlpha() * source.getAlpha()) + (destination.getAlpha() * sourceAlphaInv),
source.isModifyDensity(),
(source.getDensity() * source.getAlpha()) + (destination.getDensity() * sourceAlphaInv)
);
}
return destination;
}

return destination;
}

/**
Expand Down

0 comments on commit 4b0f3ec

Please sign in to comment.