# 前言

前些日子做了个水龙头流水的效果(当然跟高大上的流体之类的无关),所用到的无非就是粒子效果 + Shader + 部分代码而已。
不过,自己觉得看着还行,所以有此一记。

效果如下:

简答来说,就是开启水龙头 -> 流水,同时扰动水纹,关闭水龙头 -> 关闭水,同时慢慢将水纹渐隐掉。
(上面两个手柄是因为:这个是 VR 项目,开发机跟运行机是不同的,我的开发机上面什么都没,没办法之下只有模拟下了,不过只要接入 VR 就会自动转换了,没什么影响)

# 实现

先来看看 UE4 材质节点:

材质实例设置:

就是这样。

其中,主要就是通过 Sin 计算纹理扰动比较麻烦,但若是用代码来描述的话,也就是几句的事情 —— 实际上,在 UE4 中我拖出这些节点来了之后,自己都看着费劲,所以原本,这个效果我是先行在 Unity3D 中实现的:

水纹效果

主要代码如下:

p
float2 uv = i.uv;
uv -= float2(0.5,0.5);
float dis =sqrt( dot(uv,uv));
uv =i.uv+ sin(100*dis - _Time.y*10)*i.uv*0.01*3;
fixed4 col = tex2D(_GrabTexture,uv);

其原理就是首先将 UV 挪到中心,计算其与中心的距离,然后通过 sin 函数 + 时间等参数对 UV 进行扰动。
我这儿时抓取了屏幕纹理(_GrabTexture),所以看着就是这种效果了。

在 UE4 中,除此之外,还另外增加了使用发现进行扰动的效果,以及插值 “平静水面与扰动水面” 的功能。

代码中开关如下:

p
void ATriggerWaterTapActor::Tick(float DeltaTime)
{
	if (bCanOpen)
	{
		WaterWaveValue = FMath::Lerp(WaterWaveValue, 0.0f, DeltaTime*0.35f);
	}
	else
	{
		WaterWaveValue = FMath::Lerp(WaterWaveValue, 1.0f, DeltaTime);
	}
	GEngine->AddOnScreenDebugMessage(2, 3, FColor::Cyan, FString::SanitizeFloat(WaterWaveValue));
	WaterMesh->SetScalarParameterValueOnMaterials(FName("Wave"), WaterWaveValue);
}
void ATriggerWaterTapActor::OnTriggered_Implementation()
{
	Super::OnTriggered_Implementation();
	bCanOpen = !bCanOpen;
	bool active = bCanOpen;
	active ? _particleSystem->Deactivate() : _particleSystem->Activate();
	GEngine->AddOnScreenDebugMessage(-1, 1, FColor::Green, active ? TEXT("关闭") : TEXT("开启"));
}