Shader第二十六讲 Tessellation
Unity
5.1之前的版本,OpenGL
ES2.0 、3.0
、desktop
OpenGL的渲染都是分别的版本。而5.1,unity使用统一的open
GL渲染器,所以一些渲染的新功能DX和OpenGL都可以使用:
Tessellation
Shader:细分曲面。安卓平台需要支持
Android Extension
Pack
Geometry
Shader:几何Shader。
Compute
Shader:
计算Shader。OpenGL
desktop 4.3+
,OpenGL
ES
3.1+
下面用一张图说明这些Shader的关系。
本讲就来介绍Tessellation细分曲面。
当我们显示普通的模型时,效果一般,于是有了法线贴图。但是法线贴图有局限性,例如入视角。而DX11的
Tessellation是真正的生成更细致的mesh。一句话就是把模型的三角面细分成一组更小的面,再配合Displace贴图等信息进行处理。
Unity的Surface Shader支持Tessellation,例子如下
[例一:基本细分曲面]
步骤
1:准备Displacement和Normal
两张贴图。Displacement根据亮度决定细分曲面的高度或者说凸起程度。
2:代码中添加
tessellate:tessFixed
float _Tess;
float4 tessFixed()
{
return _Tess;
}
这个表示每个三角面细分的量级
3:对
Displacement进行纹理采样,并沿法线方向作相应偏移。
void disp (inout appdata v)
{
float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
v.vertex.xyz += v.normal * d;
}
- Shader "Tessellation/1FixedAmount" {
- Properties {
- _Tess ("Tessellation", Range(1,32)) = 4
- _MainTex ("Base (RGB)", 2D) = "white" {}
- _DispTex ("Disp Texture", 2D) = "gray" {}
- _NormalMap ("Normalmap", 2D) = "bump" {}
- _Displacement ("Displacement", Range(0, 1.0)) = 0.3
- _Color ("Color", color) = (1,1,1,0)
- _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
- }
- SubShader {
- Tags { "RenderType"="Opaque" }
- LOD 300
- CGPROGRAM
- #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessFixed nolightmap
- struct appdata {
- float4 vertex : POSITION;
- float4 tangent : TANGENT;
- float3 normal : NORMAL;
- float2 texcoord : TEXCOORD0;
- };
- float _Tess;
- float4 tessFixed()
- {
- return _Tess;
- }
- sampler2D _DispTex;
- float _Displacement;
- void disp (inout appdata v)
- {
- float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
- v.vertex.xyz += v.normal * d;
- }
- struct Input {
- float2 uv_MainTex;
- };
- sampler2D _MainTex;
- sampler2D _NormalMap;
- fixed4 _Color;
- void surf (Input IN, inout SurfaceOutput o) {
- half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
- o.Albedo = c.rgb;
- o.Specular = 0.2;
- o.Gloss = 1.0;
- o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
[例二:基于距离细分曲面]
基于相机距离进行细分,离相机越近细分面数越多。
float4 tessDistance (appdata v0, appdata v1, appdata v2) {
float minDist = 10.0;
float maxDist = 25.0;
return UnityDistanceBasedTess(v0.vertex, v1.vertex, v2.vertex, minDist, maxDist, _Tess);
}
- Shader "Tessellation/2Distance" {
- Properties {
- _Tess ("Tessellation", Range(1,32)) = 4
- _MainTex ("Base (RGB)", 2D) = "white" {}
- _DispTex ("Disp Texture", 2D) = "gray" {}
- _NormalMap ("Normalmap", 2D) = "bump" {}
- _Displacement ("Displacement", Range(0, 1.0)) = 0.3
- _Color ("Color", color) = (1,1,1,0)
- _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
- }
- SubShader {
- Tags { "RenderType"="Opaque" }
- LOD 300
- CGPROGRAM
- #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessDistance nolightmap
- #include "Tessellation.cginc"
- struct appdata {
- float4 vertex : POSITION;
- float4 tangent : TANGENT;
- float3 normal : NORMAL;
- float2 texcoord : TEXCOORD0;
- };
- float _Tess;
- float4 tessDistance (appdata v0, appdata v1, appdata v2) {
- float minDist = 10.0;
- float maxDist = 25.0;
- return UnityDistanceBasedTess(v0.vertex, v1.vertex, v2.vertex, minDist, maxDist, _Tess);
- }
- sampler2D _DispTex;
- float _Displacement;
- void disp (inout appdata v)
- {
- float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
- v.vertex.xyz += v.normal * d;
- }
- struct Input {
- float2 uv_MainTex;
- };
- sampler2D _MainTex;
- sampler2D _NormalMap;
- fixed4 _Color;
- void surf (Input IN, inout SurfaceOutput o) {
- half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
- o.Albedo = c.rgb;
- o.Specular = 0.2;
- o.Gloss = 1.0;
- o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
[例三:边缘长度曲面]
根据三角面的边缘长度进行细分,也就是越大的三角细分越多
float4 tessEdge (appdata v0, appdata v1, appdata v2)
{
return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
}
- Shader "Tessellation/3EdgeLength" {
- Properties {
- _EdgeLength ("Edge length", Range(2,50)) = 15
- _MainTex ("Base (RGB)", 2D) = "white" {}
- _DispTex ("Disp Texture", 2D) = "gray" {}
- _NormalMap ("Normalmap", 2D) = "bump" {}
- _Displacement ("Displacement", Range(0, 1.0)) = 0.3
- _Color ("Color", color) = (1,1,1,0)
- _SpecColor ("Spec color", color) = (0.5,0.5,0.5,0.5)
- }
- SubShader {
- Tags { "RenderType"="Opaque" }
- LOD 300
- CGPROGRAM
- #pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessEdge nolightmap
- #include "Tessellation.cginc"
- struct appdata {
- float4 vertex : POSITION;
- float4 tangent : TANGENT;
- float3 normal : NORMAL;
- float2 texcoord : TEXCOORD0;
- };
- float _EdgeLength;
- float4 tessEdge (appdata v0, appdata v1, appdata v2)
- {
- return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
- }
- sampler2D _DispTex;
- float _Displacement;
- void disp (inout appdata v)
- {
- float d = tex2Dlod(_DispTex, float4(v.texcoord.xy,0,0)).r * _Displacement;
- v.vertex.xyz += v.normal * d;
- }
- struct Input {
- float2 uv_MainTex;
- };
- sampler2D _MainTex;
- sampler2D _NormalMap;
- fixed4 _Color;
- void surf (Input IN, inout SurfaceOutput o) {
- half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
- o.Albedo = c.rgb;
- o.Specular = 0.2;
- o.Gloss = 1.0;
- o.Normal = UnpackNormal(tex2D(_NormalMap, IN.uv_MainTex));
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
[例四: Phong细分曲面]
如果是low poly的模型的话,沿着法线方向去细分效果并不好。
而我们可以用Phong Tesselation去细分,该方法尤其适用于low poly模型。
tessphong:_Phong
#pragma surface surf Lambert vertex:dispNone tessellate:tessEdge tessphong:_Phong nolightmap
- Shader "Tessellation/4Phong" {
- Properties {
- _EdgeLength ("Edge length", Range(2,50)) = 5
- _Phong ("Phong Strengh", Range(0,1)) = 0.5
- _MainTex ("Base (RGB)", 2D) = "white" {}
- _Color ("Color", color) = (1,1,1,0)
- }
- SubShader {
- Tags { "RenderType"="Opaque" }
- LOD 300
- CGPROGRAM
- #pragma surface surf Lambert vertex:dispNone tessellate:tessEdge tessphong:_Phong nolightmap
- #include "Tessellation.cginc"
- struct appdata {
- float4 vertex : POSITION;
- float3 normal : NORMAL;
- float2 texcoord : TEXCOORD0;
- };
- void dispNone (inout appdata v) { }
- float _Phong;
- float _EdgeLength;
- float4 tessEdge (appdata v0, appdata v1, appdata v2)
- {
- return UnityEdgeLengthBasedTess (v0.vertex, v1.vertex, v2.vertex, _EdgeLength);
- }
- struct Input {
- float2 uv_MainTex;
- };
- fixed4 _Color;
- sampler2D _MainTex;
- void surf (Input IN, inout SurfaceOutput o) {
- half4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
- o.Albedo = c.rgb;
- o.Alpha = c.a;
- }
- ENDCG
- }
- FallBack "Diffuse"
- }
参考资料:
Surface Shaders with DX11 Tessellation
Phong Tessellation
《Introduction_to_3D_Game_Programming_with_Directx_11》
|