该Shader使用了_MainTex和_BumpMap作为纹理输入,使用_RippleCenter、_RippleSize和_RippleSpeed三个属性来控制波纹的位置、大小和速度。 在顶点函数中,我们根据传入的顶点位置和法线计算出该顶点在世界空间中的坐标和法线。在片段函数中,我们使用之前计算出的位置和法线,结合_RippleCenter、_RippleSize和_RippleSpeed来计算出波纹效果,并作为纹理坐标进行采样。采样出的颜色最终作为Shader的输出结果。 在波纹效果计算中,我们先从_BumpMap中采样出法线贴图,然后计算出在正常情况下(即没有波纹效果)该顶点的法线。接着,我们计算波纹效果的偏移量,这里选择了一个定点作为波纹的发源地,并通过传入的_RippleCenter和_RippleSize属性来控制它的位置和大小。最后,我们根据时间和顶点的位置计算出每个顶点的波纹效果,并把它叠加到纹理坐标上。最后,我们再次采样_MainTex纹理,并将处理后的颜色作为Shader的输出结果返回。
水面波纹Shader代码,可作为参考,如果有报错请在空位添加个*(乘号):
// 定义一个自定义的水纹Shader
Shader "Custom/WaterRipple" {
// 定义所需属性
Properties {
_MainTex ("Texture", 2D) = "white" {}
_BumpMap("Normal Map", 2D) = "bump" {}
_RippleCenter("Ripple Center", Vector) = (0.5,0.5,0,0)
_RippleSize("Ripple Size", Range(0,1)) = 0.05
_RippleSpeed("Ripple Speed", Range(0,1)) = 0.1
}
SubShader {
Tags {"Queue"="Transparent" "RenderType"="Opaque" }
LOD 200
Pass {
CGPROGRAM
// 定义顶点着色器函数
#pragma vertex vert
// 定义片元着色器函数
#pragma fragment frag
// 引入UnityCG.cginc库
#include "UnityCG.cginc"
// 定义输入顶点数据结构体
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
// 定义输出顶点数据结构体
struct v2f {
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float3 worldPos : TEXCOORD1;
float3 worldNormal : TEXCOORD2;
};
// 定义纹理采样器
sampler2D _MainTex;
sampler2D _BumpMap;
float4 _RippleCenter;
float _RippleSize;
float _RippleSpeed;
// 定义顶点着色器函数
v2f vert (appdata v) {
v2f o;
// 位置转换为裁剪空间坐标
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
// 保存世界空间中的位置和法线信息
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
o.worldNormal = UnityObjectToWorldNormal(v.normal);
return o;
}
// 定义片元着色器函数
float4 frag (v2f i) : SV_Target {
float2 uv = i.uv;
float4 color = tex2D(_MainTex, uv);
// 采样法线图
float4 bump = tex2D(_BumpMap, uv);
// 根据法线图计算出法线信息
float2 normalMap = (bump.xy 2.0 - 1.0) _RippleSize;
// 计算片元到波纹中心的距离
float dist = distance(i.worldPos.xy, _RippleCenter.xy);
// 根据距离计算出波纹的大小
normalMap = pow(saturate((_RippleSize - dist) / _RippleSize), 2);
// 根据当前片元的位置和波纹中心的位置计算出角度
float angle = atan2(i.worldPos.y - _RippleCenter.y, i.worldPos.x - _RippleCenter.x);
// 加入时间偏移量和角度因素
float timeOffset = _Time.y _RippleSpeed + angle / (2 3.14159265359);
// 计算纹理坐标偏移
uv += normalMap sin(timeOffset) 0.025;
// 采样新的纹理颜色
color = tex2D(_MainTex, uv);
return color;
}
ENDCG
}
}
// 备选Shader
FallBack "Diffuse"
}
这个shader使用了正弦函数模拟火焰的动态效果,通过调节Amplitude、Distortion、SpeedX和SpeedY可以获得不同的效果。同时还使用了UV纹理偏移来模拟火焰的动态变化。您可以根据自己的需求进行调整。如果有报错请在空位添加个*(乘号)
// 定义自定义材质 "Custom/FireEffect"
Shader "Custom/FireEffect" {
Properties {
// 主纹理贴图,使用 2D 纹理类型,初始值为白色
_MainTex ("Texture", 2D) = "white" {}
// 颜色属性,初始值为白色
_Color ("Tint", Color) = (1,1,1,1)
// X 轴速度属性,范围在0到10之间,默认值为2
_SpeedX ("X-Speed", Range(0,10)) = 2
// Y 轴速度属性,范围在0到10之间,默认值为2
_SpeedY ("Y-Speed", Range(0,10)) = 2
// 振幅属性,范围在0到1之间,默认值为0.5
_Amplitude ("Amplitude", Range(0,1)) = 0.5
// 扭曲属性,范围在0到1之间,默认值为0.5
_Distortion ("Distortion", Range(0,1)) = 0.5
}
SubShader {
// 渲染类型为不透明
Tags { "RenderType"="Opaque" }
// LOD 等级设为100
LOD 100
CGPROGRAM
// 使用Standard表面着色器
#pragma surface surf Standard
// 声明和使用主纹理和其它属性
sampler2D _MainTex;
float4 _Color;
float _SpeedX;
float _SpeedY;
float _Amplitude;
float _Distortion;
// 定义输入结构体
struct Input {
float2 uv_MainTex; // 主纹理坐标
float4 worldPos; // 世界坐标
};
// 顶点函数(可选)
void vert (inout appdata_full v)
{
// 添加顶点位移以模拟火焰效果
v.vertex.xyz += _Amplitude sin(_Time.y _SpeedY + v.vertex.x + v.vertex.y) v.normal;
}
// 表面着色函数
void surf (Input IN, inout SurfaceOutputStandard o) {
// 计算纹理偏移量
float2 offset = float2((sin(_Time.y _SpeedX) + cos(_Time.y _SpeedY)) _Distortion, 0);
// 获取纹理颜色并应用颜色和透明度
float4 tex = tex2D(_MainTex, IN.uv_MainTex + offset);
o.Albedo = tex.rgb _Color.rgb;
o.Alpha = tex.a _Color.a;
}
ENDCG
}
// 回退方案为Diffuse
FallBack "Diffuse"
}
传送门特效Shader代码,附有注释说明,如果有报错请在空位添加个*(乘号):
Shader "Custom/PortalEffect" {
Properties {
// 设置传送门的颜色
_Color ("Color", Color) = (1,1,1,1)
// 设置传送门的强度
_Strength ("Strength", Range(0, 1)) = 0.5
// 设置传送门的位置和大小
_Portal("Portal", Range(-1,1)) = (0,0,0.5,0.5)
}
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// Unity定义的顶点输入结构体
struct appdata {
float4 vertex : POSITION;
};
// Unity定义的顶点输出结构体
struct v2f {
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
// 顶点着色器函数
v2f vert (appdata v) {
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.vertex.xy;
return o;
}
// 片段着色器函数
fixed4 frag (v2f i) : SV_Target {
// 获取传送门的位置和大小
float4 portal = _Portal;
// 将片段坐标转换到传送门空间
float2 uv = (i.vertex.xy - portal.xy) / portal.zw;
// 计算传送门中心点到当前点的距离
float distance = length(uv);
// 根据距离计算传送门的效果
float strength = smoothstep(0.0, _Strength, distance);
// 根据传送门颜色和强度来渲染
fixed4 col = _Color * strength;
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
这个Shader的代码结构包含以下部分: 1. Properties:定义了该Shader所需要的属性,包括传送门的颜色、强度和位置等。 2. SubShader:描述了该Shader的外观表现,包括标签、渲染顺序以及具体的渲染流程等。 3. Pass:定义了顶点着色器和片段着色器,并对它们进行了组合,构成了完整的渲染流程。 4. CGPROGRAM:标记了该Shader代码实现部分的开始。 5. #pragma vertex vert:表示该Shader使用的顶点着色器函数为vert。 6. #pragma fragment frag:表示该Shader使用的片段着色器函数为frag。 7. struct appdata:定义了包含顶点信息的输入结构体。 8. struct v2f:定义了包含着色器输出信息的输出结构体。 9. vert函数:实现了顶点着色器的功能,将输入的顶点信息转换为输出的顶点位置和纹理坐标。 10. frag函数:实现了片段着色器的功能,根据传送门的位置和大小来计算传送门的效果,并返回颜色值。 11. ENDCG:标记了该Shader代码实现部分的结束。 12. FallBack "Diffuse":定义了使用Diffuse Shader作为备选方案的情况,当无法使用该Shader时将使用该备选方案。
金币闪烁特效代码,注释已在代码中,如果有报错请在空位添加个*(乘号):
Shader "Custom/GoldCoinEffect"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_Shininess ("Shininess", Range(0.01, 1)) = 0.078125
_Specular ("Specular", Range(0, 1)) = 0
_Amount ("Amount", Range(0, 10)) = 1
_Speed ("Speed", Range(0, 10)) = 1
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// 使用Surface Shader功能,方便编写
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Color;
float _Shininess;
float _Specular;
float _Amount;
float _Speed;
v2f vert (appdata v)
{
v2f o;
// 使用mul函数,比直接相乘更快
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
// 从_MainTex采样纹理
fixed4 tex = tex2D(_MainTex, i.uv);
// 首先根据纹理的亮度判断哪些区域需要发光
fixed brightness = tex.a;
fixed4 result = brightness * _Color;
// 生成闪烁效果的代码
float2 seed = i.uv.xy _Amount;
fixed sinX = sin(seed.x + _Time.y _Speed);
fixed sinY = sin(seed.y + _Time.y _Speed);
// 生成一个0到1之间的数,这里使用tanh函数使数值更加平滑
fixed flicker = tanh((sinX + sinY) / (2.0 _Amount));
fixed4 glow = _Color * flicker;
// 先通过pow函数计算反射光的强度,再使用lerp函数生成高光区域
fixed4 specular = pow(_Specular, _Shininess) * _Color;
result += lerp(glow, specular, brightness);
return result;
}
ENDCG
}
}
FallBack "Diffuse"
}
简单的Unity物体残影Shader特效代码,并加上了注释以便您更好地理解。这个Shader可以应用于一个3D模型,并在它的运动过程中产生残影效果。如果有报错请在空位添加个*(乘号)
Shader "Custom/Canying"
{
Properties
{
_MainTex ("Texture", 2D) = "blue" {}
_Color ("Color", Color) = (0,0,1,1)
_TrailLength ("Trail Length", Float) = 1.0
_TrailTexture ("Trail Texture", 2D) = "white" {}
}
SubShader
{
Tags {"Queue"="Transparent" "RenderType"="Transparent""Queue" ="AlphaTest"}
LOD 100
ZWrite Off //关闭深度写入
Blend SrcAlpha OneMinusSrcAlpha //设置混合魔兽
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag_ps
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float4 color : COLOR;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 pos : SV_POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD0;
float3 worldPos : TEXCOORD1;
float4 trailPos : TEXCOORD2;
};
float4x4 _ObjectToWorld;
float4x4 _WorldToObject;
float4 _Color;
float _TrailLength;
float4 _trailColor;
sampler2D _MainTex;
sampler2D _TrailTexture;
v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.color = v.color * _Color;
o.uv = v.uv;
o.worldPos = mul(_ObjectToWorld, v.vertex).xyz; //获取世界坐标
o.trailPos = v.vertex; //将顶点位置传递到片元着色器
return o;
}
fixed4 frag_ps (v2f i) : COLOR //顶点着色器
{
fixed4 col = tex2D(_MainTex, i.uv) * i.color; //从主纹理获取颜色值
float trailAlpha = 0.1; //初始化残影的透明度为0
float3 camPos = UnityObjectToClipPos(i.worldPos); //获取摄像机在模型坐标系中的位置
for(int t = 0; t < 4; t++) //循环4次
{
float trailOffset = t * 0.23; //计算每次的偏移量
float4 trailPos = mul(_ObjectToWorld, i.trailPos); //将顶点位置转换为世界坐标
float3 camTrailPos = camPos + (normalize(trailPos - _WorldSpaceCameraPos) * trailOffset); //根据相机位置计算残影位置
float4 projCamTrailPos = UnityObjectToClipPos(camTrailPos); //将残影位置转换为裁剪空间坐标
float depthValue = (projCamTrailPos.z / projCamTrailPos.w); //将深度值转换为NDC坐标系中的深度值
float distFromCenter = length(projCamTrailPos.xy); //计算残影到屏幕中心的距离
float trailAlpha2 = ((1.0 - depthValue) * (1.0 - distFromCenter)) / _TrailLength; //计算残影透明度
if(trailAlpha2 > trailAlpha)
trailAlpha = trailAlpha2; //取透明度最大的值作为该像素的残影透明度
}
col.a = trailAlpha; //将残影透明度应用到颜色的Alpha通道上
col.rgb *= 1-(trailAlpha); //在残影的位置上减少颜色的强度
return col;
}
ENDCG
}
}
FallBack "Diffuse"
}
注释: 1. Properties:此项包含了我们将要使用到的变量的属性。 _MainTex:主贴图。 _Color:物体的颜色。 _TrailLength:残影的持续时间。 _TrailTexture:残影所使用的纹理。 2. SubShader:此项指定渲染物体时使用的着色器。 Tags:指定在什么时候渲染物体。 Pass:指定物体在何时进行渲染。 3. Vertex Shader:此项包含了在GPU上运行的代码。 #pragma vertex vert:使得当前函数成为GPU上的顶点着色器代码。 #pragma fragment frag_ps:使得当前函数成为GPU上的片元着色器代码。 struct appdata:它表示了输入数据,我们将每个顶点的位置、颜色、法向量和UV坐标打包到appdata结构体中。 struct v2f:它表示了另一组结构体,用于传递从顶点着色器到片元着色器的数据。 float4x4 _ObjectToWorld 和 float4x4 _WorldToObject:用于将物体从局部坐标系转换到世界坐标系。 float4 _Color 和 sampler2D _MainTex:输入颜色和主纹理。 float _TrailLength:残影持续时间。 float4 _trailColor 和 sampler2D _TrailTexture:残影颜色和残影纹理。 4. 主要逻辑:在顶点着色器中,我们将顶点位置乘以模型矩阵将其转换为世界坐标。在片元着色器中,我们计算出每个像素相对于摄像机的位置,然后根据残影的透明度和距离对其进行着色,最后将颜色输出到屏幕上。
人物身体描边
首先,需要在Unity中创建一个新材质,并将其Shader属性设置为“Custom”。然后,在该材质的Inspector窗口中,将其“Shader”属性设置为以下代码:
Shader "Custom/Outlined" {
Properties {
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
_OutlineColor ("Outline Color", Color) = (0,0,0,1)
_OutlineWidth ("Outline Width", Range(0.01, 0.1)) = 0.03
}
SubShader {
Tags {"Queue"="Transparent" "RenderType"="Opaque"}
LOD 100
CGPROGRAM
#pragma surface surf Standard
sampler2D _MainTex;
fixed4 _Color;
fixed4 _OutlineColor;
float _OutlineWidth;
struct Input {
float2 uv_MainTex;
float3 worldPos;
float3 worldNormal;
};
void surf (Input IN, inout SurfaceOutputStandard o) {
// 获取主纹理的颜色
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
// 计算法线方向和表面到相机的方向之间的点积
float ndotv = dot(IN.worldNormal, normalize(IN.worldPos - _WorldSpaceCameraPos));
// 如果点积小于等于0,则说明表面背对相机,不进行描边处理
if (ndotv <= 0)
{
o.Albedo = c.rgb;
o.Metallic = 0.0;
o.Smoothness = 1.0;
return;
}
// 计算描边的颜色和宽度
fixed4 outline = _OutlineColor * c.a;
float outlineWidth = _OutlineWidth / abs(ndotv);
// 获取描边的alpha值
float4 mask = tex2D(_MainTex, IN.uv_MainTex + outlineWidth) +
tex2D(_MainTex, IN.uv_MainTex - outlineWidth) +
tex2D(_MainTex, IN.uv_MainTex + float2(outlineWidth, -outlineWidth)) +
tex2D(_MainTex, IN.uv_MainTex + float2(-outlineWidth, outlineWidth));
float alpha = (mask.r + mask.g + mask.b + mask.a) * 0.25;
// 设置输出的表面属性
o.Albedo = c.rgb;
o.Metallic = 0.0;
o.Smoothness = 1.0;
o.Alpha = alpha;
o.Emission = outline.rgb * alpha;
}
ENDCG
}
FallBack "Diffuse"
}
该Shader包含了以下属性:
_MainTex
: 主纹理。_Color
: 基本颜色。_OutlineColor
: 描边的颜色。_OutlineWidth
: 描边的宽度。
该Shader使用了Unity内置的Surface Shader功能,因此可以很容易地控制光照、阴影等效果。具体实现过程如下:
- 首先,获取主纹理的颜色,并计算法线方向和表面到相机的方向之间的点积。
- 如果点积小于等于0,则说明表面背对相机,不进行描边处理。
- 否则,计算出描边的颜色和宽度,以及描边的alpha值。
- 最后,根据计算得到的结果设置输出的表面属性,包括基本颜色、描边颜色、描边的alpha值和发光颜色等。