Unity Shader之Tessellation
2017-06-29 17:29
856 查看
这是一个很牛逼的东东,得益于显卡技术的发展,可以将一些粗糙的低精模型,搞出高精的效果,首先,来说说本质是啥
如图所示,Tessellation就是可以在原来的三角形上细分出很多更小的三角形,增加很多顶点。
但是在具体运用中,我们应该怎么使用,达到我们想要的效果呢,这里就不得不先说一个东西置换贴图,也叫高度图,大家都知道法线贴图,可以使一个平面产生视觉上凹凸的感觉,但是这个平面越垂直于我们的视线,看起来效果就越假,因为始终这还是一个平面,没有产生物理上的形变,高度图就是帮我们解决这个问题,用一张图来位移这个平面上的顶点,使之真正获得物理上的形变,可以看下每种不同的效果,如图
第一张只有漫反射,第二个加入法线贴图,第三个贴上置换贴图获得形变。
为啥刚还在说Tessellation,怎么突然就说到置换贴图了,这是因为,在Tessellation这个技术出来之前,置换贴图的效果其实是不怎么好的,这是因为用到置换贴图的时候,需要用到足够多的顶点去支持这个形变,打个比方,一张平面上只有8个顶点,你贴一张精美的浮雕动物像上去,却只有这8个点获得形变,你可以想象一下最后出来的效果,肯定成四不像了,在tessellation技术出来之前,要用到置换贴图,需要模型本身的顶点数非常多,是高精模型,这就限制了置换贴图的使用。
回头你再看看Tessellation,就知道我为什么要说置换贴图了吧
对!我们可以把置换贴图和Tessellation结合起来,就可以在低精模型上实现我们想要的高精效果!
先看看unity shader里面使用Tessellation的语法吧,unity官方文档里面是用表面着色器来举例子,这里也只讨论用表面着色器用Tessellation的方法,在vertex/frag shader里面使用的话,要涉及到hull和domain shader ,下面是实现的代码,有兴趣的同学可以看看,这里就不多阐述了
这里我们重点讲下表面着色器中的使用方法,很简单适合初学者,首先在加上相关Tessellation的声明
看到没,只需要在声明中加上tessellate:tessFixed
tessFixed是一个函数,返回一个float4
UnityDistanceBasedTess //根据摄像机远近来生成顶点,越近的地方生成顶点越多
UnityEdgeLengthBaseTess //根据三角形大小来生成顶点,三角形越大的顶点生成越多
还有一些其他的函数,大家可以自行查看。也可以根据自己的需求自行定义
除此之外,我们还可以使用一些算法,在不使用displacement贴图的时候,让一些低精的模型边缘看起来更圆滑一遍,如图所示
很简单,unity为我们封装了一个叫Phone tessellation的方法,只需要在刚声明tessellation的地方加上tessphone:_Phone _Phone是一个浮点数,可以让用户自行定义,除了这个算法,还有其他的算法,这个感兴趣的可以自行研究实现了
如图所示,Tessellation就是可以在原来的三角形上细分出很多更小的三角形,增加很多顶点。
但是在具体运用中,我们应该怎么使用,达到我们想要的效果呢,这里就不得不先说一个东西置换贴图,也叫高度图,大家都知道法线贴图,可以使一个平面产生视觉上凹凸的感觉,但是这个平面越垂直于我们的视线,看起来效果就越假,因为始终这还是一个平面,没有产生物理上的形变,高度图就是帮我们解决这个问题,用一张图来位移这个平面上的顶点,使之真正获得物理上的形变,可以看下每种不同的效果,如图
第一张只有漫反射,第二个加入法线贴图,第三个贴上置换贴图获得形变。
为啥刚还在说Tessellation,怎么突然就说到置换贴图了,这是因为,在Tessellation这个技术出来之前,置换贴图的效果其实是不怎么好的,这是因为用到置换贴图的时候,需要用到足够多的顶点去支持这个形变,打个比方,一张平面上只有8个顶点,你贴一张精美的浮雕动物像上去,却只有这8个点获得形变,你可以想象一下最后出来的效果,肯定成四不像了,在tessellation技术出来之前,要用到置换贴图,需要模型本身的顶点数非常多,是高精模型,这就限制了置换贴图的使用。
回头你再看看Tessellation,就知道我为什么要说置换贴图了吧
对!我们可以把置换贴图和Tessellation结合起来,就可以在低精模型上实现我们想要的高精效果!
先看看unity shader里面使用Tessellation的语法吧,unity官方文档里面是用表面着色器来举例子,这里也只讨论用表面着色器用Tessellation的方法,在vertex/frag shader里面使用的话,要涉及到hull和domain shader ,下面是实现的代码,有兴趣的同学可以看看,这里就不多阐述了
#ifdef UNITY_CAN_COMPILE_TESSELLATION struct TessVertex { float4 vertex : INTERNALTESSPOS; float3 normal : NORMAL; float4 tangent : TANGENT; }; struct OutputPatchConstant { float edge[3] : SV_TessFactor; float inside : SV_InsideTessFactor; float3 vTangent[4] : TANGENT; float2 vUV[4] : TEXCOORD; float3 vTanUCorner[4] : TANUCORNER; float3 vTanVCorner[4] : TANVCORNER; float4 vCWts : TANWEIGHTS; }; TessVertex tessvert (VertexInput v) { TessVertex o; o.vertex = v.vertex; o.normal = v.normal; o.tangent = v.tangent; return o; } float Tessellation(TessVertex v){ return _node_5663; } float4 Tessellation(TessVertex v, TessVertex v1, TessVertex v2){ float tv = Tessellation(v); float tv1 = Tessellation(v1); float tv2 = Tessellation(v2); return float4( tv1+tv2, tv2+tv, tv+tv1, tv+tv1+tv2 ) / float4(2,2,2,3); } OutputPatchConstant hullconst (InputPatch<TessVertex,3> v) { OutputPatchConstant o = (OutputPatchConstant)0; float4 ts = Tessellation( v[0], v[1], v[2] ); o.edge[0] = ts.x; o.edge[1] = ts.y; o.edge[2] = ts.z; o.inside = ts.w; return o; } [domain("tri")] [partitioning("fractional_odd")] [outputtopology("triangle_cw")] [patchconstantfunc("hullconst")] [outputcontrolpoints(3)] TessVertex hull (InputPatch<TessVertex,3> v, uint id : SV_OutputControlPointID) { return v[id]; } [domain("tri")] VertexOutput domain (OutputPatchConstant tessFactors, const OutputPatch<TessVertex,3> vi, float3 bary : SV_DomainLocation) { VertexInput v = (VertexInput)0; v.vertex = vi[0].vertex*bary.x + vi[1].vertex*bary.y + vi[2].vertex*bary.z; v.normal = vi[0].normal*bary.x + vi[1].normal*bary.y + vi[2].normal*bary.z; v.tangent = vi[0].tangent*bary.x + vi[1].tangent*bary.y + vi[2].tangent*bary.z; VertexOutput o = vert(v); return o; } #endif
这里我们重点讲下表面着色器中的使用方法,很简单适合初学者,首先在加上相关Tessellation的声明
#pragma surface surf BlinnPhong addshadow fullforwardshadows vertex:disp tessellate:tessFixed nolightmap
看到没,只需要在声明中加上tessellate:tessFixed
tessFixed是一个函数,返回一个float4
float4 tessFixed() { return _Tess; }这里tess是一个参数,可以用户自定义,也可以根据不同的条件在不同的情况使用不同的数值,大家可以看下Tessellation.cginc这个脚本,可以看到unity为我们提供了常见的几种函数可以处理这个问题
UnityDistanceBasedTess //根据摄像机远近来生成顶点,越近的地方生成顶点越多
UnityEdgeLengthBaseTess //根据三角形大小来生成顶点,三角形越大的顶点生成越多
还有一些其他的函数,大家可以自行查看。也可以根据自己的需求自行定义
除此之外,我们还可以使用一些算法,在不使用displacement贴图的时候,让一些低精的模型边缘看起来更圆滑一遍,如图所示
很简单,unity为我们封装了一个叫Phone tessellation的方法,只需要在刚声明tessellation的地方加上tessphone:_Phone _Phone是一个浮点数,可以让用户自行定义,除了这个算法,还有其他的算法,这个感兴趣的可以自行研究实现了
相关文章推荐
- Unity Shader Bump Diffuse
- 【Unity实用小方法】判断shader使用贴图数
- [UnityShader]渲染队列、ZWrite和ZTest
- Unity Shader 使用枚举切换整体色调
- UnityShader Legacy Texture Combine
- Unity 实时 半透明 阴影 shader
- Github上unity-shader智能提示和高亮插件
- 【Unity Shader编程】之十六 基于MatCap实现适于移动平台的“次时代”车漆Shader
- Unity之Shader Pass 通道显示贴图的几种方法- 六
- 【Unity Shader】Unity Shader基础入门
- UnityShader边缘光
- 【Unity】用Shader实现图片的区域遮罩,支持半透明,实现地图动态上色功能
- Unity Shader——Writing Surface Shaders(0)
- Unity里用shader让物体显示出边框效果
- unity shader:数学基础
- [UnityShader]去色效果
- Unity 琐碎(2): Shader 颜色调试
- unity, 替换shader渲染(Rendering with Replaced Shaders)
- Unity Fresnel Hero(Dota2) Shader
- unity屏幕shader之油画屏幕