什么是Flow Map
本质是一张记录了2D向量信息的纹理
Flow map上的颜色(通常为RG通道)记录该处向量场的方向,让模型上某一点表现出定量流动的特性
通过在shader中偏移uv再对纹理进行采样,来模拟流动效果
有亿个问题
Flow Map不能直接使用,需要将Flow Map上的色值从(0,1)的范围映射到方向向量的范围(-1,1)
实现无缝流动
前面我们已经把映射后的Flow Map与UV相加进行扰动,并与_Time相乘,但是随着_Time的值越来越大,扰动也会越来越大最终达到阈值,所以我们需要构造周期函数
周期函数遮罩
将周期函数减去0.5再乘以2后取绝对值即可
原周期函数(frac(x))
减去0.5后(向下平移0.5)
再乘以2(缩进一半)
取绝对值
Shader实现
Shader "Unlit/FlowMapShader"
{
Properties
{
_MainTex("MainTex",2D) = "white"{}
_FlowMap("FlowMap",2D) = "white"{}
}
SubShader
{
Tags
{
"RenderPipeline"="UniversalPipeline"
"RenderType"="Opaque"
"UniversalMaterialType" = "Unlit"
"Queue"="Geometry"
}
Pass
{
HLSLPROGRAM
#pragma target 4.5
#pragma exclude_renderers gles gles3 glcore
#pragma multi_compile_instancing
#pragma multi_compile_fog
#pragma multi_compile _ DOTS_INSTANCING_ON
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
CBUFFER_START(UnityPerMaterial)
float4 _MainTex_ST;
CBUFFER_END
TEXTURE2D(_MainTex);
TEXTURE2D(_FlowMap);
#define smp SamplerState_Linear_Repeat
SAMPLER(smp);
struct Attributes
{
float3 positionOS : POSITION;
float2 uv : TEXCOORD;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD;
};
Varyings vert(Attributes v)
{
Varyings o = (Varyings)0;
o.positionCS = TransformObjectToHClip(v.positionOS);
o.uv = TRANSFORM_TEX(v.uv,_MainTex);
return o;
}
half4 frag(Varyings i) : SV_TARGET
{
// 采样flowMap并映射到(-1,1)
half3 flowDir = SAMPLE_TEXTURE2D(_FlowMap,smp,i.uv)*2-1;
// 两个周期函数
float phase0 = frac(_Time.x );
float phase1 = frac(_Time.x + 0.5);
// 对UV进行扰动,采样出两层贴图
half4 mainTex0 = SAMPLE_TEXTURE2D(_MainTex,smp,i.uv + flowDir.xy * phase0);
half4 mainTex1 = SAMPLE_TEXTURE2D(_MainTex,smp,i.uv + flowDir.xy * phase1);
// 核心代码
// 两层贴图的蒙版,是一个锯齿状的周期函数,可以无缝衔接两层贴图的运动
float flowLerp = abs((phase0 - 0.5)/0.5);
half4 finalColor = lerp(mainTex0,mainTex1,flowLerp);
return finalColor;
}
ENDHLSL
}
}
}
|