http://game.ceeger.com/forum/read.php?tid=23209&fid=2

由于最近要做一个冰系的角色,就想能不能做一些冰霜效果。那么就试试吧,先弄一张原图:

[Shader 着色器]冰霜效果的思考和实现_贴图


1.常规的冰霜,最简单的要数霜冻的颜色变化,只需要减少亮度,增加蓝色分量。


片段着色器:


texcol *= fixed4(0.9, 0.9, 0.9, 1f);

texcol.b += 0.2;


效果如下:

[Shader 着色器]冰霜效果的思考和实现_#pragma_02

虽然简单,但效果也十分一般。


2.如果你玩过冰火围城,它里面的冰冻效果则是更加金属化,给人的感觉是一层灰色滤镜再增加一点蓝色,然后顶部会更亮。


首先,我们要计算法线夹角,方便处理顶部更亮这部分。


顶点着色器:


float3 normal = mul(SCALED_NORMAL, (float3x3)_World2Object);

fixed dotProduct = dot(normal, fixed3(0, 1, 0)) / 2;

if(dotProduct <= 0)

{

dotProduct = 0;

}

o.color = dotProduct.xxx;


然后灰化整个角色,并且增加顶部亮度。


片段着色器:


float grey = dot(texcol.rgb, float3(0.299, 0.587, 0.114)) + i.color.x;

texcol = fixed4(grey, grey, grey, texcol.a);

texcol.r -= 0.15;

texcol.b += 0.15;

效果如下:

[Shader 着色器]冰霜效果的思考和实现_贴图_03

不过由于这个模型本身比较暗,所以看上去有点像雕像。但这似乎不是我们想要的效果呢,于是我打算换一个思路,让材质先变成霜。


增加了一张贴图,看看霜的效果:

[Shader 着色器]冰霜效果的思考和实现_#pragma_04

哈哈,有点像冰棍了呢。但霜应该要亮一些,我打算增加下亮度,同时增加外发光。


顶点着色器:


fixed3 viewDir = normalize(ObjSpaceViewDir(v.vertex));

fixed dotProduct = 1 - dot(v.normal, viewDir);

o.color = smoothstep(0, 1, dotProduct);

o.color *= _RimColor;


片段着色器:


texcol.rgb += i.color;



效果:

[Shader 着色器]冰霜效果的思考和实现_贴图_05

可是这样就完全是冰棍了呢,我想要混合一下原始的像素,于是增加一个变量,控制一下混合。


片段着色器:


texcol = texcol * _Frezz + alpha * (1 - _Frezz);



设置效果:

[Shader 着色器]冰霜效果的思考和实现_#pragma_06

通过控制滚动条可以调整混合比例,这个大概是64开的比例,看着还行吧。



但这样就结束的话还是差强人意,因为冰霜的变化太过规则了,我们很多时候希望的是随机变化,显得更自然。


再增加一张噪点贴图,通过获得贴图的值调整混合比例。


float ClipTex = tex2D (_RandomTex, i.uv).r ;

float ClipAmount = (_Frezz - ClipTex) / 2 + 0.5;

if(ClipAmount < 0)

{

ClipAmount = 0;

}

if(ClipAmount > 1)

{

ClipAmount = 1;

}


效果如下:

[Shader 着色器]冰霜效果的思考和实现_贴图_07

这样马马虎虎吧,如果还要继续就需要法线贴图,遗憾的是这个模型没有法线贴图。


如果有法线贴图,我们可以再法线贴图层面上增加冰霜的颜色变化。


最后 的完整shader代码:




本部分设定了隐藏,您已回复过了,以下是隐藏的内容

// Upgrade NOTE: replaced 'PositionFog()' with multiply of UNITY_MATRIX_MVP by position

// Upgrade NOTE: replaced 'V2F_POS_FOG' with 'float4 pos : SV_POSITION'

Shader "Custom/CharactorShaderCullOff" {

Properties {

_MainTex ("Base (RGB)", 2D) = "white" {}

_AlphaTex ("Base (RGB)", 2D) = "white" {}

_RandomTex ("Base (RGB)", 2D) = "white" {}

_RimColor ("Rim Color", Color) = (1, 0, 0, 1)

_Color("_Color", Color) = (0.5,0.5,0.5,1)

_Rampage("_Rampage", Float) = 0

_Frezz("_Frezz", Range(0, 1)) = 0

}


SubShader {

//Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}

Pass {

cull off

Blend SrcAlpha OneMinusSrcAlpha

CGPROGRAM

// Upgrade NOTE: excluded shader from DX11 and Xbox360; has structs without semantics (struct v2f members pos1)

#pragma exclude_renderers d3d11 xbox360

#pragma vertex vert

#pragma fragment frag

#include "UnityCG.cginc"


struct appdata {

float4 vertex : POSITION;

float3 normal : NORMAL;

float2 texcoord : TEXCOORD0;

};


struct v2f {

half4 pos : SV_POSITION;

half2 uv : TEXCOORD0;

fixed3 color : COLOR;

};


uniform fixed4 _RimColor;

uniform fixed _Rampage;

uniform fixed _Frezz;


v2f vert (appdata_base v) {

v2f o;

o.pos = mul (UNITY_MATRIX_MVP, v.vertex);

if(_Rampage == 1)

{

fixed3 viewDir = normalize(ObjSpaceViewDir(v.vertex));

fixed dotProduct = 1 - dot(v.normal, viewDir);

o.color = smoothstep(0, 1, dotProduct);

o.color *= _RimColor;

}

float3 normal = mul(SCALED_NORMAL, (float3x3)_World2Object);

fixed dotProduct = dot(normal, fixed3(0, 1, 0)) / 2;

if(dotProduct <= 0)

{

dotProduct = 0;

}

o.color += dotProduct.xxx;

o.uv = v.texcoord.xy;

return o;

}


uniform sampler2D _MainTex;

uniform sampler2D _AlphaTex;

uniform sampler2D _RandomTex;

uniform fixed4 _Color;

fixed4 frag(v2f i) : COLOR {

fixed4 texcol = tex2D(_MainTex, i.uv);

fixed4 alpha = tex2D(_AlphaTex, i.uv);

float ClipTex = tex2D (_RandomTex, i.uv).r ;

float ClipAmount = (_Frezz - ClipTex) / 2 + 0.5;

if(ClipAmount < 0)

{

ClipAmount = 0;

}

if(ClipAmount > 1)

{

ClipAmount = 1;

}

if(_Rampage == 1)

{

texcol.rgb += i.color;

}

texcol = texcol * ClipAmount + alpha * (1 - ClipAmount);

texcol.a = alpha.a;

clip(texcol.a - 0.5);

texcol *= _Color;

return texcol;

}

ENDCG

}


}

}