欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

冰冻效果Shader案例

发布时间:2024/1/8 编程问答 62 豆豆
生活随笔 收集整理的这篇文章主要介绍了 冰冻效果Shader案例 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

老规矩先上图

最近我在设计一个星球题材的独立游戏,其中一个特色是让怪物逐渐被冰冻,并在其下方生成冰柱的特效。在这里,我想和大家分享一下我的设计过程。


文章目录

    • 一、贴合冰面
    • 二、冰冻起始点
    • 三、连贯性逐渐冰冻
    • 四、下垂的冰柱
    • 五、半萤光效果
    • 六、下面是完整代码:


一、贴合冰面

首先这个特效需要和与原模型紧密贴合,需要将源模型基础上沿着法线方向向外扩大一些,以避免与原模型有交错。具体代码如下:

//因为是叠加在原本的材质上使用的,所以需要比原本的稍微大一些,我们使用向法线方向延展的方式 v.vertex += downNormal * stepNormal + _BaseVectorNormalScale*v.normal;

二、冰冻起始点

假设你要做的是一个类似冰冻枪的功能,射击后从击中点开始结冰,使用RaycastHit.textureCoord可以获得击中点的UV值,赋值给_CenterUv属性。

_CenterUv("裁剪中心",Vector)=(0.5,0.5,0,0)

三、连贯性逐渐冰冻

一般来说 UV 具有一定的连续性,这里可以将 UV 图中某一点作为圆心点,向外逐渐展开,以达到逐渐冰冻的效果。具体的实现方法是计算指定 UV 点与起点的距离,逐渐增大其值以达到效果。

//主图 half4 var_MainTex = tex2D(_MainTex, i.uv0); //高光遮蔽图(用于区分哪部分有贴图内容) half4 var_OcclusionTex = tex2D(_OcclusionTex, i.uv0); //_CenterUv是指定中心,计算uv与中心点的距离,能修修改显示距离达到向外扩展效果 half dic =1- distance(i.uv0.xy, _CenterUv.xy)* var_OcclusionTex; clip(dic- _ClipNum);

四、下垂的冰柱

我们需要制作一种向下的冰柱,可以先使用云彩图制作随机扰动效果,这些随机效果的色值通常为0-1。在这里,只有超过0.45的图案部分才能形成向下的冰柱。
为了让冰柱看起来更流畅,我们可以在顶点中使用o.nDirWS.g属性,这将根据冰柱方向下降的程度来调整每个顶点的Y坐标。
因此,在确定了UV映射后,我们需要将超过0.45的顶点向上移动指定的距离,这将产生类似于冰柱的形状。

//在顶点阶段读图需要用tex2DLod(这里是云彩干扰图) half h = tex2Dlod(_CloudTex, float4(v.uv0.xy, 0, 0)).r; //读云彩图色值,红色值大于0.45的做法线扩展,用于做冰刺效果 //o.nDirWS.g 得到向下的法线,因为冰刺只要向下的 g 也相当于Y轴 half stepNormal = step(h,0.45)*_VectorNormalScale*max(0,(_VectorNormalScale - o.nDirWS.g));

五、半萤光效果

通常,在冰面上通常会存在一些凹凸不平的效果。我们可以使用贴图来模拟这些效果。此外,有时冰面还会有一些闪闪发光的效果。在这种情况下,我们可以使用菲涅尔光来进行模拟。

//光源漫反射 half3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb; half3 baseCol = var_MainTex.rgb*ambient*_LightColor0;// half lambert = max(0.0, ndotl); //光源镜面反射half specPow = _SpecPow;half phong = pow(max(0.0,vdotr), _SpecPow);//光源反射混合half3 baseLighting = (baseCol + phong * _EnvSpecInt);//(baseCol * lambert + phong * _EnvSpecInt)//环境漫反身half3 envDiff = baseCol * _EnvDiffInt;half upMask = max(0.0, nDirTSOrigin.g);//环境镜面反射half3 fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow) * _FresnelInt*ambient.rgb;//菲涅尔half3 envSpec = fresnel * _EnvSpecInt*ambient;//环境反射混合half3 envLighting = (envDiff + envSpec)*ambient*_LightColor0;//最终混合half3 finalRGB = (baseLighting+envLighting + fresnel )* var_OcclusionTex.r;// ;*(1 - scale)

六、下面是完整代码:

这里付上完整代码,大家可以结合代码和上面的讲解会更好理解。也可以扩展成更多的效果,希望对大家有帮助,谢谢。

