Difference between revisions of "Talk:EffectShader"

3,964 bytes added ,  15:56, 10 April 2022
imported>DavidJCobb
(→‎Projected UVs: video link)
Line 91: Line 91:


:Yeah, no, [https://www.youtube.com/watch?v=hXepCugf5gk this feature is a train wreck]. The, ah, gentle animation in that video is UV scrolling using EffectShader settings; the, uh, everything else is Projected UVs. How could this ever possibly be useful to anyone? [[User:DavidJCobb|DavidJCobb]] ([[User talk:DavidJCobb|talk]]) 2020-08-12T19:33:27 (EDT)
:Yeah, no, [https://www.youtube.com/watch?v=hXepCugf5gk this feature is a train wreck]. The, ah, gentle animation in that video is UV scrolling using EffectShader settings; the, uh, everything else is Projected UVs. How could this ever possibly be useful to anyone? [[User:DavidJCobb|DavidJCobb]] ([[User talk:DavidJCobb|talk]]) 2020-08-12T19:33:27 (EDT)
== Reverse-engineering ==
The fade timers for EffectShader effects appear to be used as follows. This function is located at 0x00497A70 in Skyrim Classic, and it appears to return a single value that should be added to the current fade opacity.
<syntaxhighlight lang="cpp" line>/*static*/ float TESEffectShader::ComputeFades(
  float previous_alpha,
  float Arg2, // probably a "delta time" float, i.e. seconds per frame
  float time_since_start,
  bool  Arg4, // probably an "is fading out" bool
  //
  // shader settings:
  //
  float fade_in_time,
  float fade_out_time,
  float full_time,
  float alpha_full,
  float alpha_persistent,
  float min_fade_rate
) {
  if (Arg4) {
      float end_of_full_time = fade_in_time + full_time;
      if (end_of_full_time < time_since_start) {
        //
        // We have passed the end of the Full Alpha period.
        //
        if (0.0 <= fade_out_time) {
            //
            // This effect shader has a defined fade-out time.
            //
            float alpha = alpha_persistent;
            if (alpha == 0)
              //
              // If the shader has a 0.0 persistent alpha, use its full alpha as the
              // persistent alpha.
              //
              alpha == alpha_full;
            //
            float fade_rate = fade_out_time / alpha;
            if (min_fade_rate > fade_rate)
              fade_rate = min_fade_rate;
            float result = previous_alpha - (fade_rate * Arg2);
            if (result >= 0.0)
              return result;
            return 0.0F;
        }
        //
        // This effect shader has a negative fade-out time, so drop to zero alpha
        // instantly.
        //
        return 0.0F;
      }
  }
  if (time_since_start < fade_in_time) {
      //
      // We're fading in to Full Alpha.
      //
      float a      = fade_in_time / Arg2;
      float result = (a * alpha_full) + previous_alpha;
      if (result > alpha_full)
        return alpha_full;
      return result;
  }
  if (full_time > time_since_start - fade_in_time) {
      //
      // We're in Full Alpha time.
      //
      return alpha_full;
  }
  if (fade_out_time > full_time + time_since_start) {
      //
      // We're past Full Alpha time, and are in Fade Out time. Opacity should fade from
      // the Full Alpha ratio to the Persistent Alpha ratio.
      //
      float alpha_span = alpha_full - alpha_persistent;
      float fade_rate  = (Arg2 / fade_out_time) * alpha_span;
      float result    = (double)previous_alpha - (float)fade_rate; // Bethesda casts
      return std::max(alpha_persistent, result);
  }
  return alpha_persistent;
}</syntaxhighlight>
This means that the timers work as follows:
* Fade in from zero alpha to ''Full Alpha Ratio'' over ''Fade-In Time'' seconds.
* Stay at ''Full Alpha Ratio'' for ''Full Alpha Time'' seconds.
* Fade down from ''Full Alpha Ratio'' to ''Persistent Alpha Ratio'' for ''Fade-Out Time'' seconds. If the alpha value falls below ''Persistent Alpha Ratio'', force it to ''Persistent Alpha Ratio''.
* Stay at ''Persistent Alpha Ratio'' until the shader is removed.
* If ''Full Alpha Time'' is negative, then drop to zero alpha immediately. Otherwise, continue.
* Fade out from ''Persistent Alpha Ratio'', if it's non-zero, or ''Full Alpha Ratio'' otherwise; we will call this value the ''Prior Alpha''. The fade rate is (''Fade Out Time'' / ''Prior Alpha'') per second(?) unless that value falls below a set minimum rate, in which case that minimum rate is used instead.
** The minimum setting is whichever is relevant among the following [[game setting]]s:
*** fEffectShaderParticleMinFadeRate
*** fEffectShaderFillEdgeMinFadeRate
Some edge-cases:
* If the shader is removed while still in ''Full Alpha Time'', then based on the subroutine above, it would wait for that time to expire, and only begin animating out as normal after ''Full Alpha Time'' is up.
53

edits