这次的效果是仿原神的熔岩流下效果,代码是内置管线的
最终效果如下,高仿熔岩效果需要开启HDR颜色和Bloom效果,用postprocessing或者URP的设置或者自己写Bloom
视频效果的特点及思路
-
镂空部分只有在岩浆下半部分以下出现 渐变图来控制 镂空程度要用渐变图的灰度值来lerp 渐变图控制镂空的起始位置 -
镂空部分随着向下流动而变大 思路是 镂空阈值随着顶点的U值或者V值的单方向变化而变小 举个例子 镂空图的同样的一块黑班在U值较小时 只有一小部分能做到镂空 但是在U值较大时 镂空的部分就变大了 -
镂空口部分是往下扩大,上面部分基本不扩大。 思路: 因为单方向的UV是0-1的小数,尝试用pow的方式去做 0-1 之间的数, pow 函数指数越大 图像越陡 0-0.5部分会被压缩到小的区域 0.5-1时候会陡增 这个pow函数线条代表了阈值随着UV的U或者V的变大的变化, 然后最后阈值 = 1-阈值,这样V或者U变大的时候,最后阈值极速减小,并且变大的方向与向下流动的方向一致,就下方部分极速镂空。 -
视频中镂空不存在半透明的部分 应该使用裁切的方式 不能用透明度渐变来做 -
镂空部分一般不出现断节 以及消失:做法 阈值做个最大限制 float hollowThresholdClamp = clamp(hollowThreshold, 0, threshold); threshold是 0.6f效果较好。 -
为了不让镂空边缘扩大的动效显得那么生硬 镂空图应该用模糊处理 这样扩大效果会好一些,因为没有模糊的图片,黑白过渡部分可能会出现明显的跳动,比如这个像素的灰度值是0.3,隔壁的突然变成了0.8,这样随着阈值减小时,镂空扩大会变得有时激进有时缓慢,不符合实际生活中熔岩扩大的渐进效果 -
自己在熔岩的底部再添加了读取渐变图让透明度渐变消失
注意点:
-
底部的渐变消失存在像素浮点精度运算问题,表现是底部有一条细丝,这是因为UV算到1的时候因为精度超出了范围变成1.xx,然后超出范围如果图片设置为repeat会自动取余读取图片靠近0时候的部分,这时最下方就是为0,按照shader的逻辑就透明度变成了1,于是就出现了最底部的一条横线。 -
尝试过用UV拉伸噪声图的方式来模拟熔岩镂空下扩,但是用UV拉伸的方式太不可控,做了一些尝试发现一些特点
- 首先UV本身是用time去控制流动的,这样改变了的UV会重新从顶点函数传入回来,也就是说,用时间叠加之后,位于模型部位的相同的顶点,在不同时刻被赋予的UV是不一样的。
- UV乘以0到1的小数可以被不同程度的拉伸 在第一条的基础上用片源去采样渐变图,将灰度值作为UV的拉伸值,实现不同部位不同程度的拉伸,但是这样还是会有不正常的现象产生。
Shader代码:
Shader "Test/Lava"
{
Properties
{
_mainTex ("主贴图", 2D) = "white" {}
_flowSpeed("流动速度",Range(0,0.5)) = 0.02
_color("颜色", Color) = (1,0,0,1)
_maskTex ("镂空图", 2D) = "white" {}
_gradientTex ("交界图", 2D) = "white" {}
_clipStrength("镂空速度",Range(0.5, 1)) = 0.5
_clipStrengthPower("镂空倍速",Range(1, 3)) = 0.5
_clampRange("镂空阈值",Range(0, 1)) = 0.6
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 mainTexUV : TEXCOORD0;
float2 maskTexUV : TEXCOORD1;
float2 gradientTexUV : TEXCOORD2;
float2 originUV : TEXCOORD4;
float4 vertex : SV_POSITION;
};
sampler2D _mainTex;
float4 _mainTex_ST;
float _flowSpeed;
float4 _color;
sampler2D _maskTex;
float4 _maskTex_ST;
sampler2D _gradientTex;
float4 _gradientTex_ST;
float _clipStrength;
float _clipStrengthPower;
float _clampRange;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.mainTexUV = TRANSFORM_TEX(v.uv, _mainTex);
o.maskTexUV = TRANSFORM_TEX(v.uv, _maskTex);
o.gradientTexUV = TRANSFORM_TEX(v.uv, _gradientTex);
o.mainTexUV.x += _Time.y * _flowSpeed;
o.maskTexUV.x += _Time.y * _flowSpeed;
o.originUV = v.uv;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 mainTexColor = tex2D(_mainTex, i.mainTexUV);
fixed4 maskValue = tex2D(_maskTex, i.maskTexUV);
fixed borderValue = tex2D(_gradientTex, i.gradientTexUV).r;
float uvXReverse = (1 - i.originUV.x) ;
float hollowThreshold = pow(uvXReverse, _clipStrengthPower) ;
float hollowThresholdClamp = clamp(hollowThreshold, 0, _clampRange);
float alpha = lerp(1, maskValue.r , borderValue);
clip(alpha - hollowThresholdClamp);
fixed4 finalColor = fixed4(mainTexColor.rgb * _color.rgb, alpha);
return finalColor;
}
ENDCG
}
}
}
|