基于时间插值一个变化的值 (glsl)

3

在我的顶点着色器中,我有一个可以从0到1变化的值,但是它没有插值。然而,我希望随着时间的推移进行插值,但我不想通过Javascript(从CPU)来实现。当其发生某些用户输入时,我希望将其从0插值到1(或者反向插值)。

我有一个递增的uTime统一变量,我可以用于解决这个问题吗?

希望我已经清楚地解释了我的问题。谢谢您的帮助。


您将需要告诉顶点着色器旅行的方向,它是否被启用或禁用,因为它不知道先前的状态是什么。其余部分可以使用时间统一变量完成。 - Andrea
谢谢您的见解,您是指传递另一个统一变量还是将先前的状态存储在变量中?@Andrea - Fabian Tjoe A On
我一开始也是这么想的,但仔细想想,你实际上可以使用某种类型的持久存储来跟踪状态变化,着色器可以从中写入和读取(例如shared或SSBOs)。 - Andrea
有趣,但我想我得尝试发送另一个uniform。我正在使用WebGL 1,我不确定是否已经有使用SSBOs的选项。 - Fabian Tjoe A On
1个回答

5
我认为uTime包含以毫秒为单位的时间。将该值除以一个时间跨度,得到一个在该时间跨度内递增1的值。
该值的小数部分不断从0.0变化到1.0,并在0.0处重新开始。可以通过fract计算数字的小数部分。例如:
(如果uTime的单位是秒,则timespan必须为3.0)
uniform float uTime; // time in milliseconds

void main()
{
    const float timespan = 3000.0; // e.g. 3 seconds
    float w = fract(uTime / timespan);

    // [...]
}

对于 Hermite插值,还需要额外使用 smoothstep:

uniform float uTime; // time in milliseconds

void main()
{
    const float timespan = 3000.0; // e.g. 3 seconds
    float w = smoothstep(0.0, 1.0, fract(uTime / timespan));

    // [...]
}

通过使用sin,可以实现另一种不错的效果。Sine给出的值在弧度[0.0, 2*PI]内随角度连续变化,取值范围为-1.0到1.0,例如:

uniform float float uTime; // time in milliseconds

void main()
{
    const float timespan = 3000.0; // e.g. 3 seconds
    float w = sin(2.0 * 3.14159 * uTime / timespan) * 0.5 + 0.5;

    // [...]
}

如果您想在特定时间点开始动画,则需要第二个统一变量(uStartTime),该变量指示时间点。该变量必须与uTime具有相同的单位。
每当需要开始动画时,设置uStartTime的值。在开始时,其值为0。如果uStartTime小于或等于uTime,则动画为0.0。这是一个罕见的情况,只发生在设置uStartTime的瞬间。如果uTime大于或等于uStartTime + timespan,则动画为1.0。不需要计算分数部分,而是将当前时间和起始时间之差的clamp限制在0.0到1.0的范围内。例如:
uniform float uTime; // time in milliseconds
uniform float uStartTime; 

void main()
{
    const float timespan = 3000.0; // e.g. 3 seconds
    float w = clamp((uTime-uStartTime) / timespan, 0.0, 1.0);

    // [...]
}

如果您想根据“方向”设置插值方向(从0到1或从1到0),则需要一些额外的信息。添加另一个类型为float的统一变量(uTarget),并将其设置为0.0或1.0。该值定义了插值目标:
uniform float uTime; // time in milliseconds
uniform float uStartTime; 
uniform float uTarget; // 0.0 or 1.0 

void main()
{
    const float timespan = 3000.0; // e.g. 3 seconds
    float w = clamp((uTime-uStartTime) / timespan, 0.0, 1.0);
    w = mix(1.0-w, w, uTarget);

    // [...]
}

谢谢!回答详细又好。uTime确实是以毫秒为单位的时间。没想到可以使用这个均匀分布的分形部分进行插值。然而,我想这并没有完全回答我的问题,这只是说明了如何使用uTime均匀分布进行插值,但我真正想要的是每当我的值改变时,插值会朝着正确的方向发生。 - Fabian Tjoe A On
感谢您的编辑!据我理解,uStartTime 从0开始。那么,每次我的值发生变化时,我应该以毫秒为单位设置 uStartTime 吗?由于 uStartTime 与持续增加的 uTime 进行比较,所以我需要根据 uTime 计算特定的值吗?或者它可以是1和0吗? - Fabian Tjoe A On
1
@FabianTjoeAOn 你所要做的就是在数值改变时设置 uStartTime。将同一时间设置为 uTime 中设置的时间。每帧都会设置 uTime,但仅在值更改时才设置 uStartTime - Rabbid76
没错,这个可以工作 :). 但是,插值现在是单向的,它只在0到1之间进行插值,如何根据变化的值(而不是uTime)使其双向插值呢? - Fabian Tjoe A On
@FabianTjoeAOn 您是希望在方向改变时,值从0变为1再变为0吗?还是说您的意思是根据方向分别将值从0变为1或从1变为0? - Rabbid76
我的意思是后者,所以当我的值从0变为1时,要从0插值到1。然后它保持为1。然后值从1变为0时,要从1插值到0。 - Fabian Tjoe A On

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接