Shader入门—曲面细分着色器和几何着色器
前记:学不可以停止-------------------------------mx
基础知识:
曲面细分着色器:可以将一个几何体细化为一个球体也能将一根直线无限向曲线逼近
使用曲面细分的好处:直接使用顶点数更多的模型会带来更高的性能消耗,曲面细分能根据规则来动态调整模型的复杂度,达到对应的效果
曲面细分着色器的输入输出:
曲面细分着色器流程:
Hull Shader各参数解析:
几何着色器:专门处理场景里的几何图形,可以将创建或销毁几何图元,可以根据顶点的信息批量处理几何图形,对顶点附近的数据进行函数的处理,快速创造出新的多边形(Vertex Shader是专门处理多边形顶点的,而Geometry shader就是专门用来处理场景中的几何图形)
几何着色器的输入输出:
输入:图元—顶点,边,三角形等
points-GL_POINTS (1)
lines-GL_LINES, GL_LINE_STRIP, GL_LINE_LIST (2)
lines_adjacency-GL_LINES_ADJACENCY, GL_LINE_STRIP_ADJACENCY (4)
triangles-GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN(3)
triangles_adjacency-GL_TRIANGLES_ADJACENCY, GL_TRIANGLE_STRIP_ADJACENCY (6)
输出:图元(输出图元类型跟输入图元类型完全不同,而且输出图元的数量和输入图元数量也没有关系)
points
line_strip
triangle_strip
几何着色器的实际应用:
曲面细分着色器shader
Shader "Custom/TessShader"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_TessellationUniform ("_TessellationUniform", Range(1,64)) = 1
}
SubShader
{
Name "FORWARD"
Tags
{
"LightMode"="ForwardBase"
}
LOD 200
Pass{
CGPROGRAM
#pragma hull hullProgram
#pragma domain ds
#pragma vertex tessvert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Tessellation.cginc"
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 5.0
sampler2D _MainTex;
float4 _MainTex_ST;
struct VertexInput
{
float4 vertex : POSITION;
float3 normal : NORMAL ;
float4 tangent : TANGENT ;
float2 uv : TEXCOORD;
};
struct VertexOutput
{
float4 vertex : SV_POSITION;
float3 normal :NORMAL;
float4 tangent :TANGENT;
float2 uv : TEXCOORD;
};
VertexOutput vert (VertexInput v)//这个函数应用在domain函数中,用来处理坐标
{
VertexOutput o;
o.uv =TRANSFORM_TEX(v.uv,_MainTex);
o.vertex =UnityObjectToClipPos(v.vertex);
o.normal =v.normal;
o.tangent = v.tangent;
return o;
}
#ifdef UNITY_CAN_COMPILE_TESSELLATION
struct TessVertex
{
float4 vertex: INTERNALTESSPOS;
float3 normal :NORMAL;
float4 tangent :TANGENT;
float2 uv :TEXCOORD0;
};
struct OutputPatchConstant//不同图元该结构会有所不同
{
float edge[3] : SV_TESSFACTOR;
float inside : SV_INSIDETESSFACTOR;
};
TessVertex tessvert (VertexInput v)
{
TessVertex o;
o.vertex = v.vertex;
o.normal = v.normal;
o.tangent=v.tangent;
o.uv = v.uv;
return o;
}
float _TessellationUniform;
OutputPatchConstant hsconst (InputPatch<TessVertex , 3> patch)
{
OutputPatchConstant o;
o.edge[0] = _TessellationUniform;
o.edge[1] = _TessellationUniform;
o.edge[2] = _TessellationUniform;
o.inside = _TessellationUniform;
return o;
}
[UNITY_domain("tri")]//去掉图元
[UNITY_partitioning("fractional_odd")]
[UNITY_outputtopology("triangle_cw")]
[UNITY_patchconstantfunc("hsconst")]//规定曲面细分的属性,一个patch有三个点,但是三个点都会共用这个函数
[UNITY_outputcontrolpoints(3)]//不同的图元会对应不同的控制点
TessVertex hullProgram (InputPatch<TessVertex,3> patch ,uint id:SV_OutputControlPointID)
{
return patch[id];
}
[UNITY_domain("tri")]//同样需要定义图元
VertexOutput ds (OutputPatchConstant tessFactors ,const OutputPatch<TessVertex,3> patch ,float3 bary :SV_DOMAINLOCATION)
{
VertexOutput v;
v.vertex = patch[0].vertex * bary.x + patch[1].vertex*bary.y +patch[2].vertex*bary.z;
v.tangent =patch[0].tangent*bary.x +patch[1].tangent*bary.y +patch[2].tangent*bary.z;
v.normal =patch[0].normal*bary.x + patch[1].normal * bary.y +patch[2].normal*bary.z;
v.uv =patch[0].uv*bary.x + patch[1].uv *bary.y +patch[2].uv * bary.z;
VertexOutput o =vert(v);
return o;
}
#endif
float4 frag(VertexOutput i) :SV_Target
{
return float4(1.0,1.0,1.0,1.0);
}
ENDCG
}
}
FallBack "Diffuse"
}
曲面细分着色器shader与置换贴图结合
Shader "Unlit/Tess_Diss_Shader"
{
Properties
{
_MainTex("MainTex",2D) = "white"{}
_DisplacementMap("_DisplacementMap",2D)="gray"{}
_DisplacementStrength("DisplacementStrength",Range(0,1)) = 0
_Smoothness("Smoothness",Range(0,5))=0.5
_TessellationUniform("TessellationUniform",Range(1,64)) = 1
}
SubShader
{
Tags { "RenderType"="Opaque"
"LightMode"="ForwardBase"}
LOD 100
Pass
{
CGPROGRAM
//定义2个函数 hull domain
#pragma hull hullProgram
#pragma domain ds
#pragma vertex tessvert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
//引入曲面细分的头文件
#include "Tessellation.cginc"
#pragma target 5.0
float _TessellationUniform;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _DisplacementMap;
float4 _DisplacementMap_ST;
float _DisplacementStrength;
float _Smoothness;
struct VertexInput
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
float4 tangent : TANGENT;
};
struct VertexOutput
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float4 worldPos:TEXCOORD1;
half3 tspace0 :TEXCOORD2;
half3 tspace1 :TEXCOORD3;
half3 tspace2 :TEXCOORD4;
};
VertexOutput vert (VertexInput v)
//这个函数应用在domain函数中,用来空间转换的函数
{
VertexOutput o;
o.uv = TRANSFORM_TEX(v.uv,_MainTex);
//Displacement
//由于并不是在Fragnent shader中读取图片,GPU无法获取mipmap信息,因此需要使用tex2Dlod来读取图片,使用第四坐标作为mipmap的level,这里取了0
float Displacement = tex2Dlod(_DisplacementMap,float4(o.uv.xy,0.0,0.0)).g;
Displacement = (Displacement-0.5)*_DisplacementStrength;
v.normal = normalize(v.normal);
v.vertex.xyz += v.normal * Displacement;
o.pos = UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld, v.vertex);
//计算切线空间转换矩阵
half3 vNormal = UnityObjectToWorldNormal(v.normal);
half3 vTangent = UnityObjectToWorldDir(v.tangent.xyz);
//compute bitangent from cross product of normal and tangent
half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
half3 vBitangent = cross(vNormal,vTangent)*tangentSign;
//output the tangent space matrix
o.tspace0 = half3(vTangent.x,vBitangent.x,vNormal.x);
o.tspace1 = half3(vTangent.y,vBitangent.y,vNormal.y);
o.tspace2 = half3(vTangent.z,vBitangent.z,vNormal.z);
return o;
}
//有些硬件不支持曲面细分着色器,定义了该宏就能够在不支持的硬件上不会变粉,也不会报错
#ifdef UNITY_CAN_COMPILE_TESSELLATION
//顶点着色器结构的定义
struct TessVertex{
float4 vertex : INTERNALTESSPOS;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float2 uv : TEXCOORD0;
};
struct OutputPatchConstant {
//不同的图元,该结构会有所不同
//该部分用于Hull Shader里面
//定义了patch的属性
//Tessellation Factor和Inner Tessellation Factor
float edge[3] : SV_TESSFACTOR;
float inside : SV_INSIDETESSFACTOR;
};
TessVertex tessvert (VertexInput v){
//顶点着色器函数
TessVertex o;
o.vertex = v.vertex;
o.normal = v.normal;
o.tangent = v.tangent;
o.uv = v.uv;
return o;
}
//float _TessellationUniform;
OutputPatchConstant hsconst (InputPatch<TessVertex,3> patch){
//定义曲面细分的参数
OutputPatchConstant o;
o.edge[0] = _TessellationUniform;
o.edge[1] = _TessellationUniform;
o.edge[2] = _TessellationUniform;
o.inside = _TessellationUniform;
return o;
}
[UNITY_domain("tri")]//确定图元,quad,triangle等
[UNITY_partitioning("fractional_odd")]//拆分edge的规则,equal_spacing,fractional_odd,fractional_even
[UNITY_outputtopology("triangle_cw")]
[UNITY_patchconstantfunc("hsconst")]//一个patch一共有三个点,但是这三个点都共用这个函数
[UNITY_outputcontrolpoints(3)] //不同的图元会对应不同的控制点
TessVertex hullProgram (InputPatch<TessVertex,3> patch,uint id : SV_OutputControlPointID){
//定义hullshaderV函数
return patch[id];
}
[UNITY_domain("tri")]//同样需要定义图元
VertexOutput ds (OutputPatchConstant tessFactors, const OutputPatch<TessVertex,3>patch,float3 bary :SV_DOMAINLOCATION)
//bary:重心坐标
{
VertexInput v;
v.vertex = patch[0].vertex*bary.x + patch[1].vertex*bary.y + patch[2].vertex*bary.z;
v.tangent = patch[0].tangent*bary.x + patch[1].tangent*bary.y + patch[2].tangent*bary.z;
v.normal = patch[0].normal*bary.x + patch[1].normal*bary.y + patch[2].normal*bary.z;
v.uv = patch[0].uv*bary.x + patch[1].uv*bary.y + patch[2].uv*bary.z;
VertexOutput o = vert (v);
return o;
}
#endif
float4 frag (VertexOutput i) : SV_Target
{
float3 lightDir =_WorldSpaceLightPos0.xyz;
float3 tnormal = UnpackNormal (tex2D (_DisplacementMap, i.uv));
half3 worldNormal;
worldNormal.x=dot(i.tspace0,tnormal);
worldNormal.y= dot (i.tspace1, tnormal);
worldNormal.z=dot (i.tspace2, tnormal);
float3 albedo=tex2D (_MainTex, i.uv). rgb;
float3 lightColor = _LightColor0.rgb;
float3 diffuse = albedo * lightColor * DotClamped(lightDir,worldNormal);
float3 viewDir = normalize (_WorldSpaceCameraPos. xyz-i. worldPos. xyz);
float3 halfVector = normalize(lightDir + viewDir);
float3 specular = albedo * pow (DotClamped (halfVector, worldNormal), _Smoothness * 100);
float3 result = specular + diffuse;
return float4(result, 1.0);
return float4(result,1.0);
}
ENDCG
}
}
Fallback "Diffuse"
}
几何着色器shader
_DissolveThreshold、_ColorFactor的值需要根据不同的模型修改
Shader "My/DoublePass"
{
Properties
{
_Diffuse("Diffuse", Color) = (1,1,1,1)
_DissolveColor("Dissolve Color", Color) = (0,0,0,0)
_MainTex("Base 2D", 2D) = "white"{}
_ColorFactor("ColorFactor", Range(0,0.001)) = 0.0004
_DissolveThreshold("DissolveThreshold", Range(-0.002,0.02)) = 0
_BoxScale("BoxScale",Range(0,1)) = 0.001
_BoxColor("BoxColor",Color) = (1,1,1,1)
_Alpha("_Alpha",Range(0,1))=1
}
SubShader
{
Pass{
Tags{ "RenderType" = "Opaque" }
Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
uniform fixed4 _Diffuse;
uniform fixed4 _DissolveColor;
uniform sampler2D _MainTex;
uniform float4 _MainTex_ST;
uniform float _ColorFactor;
uniform float _DissolveThreshold;
struct v2f
{
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD0;
float2 uv : TEXCOORD1;
float4 objPos : TEXCOORD2;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject);
o.objPos = v.vertex;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float factor = i.objPos.z -_DissolveThreshold ;
clip(factor);
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);
fixed3 lambert = saturate(dot(worldNormal, worldLightDir));
fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;
fixed3 color = tex2D(_MainTex, i.uv).rgb * albedo;
if (factor < _ColorFactor)
{
return _DissolveColor;
}
return fixed4(color, 1);
}
ENDCG
}
Pass {
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
Blend One One
Cull Off
CGPROGRAM
#pragma target 4.0
#pragma vertex vert
#pragma geometry geo
#pragma fragment frag
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2g
{
float4 vertex : POSITION;
float3 normal : NORMAL;
float2 uv : TEXCOORD0;
float4 objPos: TEXCOORD1;
};
struct g2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _BoxScale;
fixed4 _BoxColor;
float _ColorFactor;
float _DissolveThreshold;
float _Alpha;
v2g vert (appdata v) {
v2g o;
o.vertex = v.vertex;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.objPos = v.vertex;
return o;
}
#define ADD_VERT(v) \
o.vertex = UnityObjectToClipPos(v); \
TriStream.Append(o);
#define ADD_TRI(p0, p1, p2) \
ADD_VERT(p0) ADD_VERT(p1) \
ADD_VERT(p2) \
TriStream.RestartStrip();
[maxvertexcount(36)]
void geo(triangle v2g v[3], inout TriangleStream<g2f> TriStream) {
float4 vertex = (v[0].vertex + v[1].vertex + v[2].vertex) / 3;
float2 uv = (v[0].uv + v[1].uv + v[2].uv) / 3;
float3 edgeA = v[1].vertex - v[0].vertex;
float3 edgeB = v[2].vertex - v[0].vertex;
float3 normalFace = normalize(cross(edgeA, edgeB));
float factor = vertex.z - _DissolveThreshold;
//if(factor < 0) return;
if(factor < _ColorFactor &&factor+_ColorFactor*2 > _ColorFactor)
{
//这里存粹是为效果而设置的,让它看上去是对的。
vertex.xyz += normalFace * lerp(0,0.005,sin(_Time*0.5));
//不同的消散效果可以调不同的参数
g2f o;
o.uv = uv;
float scale = _BoxScale;
float4 v0 = float4( 1, 1, 1,1)*scale + float4(vertex.xyz,0);
float4 v1 = float4( 1, 1,-1,1)*scale + float4(vertex.xyz,0);
float4 v2 = float4( 1,-1, 1,1)*scale + float4(vertex.xyz,0);
float4 v3 = float4( 1,-1,-1,1)*scale + float4(vertex.xyz,0);
float4 v4 = float4(-1, 1, 1,1)*scale + float4(vertex.xyz,0);
float4 v5 = float4(-1, 1,-1,1)*scale + float4(vertex.xyz,0);
float4 v6 = float4(-1,-1, 1,1)*scale + float4(vertex.xyz,0);
float4 v7 = float4(-1,-1,-1,1)*scale + float4(vertex.xyz,0);
ADD_TRI(v0, v2, v3);
ADD_TRI(v3, v1, v0);
ADD_TRI(v5, v7, v6);
ADD_TRI(v6, v4, v5);
ADD_TRI(v4, v0, v1);
ADD_TRI(v1, v5, v4);
ADD_TRI(v7, v3, v2);
ADD_TRI(v2, v6, v7);
ADD_TRI(v6, v2, v0);
ADD_TRI(v0, v4, v6);
ADD_TRI(v5, v1, v3);
ADD_TRI(v3, v7, v5);
}
else
{
vertex.xyz =float3(0,0,0);
}
}
fixed4 frag (g2f i) : SV_Target {
float4 col = _BoxColor;
col.a = _Alpha;
return col;
}
ENDCG
}
}
}
学习相关链接:
https://www.bilibili.com/video/BV1XX4y1A7Ns
https://blog.csdn.net/qq_37925032/article/details/82936769
https://www.yuque.com/docs/share/4941142e-6c9e-4f6d-8e53-ee053ef42a2e?#
https://www.yuque.com/sugelameiyoudi-jadcc/okgm7e/xyx5h5
https://zhuanlan.zhihu.com/p/76775024
https://blog.csdn.net/vampirem/article/details/12152945?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%87%A0%E4%BD%95%E7%9D%80%E8%89%B2%E5%99%A8&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-7-.nonecase&spm=1018.2226.3001.4187
------------------------------博主:mx