[OpenGL] 纹理高级篇 - flowmap的原理
Posted ZJU_fish1996
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[OpenGL] 纹理高级篇 - flowmap的原理相关的知识,希望对你有一定的参考价值。
flowmap简单来说就是一种特殊的uv纹理动画,我们把运动向量记录在纹理中,并让纹理uv向特定方向运动。
它的原理非常简单,但如果你直接将运动向量乘以时间,叠加到原始纹理坐标上,那么你不会得到正确的结果:
vec2 motionvector = texture(flowmap, uv).xy * 2 - 1; // decode motion vector
uv = uv + time * motionvector;
vec3 color = texture(tex, uv).rgb;
当我们累加一个纹理扰动时,图像必然会失真,这种失真表现在纹理被拉伸或压缩,以及纹理产生tiling。但数值较小时,失真较小。
我们必须确保累加到纹理坐标上的运动向量是一个比较小的值,因此我们应该在一个较小的数值空间内循环应用运动向量。
基于这一想法,我们优化我们的代码如下:
vec2 motionvector = texture(flowmap, uv).xy * 2 - 1; // decode motion vector
uv = uv + fract(time) * motionvector * flowstrength;
vec3 color = texture(tex, uv).rgb;
我们截取时间的小数部分,确保它的数值处在一个较小的区间,其中,flowstrength可用于控制数值的范围,数值越大,运动幅度越大,图像的变形也会更加严重。一般情况下,这个参数最好不要超过1。
但是,这种循环应用会带来不连贯,因此flowmap真正的难点在于,如何实现永不停息的“流动”。
为了减轻不连贯的效果,我们应用两个相位相差半个周期的uv运动,并在两张图像之间混合,得到看起来更为正确的结果。
具体应用到纹理上,表现为第一个图像的uv运动在当前周期快要结束的时候,逐渐淡出,第二个图像的uv运动在周期起始位置开始,逐渐淡入。
vec2 motionvector = texture(flowmap, uv).xy * 2 - 1; // decode motion vector
vec2 uv1 = uv + fract(time) * motionvector * flowstrength;
vec2 uv2 = uv + fract(time + 0.5) * motionvector * flowstrength;
vec3 color1 = texture(tex, uv1).rgb;
vec3 color2 = texture(tex, uv2).rgb;
根据时间,计算一个混合系数:
float alpha = abs((fract(time) - 0.5) * 2); // 模拟三角波,也可以使用sin函数模拟
vec3 color = mix(color1, color2, alpha);
以上是关于[OpenGL] 纹理高级篇 - flowmap的原理的主要内容,如果未能解决你的问题,请参考以下文章
一看就懂的OpenGL ES教程——临摹画手的浪漫之纹理映射(实践篇)