曲面细分函数tessFixed返回一个float4的值:xyz是三角形的三个顶点的细分程度,w是比例。在本shader里只是一个float常量来作为模型的细分程度。
We can also change tessellation level based on distance from the camera. For example, we could define two distance values; distance at which tessellation is at maximum, and distance towards which tessellation level gradually decreases.
我们也能通过模型与相机的距离改变细分程度。举个例子,我们需要定义两个距离值;一个是距离相机最近的距离值,一个是最远的距离值。
We found the UnityDistanceBasedTess function In 'Tessellation.cginc'
“Tessellation.cginc”中我们找到了UnityDistanceBasedTess函数
float4 UnityDistanceBasedTess (float4 v0, float4 v1, float4 v2, float minDist, float maxDist, float tess){ float3 f; f.x = UnityCalcDistanceTessFactor (v0,minDist,maxDist,tess); f.y = UnityCalcDistanceTessFactor (v1,minDist,maxDist,tess); f.z = UnityCalcDistanceTessFactor (v2,minDist,maxDist,tess); return UnityCalcTriEdgeTessFactors (f);}We can see the UnityDistanceBasedTess function is call theUnityCalcDistanceTessFactor function, we also found it in the 'Tessellation.cginc';
我们能看到UnityDistanceBasedTess函数主要还是调用UnityCalcDistanceTessFactor这个函数,于是我们又在'Tessellation.cginc'中找到了它;
float UnityCalcDistanceTessFactor (float4 vertex, float minDist, float maxDist, float tess){ float3 wpos = mul(_Object2World,vertex).xyz; float dist = distance (wpos, _WorldSpaceCameraPos); float f = clamp(1.0 - (dist - minDist) / (maxDist - minDist), 0.01, 1.0) * tess; return f;}In the UnityCalcDistanceTessFactor function ,take the vertex chang to world space, then compute the distance between the vertex and the camera,finally compute the tess.
在UnityCalcDistanceTessFactor函数中把点转换为世界坐标wpos,在求出点与同是世界坐标的相机的距离dist,再求出细分程度tess。
Here the tessellation function takes three parameters; the vertex data of three triangle corners before tessellation. This is needed to compute tessellation levels, which depend on vertex positions now. We include a built-in helper file “Tessellation.cginc” (in EditorDataCGIncludes) and call UnityDistanceBasedTess function from it to do all the work. That function computes distance of each vertex to the camera and derives final tessellation factors.
这里的细分函数有三个参数;三角形的三个角在曲面细分之前顶点数据。这通过顶点位置来计算细分程度。我们声明包含帮助文件“Tessellation.cginc”(EditorDataCGIncludes中)并且调用其中的UnityDistanceBasedTess函数来做所有工作。那个函数计算每个顶点与相机的距离,并返回细分函数的float4值。
远(far):
近(close):
这个gif也能体现相机距离与细分程度的变化
Purely distance based tessellation is good only when triangle sizes are quite similar.
Tessellation levels could be computed based on triangle edge length on the screen - the longer the edge, the larger tessellation factor should be applied.
单纯的基于距离的曲面细分只是在当在三角形大小差不多时效果很好。
将要基于屏幕上的三角形边缘长度计算曲面细分,可以使用更大的细分程度
UnityEdgeLengthBasedTess function inbound three parameters v0, v1, v2 is the three vertices of the triangle.
UnityEdgeLengthBasedTess传入的v0,v1,v2是三角形的三个顶点
float UnityCalcEdgeTessFactor (float3 wpos0, float3 wpos1, float edgeLen){ // distance to edge center float dist = distance (0.5 * (wpos0+wpos1), _WorldSpaceCameraPos); // length of the edge float len = distance(wpos0, wpos1); // edgeLen is approximate desired size in pixels float f = max(len * _ScreenParams.y / (edgeLen * dist), 1.0); return f;}
In UnityEdgeLengthBasedTess function compute the distance of the middle of two vertices and the camera’s postation(both two are in world space) , then compute the distance of two vertices, finally compute the tess;
UnityCalcEdgeTessFactor中先求出两个点的中点与相机的距离(全是世界坐标),再求出两个点的距离,再求出细分程度
For performance reasons, it’s advisable to call UnityEdgeLengthBasedTessCull function instead, which will do patch frustum culling. This makes the shader a bit more expensive, but saves a lot of GPU work for parts of meshes that are outside of camera’s view.
由于性能的原因,可以适当的调用UnityEdgeLengthBasedTessCull函数代替(通过判断相机平截头体,对不在范围内的点不进行细分),
调用这个代替函数虽然也浪费一些性能,但不必细分不必要的点
Before see the Phong tessellation shader, we need to know that theory.
再看Phong曲面细分的shader之前先
深入了解一下Phong曲面细分
This is the Phong tessellation by Tamy Boubekeu and Marc Alexa
Tamy Boubekeur和Marc Alexa 做出的phong曲面细分,
They explain the theory in a video.
他们用一个视频来简要讲解做法
输入一个带有法线的三角形,在重心插入点来做线性细分
正交投影在与此点的“点法式”(法线相垂直的)平面上
在投射的位置线性的插入
1. 计算出线性细分
2. 在三角形三个点上的正切平面上做正交投射
3. 计算重心插入这三个投影
这是他们做出的结果:
Phong Tessellation modifies positions of the subdivided faces so that the resulting surface follows the mesh normals a bit. It’s quite an effective way of making low-poly meshes become more smooth.
Unity’s surface shaders can compute Phong tessellation automatically using tessphong:VariableName compilation directive.
Phong细分修改细分面的位置,使细分面沿着法线突出一点。这是一个让低模变光滑的非常有效的方式。
Unity得surface shaders中能使用tessphong:VariableName编译指令自动计算Phong曲面细分。
Shader 'Custom/testShader' { 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' }
Let’s see a comparison between regular shader and one that uses Phong tessellation. Even without any displacement mapping, the surface becomes more round.
看看普通shader和Phong细分之后的比较。如果不用之前几个shader的贴图置换,你也能看到模型的表面比以前更圆更光滑了
Base on Phong tessellation we add Displacement mapping, the result is perfect
曲面细分再加上贴图置换(Displacement mapping)就是完美
欢迎光临 纳金网 (http://go.narkii.com/club/) | Powered by Discuz! X2.5 |