Shader "Custom/IceAnimStandard" {Properties{[Header(Ground_Base)]_MainTex("基础色 ",2D) = "white"{}_CloudTex("干扰图 ",2D) = "white"{}_BaseColor("基础色",Color) = (1.0,1.0,1.0,1.0)_NormMap("法线贴图",2D) = "bump"{}[Header(Normal)]_NormalScale("法线缩放",Range(0.0,1)) = 1_VectorNormalScale("顶点法线缩放",Range(0,0.1)) = 0_BaseVectorNormalScale("基础顶点法线缩放",Range(0,1)) = 0.06[Header(Ground_Diffuse)]_EnvDiffInt("环境漫反射强度",Range(0,1)) = 0.2[Header(Ground_Specular)]_FresnelPow("菲涅尔次幂",Range(0,10)) = 1_FresnelInt("菲涅尔强度",Range(0,2)) = 1_SpecPow("高光次幂",Range(0,5)) = 30_EnvSpecInt("环境镜面反射强度",Range(0,5)) = 0.2_OcclusionTex("高光遮蔽",2D) = "white"{}_CenterUv("裁剪中心",Vector)=(0.5,0.5,0,0)_ClipNum("裁剪数值",Range(0,1)) = 1}SubShader{Tags{"RenderType" = "Opaque" "IgnoreProjector" = "True"}//Pass{Tags{"LightMode" = "ForwardBase"}//ZWrite off//Cull offCGPROGRAM#pragma vertex vert#pragma fragment frag#include "Lighting.cginc"#include "AutoLight.cginc"#include "UnityCG.cginc"#pragma target 3.0#pragma multi_compile_fwdbase//地面参数uniform sampler2D _MainTex;uniform sampler2D _CloudTex;uniform sampler2D _NormMap; uniform half4 _NormMap_ST;uniform half4 _BaseColor;uniform half _NormalScale;uniform half _VectorNormalScale;uniform half _BaseVectorNormalScale;uniform half _EnvDiffInt;uniform half _SpecPow;uniform half _EnvSpecInt;uniform half _FresnelPow;uniform half _FresnelInt;uniform sampler2D _OcclusionTex;uniform half2 _CenterUv;uniform half _ClipNum;//输入结构struct a2v {float4 vertex: POSITION; //顶点信息float2 uv0: TEXCOORD0; //UV信息float4 normal: NORMAL; //法线信息float4 tangent: TANGENT; //切线信息};//输出结构struct v2f {float4 pos:SV_POSITION; //屏幕定点位置float2 uv0:TEXCOORD0; //UV(不可动)保持默认float2 uv2:TEXCOORD2; //法线UV(用于重复平铺)float3 WorldPos:TEXCOORD7; //世界坐标位置float3 nDirWS:TEXCOORD4; //世界坐标法线float3 tDirWS:TEXCOORD5; //世界坐标切线float3 bDirWS:TEXCOORD6; //世界坐标副切线SHADOW_COORDS(3)};v2f vert(a2v v) {v2f o; //新输出结构o.nDirWS = UnityObjectToWorldNormal(v.normal); //法线位置 OS>WShalf h = tex2Dlod(_CloudTex, float4(v.uv0.xy, 0, 0)).r;half stepNormal = step(h,0.45)*_VectorNormalScale*max(0,(_VectorNormalScale - o.nDirWS.g));half4 downNormal = -half4(o.nDirWS,0);downNormal.y = max(0.1, downNormal.y);downNormal.x = 0;downNormal.z = 0;v.vertex += downNormal * stepNormal + _BaseVectorNormalScale*v.normal;o.pos = UnityObjectToClipPos(v.vertex); //顶点位置 OS>CSo.uv0 = v.uv0; //传弟UVo.uv2 = v.uv0 *_NormMap_ST.xy + _NormMap_ST.zw; //传弟UVo.WorldPos = mul(unity_ObjectToWorld, v.vertex); //点位置 CS>WSo.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz,0)).xyz); //切线方向o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS)*v.tangent.w); //副切方向TRANSFER_SHADOW(o);return o;}float4 frag(v2f i) :SV_TARGET{//纹理采样half4 var_MainTex = tex2D(_MainTex, i.uv0);half4 var_OcclusionTex = tex2D(_OcclusionTex, i.uv0);half dic =1- distance(i.uv0.xy, _CenterUv.xy)* var_OcclusionTex;clip(dic- _ClipNum);var_MainTex.rgb *= _BaseColor;//向量准备float3x3 TBN = float3x3(i.tDirWS, i.bDirWS, i.nDirWS);float4 var_normapTex = tex2D(_NormMap,i.uv2);float3 nDirTS = UnpackNormal(var_normapTex).rgb;float3 nDirTSOrigin = normalize(mul(nDirTS, TBN));nDirTS.xy *= (_NormalScale - (abs(i.uv0.y - 0.5)*(_NormalScale)));nDirTS.z = max(0.5, sqrt(1.0 - saturate(dot(var_normapTex.xy, var_normapTex.xy))));float3 nDirWS = normalize(mul(nDirTS, TBN));float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.WorldPos.xyz);float3 lDirWS = _WorldSpaceLightPos0.xyz;float3 lrDirWS = reflect(-lDirWS,nDirWS);//中间量准备float ndotl = max(0.5, dot(nDirWS, lDirWS));float vdotr = dot(vDirWS, lrDirWS);float vdotn = dot(vDirWS, nDirWS);//光照模型//光源漫反射half3 ambient = UNITY_LIGHTMODEL_AMBIENT.rgb;half3 baseCol = var_MainTex.rgb*ambient*_LightColor0;//half lambert = max(0.0, ndotl);//光源镜面反射half specPow = _SpecPow;half phong = pow(max(0.0,vdotr), _SpecPow);//光源反射混合half3 baseLighting = (baseCol + phong * _EnvSpecInt);//(baseCol * lambert + phong * _EnvSpecInt)//环境漫反身half3 envDiff = baseCol * _EnvDiffInt;half upMask = max(0.0, nDirTSOrigin.g);//环境镜面反射half3 fresnel = pow(max(0.0, 1.0 - vdotn), _FresnelPow) * _FresnelInt*ambient.rgb;//菲涅尔half3 envSpec = fresnel * _EnvSpecInt*ambient;//环境反射混合half3 envLighting = (envDiff + envSpec)*ambient*_LightColor0;//最终混合half3 finalRGB = (baseLighting+envLighting + fresnel )* var_OcclusionTex.r;// ;*(1 - scale)//返回值//阴影衰减UNITY_LIGHT_ATTENUATION(atten, i, i.WorldPos);return half4((finalRGB)*atten,1);}ENDCG}}FallBack "Diffuse" }

总结

以上是生活随笔为你收集整理的冰冻效果Shader案例的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。