前言
接触UNITY的shader这两年时间一直想写些关于纪念碑谷的东西,其实你完全可以用普通的顶点着色器加上片段着色器实现文中内容,今天稍稍借题发挥一下:
1.关于几何着色器?
Input Assembler(IA)从顶点缓冲区上的输入流中接收顶点数据,并且把数据项转换为规范的格式。vertex shader通常用来把顶点从模型空间变换到平面空间,vertex shader读取一个顶点,输出一个顶点。Pixel Shader读取单一pixel属性,输出包含颜色和Z信息的的片断。而geometry shader是DirectX10提出的,把同一区域的所有顶点作为输入,产生新的顶点或者区域。此外数据流输出(steam output)把geometry shader输出的顶点信息复制为4个连续的输出缓冲子集。理论上来说,steam output的输出能力和Input Assembler的输入能力相匹配。
Shader就是一段可以改变像素、顶点和几何学特征的小程序。Vertex Shader是专门处理多边形顶点的。那么Geometry shader就是专门用来处理场景中的几何图形。在过去Vertex Shader每一次运行只能处理一个顶点的数据,并且每次只能输出一个顶点的结果。在整个游戏场景中,绘制的几何图形的任务量非常庞大,如果仅仅依靠 Vertex Shader单一来完成,效率会极其低下。
现在DX10的设计师们在顶点与像素的处理过程中又加入了(Geometry shader)几何着色器。它可以根据顶点的信息来批量处理几何图形,对Vertex附近的数据进行函数处理,快速创造出新的多边形。通过stream out将这些结果传递给其他Shader或buffer。
----几何着色器来源介绍
2.Unity3D下几何着色器实现的例子介绍
2.1 Properties的定义
Properties
{
_FaceColor("Face Color",Color) = (1,1,1,1)//面向光源显示的颜色
_BackColor("Back Color",Color) = (1,1,1,1)//背向光源显示的颜色
_MaxTex("Main Texture",2D) = "white" {} //主贴图
_NormalMap("Normal Map",2D) = "bump"{}//控制海面挪动的发现图
_Hightness("Hightness",Float) = 4//调节海面的挪动高度
_TimeRate("Time Rate",Float) = 0.2//控制海面的挪动频率
}
2.2 着色器的定义
Tags{"RenderType" = "Opaque" "Queue" = "Gepmetry"}
LOD 200
CGPROGRAM
# pragma 5.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
//定义顶点着色器
#pragma vertex vert
//定义片段着色器
#pragma fragment frag
//定义几何着色器
#pragma geometry geom
2.3 结构体的声明
struct a2v
{
float4 vertex : POSITION;//模型顶点位置
float3 normal : NORMAL;//模型法线
float4 texcoord : TEXCOORD0;//输入的坐标纹理集
float4 tangent : TANGENT;//模型切线
}
struct v2g
{
float4 pos :POSITION;//顶点位置
float2 uv :TEXCOORD0;//坐标纹理集
float3 lightDir : TEXCOORD1;//光照方向
}
struct g2f
{
float4 pos : POSITION;//位置信息
float2 uv : TEXCOORD0;//坐标纹理集
float3 diffColor:TEXCOORD1;//输出颜色
}
2.4 顶点着色器
v2g vert(a2v v)
{
v2g output;
float d2 = tex2Dlod(_NormalMap,float4(v.texcoord.xy+_Time.xx*_TimeRate,0,0)).r;//海水根据时间抖动高度
output.pos = mul(UNITY_MATRIX_MVP,v.vertex) + float4(0,d2,0,0)*_Heightness;//平面顶点位置
output.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
float3 binormal = cross(v.normal,v.tangent.xyz);//副法线
float3x3 rotation = float3x3(v.tangent.xyz , binormal , v.normal );//自身矩阵
output.lightDir = normalize(mul(UNITY_MATRIX_MVP,mul(rotation , ObjSpaceLightDir(v.vertex))));//光照方向
return output;
}
2.5 几何着色器
2.6 片段着色器
2.7 总览
Properties
{
_FaceColor("Face Color",Color) = (1,1,1,1)//面向光源显示的颜色
_BackColor("Back Color",Color) = (1,1,1,1)//背向光源显示的颜色
_MainTex("Main Texture",2D) = "white" {} //主贴图
_NormalMap("Normal Map",2D) = "bump"{}//控制海面挪动的发现图
_Hightness("Hightness",Float) = 1//调节海面的挪动高度
_TimeRate("Time Rate",Float) = 1//控制海面的挪动频率
}
SubShader
{
Pass
{
Tags{"RenderType" = "Opaque" "Queue" = "Gepmetry"}
LOD 200
CGPROGRAM
# pragma 5.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
//定义顶点着色器
#pragma vertex vert
//定义片段着色器
#pragma fragment frag
//定义几何着色器
#pragma geometry geom
struct a2v
{
float4 vertex : POSITION;//模型顶点位置
float3 normal : NORMAL;//模型法线
float4 texcoord : TEXCOORD0;//输入的坐标纹理集
float4 tangent : TANGENT;//模型切线
};
struct v2g
{
float4 pos :POSITION;//顶点位置
float2 uv :TEXCOORD0;//坐标纹理集
float3 lightDir : TEXCOORD1;//光照方向
};
struct g2f
{
float4 pos : POSITION;//位置信息
float2 uv : TEXCOORD0;//坐标纹理集
float3 diffColor:TEXCOORD1;//输出颜色
};
float4 _MainTex_ST;
sampler2D _MainTex;
float4 _NormalMap_ST;
sampler2D _NormalMap;
float _TimeRate;
float _Hightness;
fixed4 _FaceColor;
fixed4 _BackColor;
v2g vert(a2v v)
{
v2g output;
float d2 = tex2Dlod(_NormalMap,float4(v.texcoord.xy+_Time.xx*_TimeRate,0,0)).r;//海水根据时间抖动高度
output.pos = mul(UNITY_MATRIX_MVP,v.vertex) + float4(0,d2,0,0)*_Hightness;//平面顶点位置
output.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
float3 binormal = cross(v.normal,v.tangent.xyz) * v.tangent.w;//副法线
float3x3 rotation = float3x3(v.tangent.xyz , binormal , v.normal );//自身矩阵
output.lightDir = normalize(mul(UNITY_MATRIX_MVP,mul(rotation , ObjSpaceLightDir(v.vertex))));//光照方向
return output;
}
}
}