UnityShader之网格渲染、流光、模型切割
shader的东西虽然接触的已经有一些时间了,但是一直都没有系统的学过,都是自己看到哪学到哪,有时看见有趣的例子也会记录下来,便于以后查阅,今天记录一个几种效果集合的shader例子
首先,大家都知道在untiy scene场景中有一种渲染模式为wireframe,此种模式下模型为纯网格展示,非常有科技感的赶脚
于是想着实现一下,不过后来是在网上看到的例子,这里记录一下 #pragma geometry g
Geometry Shader是继Vertex Shader和Fragment Shader之后,由Shader Model 4(第四代显卡着色架构)正式引入的第三个着色器。 性能差因为不像 V和F那样高度并行.
Geometry Shader 是vertex和pixel之间的一个optional的stage.
V的功能是处理顶点,G是处理图元,最后光栅化后传给F. 通俗理解:G是用来处理三角形的
V的输出 传给 G 作为输入,G 处理完成后,G的输出 传给 F作为输入
G输出的是最后的齐次裁剪空间,也就是经过mvp。
还有就是加了流光和模型切割,直接贴上代码好了
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
Shader "Custom/Wireframe"
{
Properties
{
_MainTex("texture",2D)="white"{}
_Color("Color", Color) = (1,1,1,1)
_DiffuseScale("diffuse",Range(0,1))=0.1
_WireColor("WireColor", Color) = (1,0,0,1)
_Speed("Flash_Speed", Float) = 1.0
_Angle("Flash_Angle",Range(-1.57,1.57)) = 0.78
_Length("Flash_Length",Float) = 0.3
_FlashColor("flash",Color)=(1,1,1,1)
_ClipLineY("clipy",Float) = 10
_ClipLine_Y("clip_y",Float)=-10
_ClipLine_X("clip_x",Float) = 10
_ClipLineX("clipx",Float)=-10
_ClipLine_Z("clip_z",Float)=10
_ClipLineZ("clipz",Float)=-10
_CutTex("CutTexture",2D) = "white"{}
_CutColor("cutcolor",color)=(1,1,1,1)
_Sensity("Sens",Float) = 1
}
SubShader
{
PASS{
//blend srcalpha oneminussrcalpha
//zwrite on
Cull FRONT
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma vertex vert
// Use shader model 3.0 target, to get nicer looking lighting
#pragma fragment frag
#include "UnityCG.cginc"
#include "lighting.cginc"
float4 _CutColor;
sampler2D _CutTex;
// sampler2D unity_Lightmap;
float4 _CutTex_ST;
// float4 unity_LightmapST;
float _ClipLineY;
float _ClipLineX;
float _ClipLineZ;
float _ClipLine_X;
float _ClipLine_Y;
float _ClipLine_Z;
float _Sensity;
struct v2f{
float4 pos:POSITION;
float4 vertex:COLOR;
float2 uv:TEXCOORD0;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.vertex = v.vertex;
o.uv = TRANSFORM_TEX(v.texcoord,_CutTex);
return o;
}
fixed4 frag (v2f IN):COLOR
{
fixed4 col =tex2D(_CutTex,IN.uv)*_CutColor;
float4 tpos = mul(unity_ObjectToWorld, IN.vertex);
if (tpos.x < _ClipLineX*_Sensity||tpos.x>_ClipLine_X*_Sensity)
{
discard;
}
if (tpos.y > _ClipLineY*_Sensity||tpos.y<_ClipLine_Y*_Sensity)
{
discard;
}
if (tpos.z < _ClipLineZ*_Sensity||tpos.z>_ClipLine_Z*_Sensity) {
discard;
}
return col;
}
ENDCG
}
Pass
{
Cull Back
CGPROGRAM
#include "UnityCG.cginc"
#pragma target 5.0
#pragma vertex vert
#pragma geometry geom
#pragma fragment frag
half4 _WireColor, _Color;
sampler2D _MainTex;
float _DiffuseScale;
float _Speed;
float _Angle;
float _Length;
fixed4 _FlashColor;
float4 _CutColor;
sampler2D _CutTex;
// sampler2D unity_Lightmap;
float4 _CutTex_ST;
// float4 unity_LightmapST;
float _ClipLineY;
float _ClipLineX;
float _ClipLineZ;
float _ClipLine_X;
float _ClipLine_Y;
float _ClipLine_Z;
float _Sensity;
struct v2g
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 vert:COLOR;
};
struct g2f
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 dist : TEXCOORD1;
float4 vert:COLOR;
};
v2g vert(appdata_base v)
{
v2g OUT;
OUT.pos = UnityObjectToClipPos(v.vertex);
OUT.uv = v.texcoord; //the uv's arent used in this shader but are included in case you want to use them
OUT.vert=v.vertex;
return OUT;
}
//网格渲染部分
[maxvertexcount(3)]
void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream)
{
float2 WIN_SCALE = float2(_ScreenParams.x/2.0, _ScreenParams.y/2.0);
//frag position
float2 p0 = WIN_SCALE * IN[0].pos.xy / IN[0].pos.w;
float2 p1 = WIN_SCALE * IN[1].pos.xy / IN[1].pos.w;
float2 p2 = WIN_SCALE * IN[2].pos.xy / IN[2].pos.w;
//barycentric position
float2 v0 = p2-p1;
float2 v1 = p2-p0;
float2 v2 = p1-p0;
//triangles area
float area = abs(v1.x*v2.y - v1.y * v2.x);
g2f OUT;
OUT.pos = IN[0].pos;
OUT.uv = IN[0].uv;
OUT.dist = float3(area/length(v0),0,0);
OUT.vert = IN[0].vert;
triStream.Append(OUT);
OUT.pos = IN[1].pos;
OUT.uv = IN[1].uv;
OUT.dist = float3(0,area/length(v1),0);
OUT.vert = IN[1].vert;
triStream.Append(OUT);
OUT.pos = IN[2].pos;
OUT.uv = IN[2].uv;
OUT.dist = float3(0,0,area/length(v2));
OUT.vert = IN[2].vert;
triStream.Append(OUT);
}
half4 frag(g2f IN) : COLOR
{
float4 tpos = mul(unity_ObjectToWorld, IN.vert);
if (tpos.x < _ClipLineX*_Sensity||tpos.x>_ClipLine_X*_Sensity)
{
discard;
}
if (tpos.y > _ClipLineY*_Sensity||tpos.y<_ClipLine_Y*_Sensity)
{
discard;
}
if (tpos.z < _ClipLineZ*_Sensity||tpos.z>_ClipLine_Z*_Sensity) {
discard;
}
//distance of frag from triangles center
float d = min(IN.dist.x, min(IN.dist.y, IN.dist.z));
//float d = min(IN.dist.x,max(IN.dist.y,IN.dist.z)*IN.dist.w);
//fade based on dist from center
float I = exp2(-4.0*d*d);
float4 col = lerp(tex2D(_MainTex,IN.uv)+_Color*_DiffuseScale,_WireColor,I);
//流光部分
float size = 1.f + abs(tan(_Angle));//在Y轴投影最大值/
if (_Length < 0.f)
_Length = 0.f;//宽度最低为0/
if (_Length > size)
_Length = size;
float bottom = fmod(_Time.y*_Speed, size);//取余,实现循环播放/
if (_Angle < 0.f)
bottom += tan(_Angle);//角度为负时需要将运动起始点向下移动tan(_Angle)的距离/
if (_Speed < 0.f)
bottom = size + bottom;
float top = bottom + _Length *(_Speed / abs(_Speed));//top为运动方向上的上方/
float alpha = min(1.f, abs(((bottom + top) / 2.f - IN.uv.x*tan(_Angle)) - IN.uv.y) / (_Length/2.f));//根据该点距离闪光中心的距离设定alpha/
col.rgb = lerp(_FlashColor.rgb, col.rgb, alpha);//alpha越高,说明距离闪光中心越远,取值越接近原像素颜色/
return col;
}
ENDCG
}
}
}
最后是效果图