在内置的 渲染管线一系列将场景内容显示在屏幕上的操作。 Unity 允许您从预制渲染管线中选择,或编写自己的渲染管线。 更多信息
参见 词汇表 中,表面着色器一种为内置渲染管线编写着色器的简化方法。 更多信息
参见 词汇表 对 DirectX 11 / OpenGL Core GPU 曲面细分具有一定的支持。
tessellate:FunctionName
修饰符指示。该函数计算三角形边和内部的曲面细分因子。vertex:FunctionName
)在曲面细分之后调用,针对域中的每个生成的顶点 着色器在 GPU 上运行的程序。 更多信息表面着色器支持简单的曲面细分和位移。当您编写自定义 着色器程序 时,可以使用完整的 DX11 着色器模型 5.0 功能集,包括几何着色器、外壳着色器和域着色器。
曲面细分支持的当前限制
功能名称 | 通用渲染管线 (URP) | 高清渲染管线 (HDRP) | 自定义 SRP | 内置渲染管线 |
---|---|---|---|---|
表面着色器 | 否 有关在 URP 中创建着色器对象的简化方法,请参见 着色器图。 |
否 有关在 HDRP 中创建着色器对象的简化方法,请参见 着色器图。 |
否 | 是 |
如果模型的面在屏幕上的大小大致相同,请向 网格Unity 中主要的图形基元。网格构成 3D 世界的大部分内容。 Unity 支持三角形或四边形多边形网格。 NURBS、NURMS、细分曲面必须转换为多边形。 更多信息
参见 词汇表 添加固定数量的曲面细分(在整个网格上使用相同的曲面细分级别)。
以下示例脚本应用固定数量的曲面细分。
Shader "Tessellation Sample" {
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
#pragma target 4.6
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"
}
在上面的示例中,tessFixed
曲面细分函数以单个 float4 值返回四个曲面细分因子:三个因子对应于三角形的每条边,一个因子对应于三角形的内部。
该示例返回在材质属性中设置的常量值。
您还可以根据与 摄像机创建场景中特定视点的图像的组件。 输出要么绘制到屏幕上,要么作为纹理捕获。 更多信息
参见 词汇表 的距离来更改曲面细分级别。 例如,您可以定义两个距离值
Shader "Tessellation Sample" {
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
#pragma target 4.6
#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"
}
在此,曲面细分函数将曲面细分前三个三角形角的顶点数据作为其三个参数。
Unity 需要此信息来计算曲面细分级别,这些级别取决于顶点位置。
该示例包含一个内置的辅助文件 Tessellation.cginc,并调用该文件中的 UnityDistanceBasedTess
函数来完成所有工作。该函数计算每个顶点到摄像机的距离并推导出最终的曲面细分因子。
纯基于距离的曲面细分仅在三角形大小非常相似时才有效。在上图中,具有小三角形的 游戏对象Unity 场景中的基本对象,可以表示角色、道具、场景、摄像机、路径点等等。 游戏对象的函数由附加到它的组件定义。 更多信息
参见 词汇表 被过度细分,而具有大三角形的 GameObjects 未被足够细分。
改进此问题的一种方法是根据屏幕上三角形边长来计算曲面细分级别。 Unity 应将更大的曲面细分因子应用于更长的边。
Shader "Tessellation Sample" {
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
#pragma target 4.6
#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"
}
在此示例中,您调用 Tessellation.cginc 中的 UnityEdgeLengthBasedTess
函数来完成所有工作。
出于性能原因,请改为调用 UnityEdgeLengthBasedTessCull 函数,该函数执行贴片视锥体剔除。这使得着色器稍微更昂贵,但可以为位于摄像机视图之外的网格部分节省大量 GPU 工作量。
Phong 曲面细分 修改细分面的位置,以便生成的表面略微遵循网格法线。这是一种使低多边形网格变得更平滑的非常有效的方法。
Unity 的表面着色器可以使用 tessphong:VariableName
编译指令自动计算 Phong 曲面细分。以下是一个示例着色器
Shader "Phong Tessellation" {
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"
}
以下是普通着色器(顶行)与使用 Phong 曲面细分的着色器(底行)之间的比较。可以看到,即使没有位移映射,表面也变得更圆润。