曲面细分
详细介绍

当然除了细分与简化之外,还有另外一种同属一类的操作叫做==曲面规则化(Mesh Regularization)==其所作的便是将三角面都变的尽可能相同,从而也达到提升模型效果的目的

曲面细分shader内容:

原文连接

  • 曲面细分又分为:Hull shader 、Tessellation Primitive Generator 、 Domain shader

    • Hull shader主要作用:定义一些细分的参数(如:每条边上如何细分,内部三角形如何细分)
    • Tessellation Primitive Generator,不可编程的
    • Domain shader:经过曲面细分着色器细分后的点是位于重心空间的,这部分的作用就是把它转化到我们要用的空间。

Hull Shader

由两部分组成:

  • Constant Hull Shader:对于每一个patch(原始三角片) 都会执行一次这个constant hull shader,其功能是用来输出所谓的细分因子(tessellation factor).细分因子用于在tessellation 阶段告诉硬件如何对patch进行细分。
struct PatchTess
{float EdgeTess[3]:SV_TessFactor;float InsideTess:SV_InsideTessFactor;
};
PatchTess constantHS(InputPatch<VertexOut,3> patch,uint patchID:SV_PrimitiveID)
{PatchTess pt;pt.EdgeTess[0]=3;pt.EdgeTess[1]=3;pt.EdgeTess[2]=3;pt.InsideTess=3;    }

constant hull shader 通过InputPatch<VertexOut,3> 以patch内的所有控制点作为输入。看渲染管线图可以知道,hull shader的输入来自于顶点着色器,因此VertexOut就是顶点着色器的输出。系统同时通过SV_PrimitiveID提供了一个称之为patch ID的变量,这个ID是patch在该次绘制中的唯一标识。constant hull shader必须以 细分因子作为输出。对于拓扑结构为三角面的模型,其细分因子的结构如上面代码所示。不同细分因子的结果如下所示

  • Control Point Hull Shader
    control point hull shader使用多个控制点作为输入(原始模型顶点),并且输出多个控制点。每输出一个控制点都会调用一次 control point hull shader。通常在hull shader阶段输出的控制点数目和输入的控制点数目一致,除非我们要改变模型的几何结构,例如把一个三角面输出为一个三阶贝塞尔曲面。真真正的曲面细分实在下一个tessellation stage完成的。
struct HullOut
{float3 PosL:TEXCOORD0;
};[domain("tri")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("ConstantHS")]
[maxtessfactor(64.0f)]
HullOut HS(InputPatch<VertexOut,3> p,uint i:SV_OutputControlPointID)
{HullOut hout;hout.PosL=p[i].PosL;return hout;
}

前面提到 control point hull shader是每一个输出的control point 都要执行一次,因此这里引入了SV_OutputControlPointID语义修饰的参数i,表示当前hull shader正在处理的那个 control point 的索引。例子中中输入的controlpoint和输出的contorl point数目一致,但是实践中输出的control point数目可以多于输入的control point的数目,多出来的control point的信息,可以根据算法以及输入的control point进行计算。 control point hull shader引入了一系列属性:

  • domain: patch 类型或者叫做模型图元的拓扑结构有效参数为tri,quad,isoline。tri表示三角面
  • partitioning:指定曲面细分的拆分模式
    • integer:新的顶点只在细分因子为整数时进行添加或删除,细分因子的小数部分被忽略,这种情况下对于动态曲面细分因子,会出现在某个点(整数点)模型精度突然提高或减低,会有肉眼可见的精度突变
    • fraction:新的顶点依然在位于整数细分因子时(1.0,2.0,3.0等)进行添加或删除,但是根据细分因子的小数部分进行平滑过度。fraction模式,包括fractional_even和fractional_odd
  • outputtopology:输出的三角面正面的环绕方式
    • triangle_cw:顶点顺时针排列代表正面
    • triangle_ccw:顶点逆时针排列代表正面
    • line:只针对line的细分
  • outputcontrolpoints:输出的control point 的数目,同时也是control point hull shader的执行次数,因为每输出一个control point ,都执行一次hull shader.SV_OutputControlPointID语义指定的索引值的总数,对应于这里的control point数目
  • patchconstantfunc:一个字符串指定的constant hull shader 函数的名字,既前面的constant hull shader
  • maxtessfactor:告诉硬件最大的细分因子,有了此上限值,硬件可以执行某些优化,例如可以预先知道需要多少资源来执行曲面细分。Direct3D 11支持的最大值为64.其他硬件支持的最大值可能为16,因此unity中使用通常使用16作为最大值上限。

Tessellation Primitive Generator

作为程序员我们没法控制 tessellation stage的执行,该阶段的任务都是由硬件完成的,硬件根据constant hull shader输出的细分因子和control point,来决定如何对patch进行细分。

Domain Shader

tessellation stage输出我们新创建的所有顶点。 对于每一个tessellation stage输出的顶点都会调用一次domain shader.
当开启曲面细分时,vertex shader的功能是处理每一个control point,而domain shader才是实际上的处理细分的patch的顶点着色器。使用中,我们通常在这里把细分过的顶点坐标,投影到齐次裁减空间,包括顶点法线,切线,UV的处理都在这里执行。在domain shader中,以 constant hull shader输出的细分因子和control point hull shader 输出的control point,以及和细分过的顶点位置相关的参数化的(u,v,w)坐标作为输入,使用这个和实际顶点位置一一对应的参数化的(u,v,w)坐标以及其他输入参数,我们可以计算得到实际的顶点坐标。
对于拓扑结构为三角面的图元,这里的(uvw)三维坐标是重心点坐标。对于其他拓扑结构例如四边形quad,只需要二维(uv)即可描述细分坐标(类似纹理uv)。

struct DomainOut
{float4 PosH:SV_POSITION;
};
[domain("tri")]
DomainOut DS(PatchTess patchTess,float3 baryCoords:SV_DomainLocation,const OutputPatch<HullOut,3> triangles)
{DomainOut dout;              float3 p=triangles[0].PosL*baryCoords.x+triangles[1].PosL*baryCoords.y+triangles[2].PosL*baryCoords.z;    dout.PosH=TransformObjectToHClip(p.xyz);return dout;
}

曲面细分实现

曲面细分的逐步实现

  • 一个曲面细分实现的头文件:
    Customtessellation.cginc
// Tessellation programs based on this article by Catlike Coding:
// https://catlikecoding.com/unity/tutorials/advanced-rendering/tessellation/struct vertexInput
{float4 vertex : POSITION;float3 normal : NORMAL;float4 tangent : TANGENT;
};struct vertexOutput
{float4 vertex : SV_POSITION;float3 normal : NORMAL;float4 tangent : TANGENT;
};struct TessellationFactors
{float edge[3] : SV_TessFactor;float inside : SV_InsideTessFactor;
};vertexInput vert(vertexInput v)
{return v;
}vertexOutput tessVert(vertexInput v)
{vertexOutput o;// Note that the vertex is NOT transformed to clip// space here; this is done in the grass geometry shader.o.vertex = v.vertex;o.normal = v.normal;o.tangent = v.tangent;return o;
}float _TessellationUniform;TessellationFactors patchConstantFunction (InputPatch<vertexInput, 3> patch)
{TessellationFactors f;f.edge[0] = _TessellationUniform;f.edge[1] = _TessellationUniform;f.edge[2] = _TessellationUniform;f.inside = _TessellationUniform;return f;
}[UNITY_domain("tri")]
[UNITY_outputcontrolpoints(3)]
[UNITY_outputtopology("triangle_cw")]
[UNITY_partitioning("integer")]
[UNITY_patchconstantfunc("patchConstantFunction")]
vertexInput hull (InputPatch<vertexInput, 3> patch, uint id : SV_OutputControlPointID)
{return patch[id];
}[UNITY_domain("tri")]
vertexOutput domain(TessellationFactors factors, OutputPatch<vertexInput, 3> patch, float3 barycentricCoordinates : SV_DomainLocation)
{vertexInput v;#define MY_DOMAIN_PROGRAM_INTERPOLATE(fieldName) v.fieldName = \patch[0].fieldName * barycentricCoordinates.x + \patch[1].fieldName * barycentricCoordinates.y + \patch[2].fieldName * barycentricCoordinates.z;MY_DOMAIN_PROGRAM_INTERPOLATE(vertex)MY_DOMAIN_PROGRAM_INTERPOLATE(normal)MY_DOMAIN_PROGRAM_INTERPOLATE(tangent)return tessVert(v);
}

完整shader:

Shader "Unlit/TessShader"
{Properties{_TessellationUniform("TessellationUniform",Range(1,64)) = 1}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM//定义2个函数 hull domain#pragma hull hullProgram#pragma domain ds#pragma vertex tessvert#pragma fragment frag#include "UnityCG.cginc"//引入曲面细分的头文件#include "Tessellation.cginc" #pragma target 5.0struct VertexInput{float4 vertex : POSITION;float2 uv : TEXCOORD0;float3 normal : NORMAL;float4 tangent : TANGENT;};struct VertexOutput{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;float3 normal : NORMAL;float4 tangent : TANGENT;};VertexOutput vert (VertexInput v)//这个函数应用在domain函数中,用来空间转换的函数{VertexOutput o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;o.tangent = v.tangent;o.normal = v.normal;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 Factorfloat 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;}#endiffloat4 frag (VertexOutput i) : SV_Target{return float4(1.0,1.0,1.0,1.0);}ENDCG}}Fallback "Diffuse"
}

Shader学习_曲面细分着色器相关推荐

  1. 曲面细分着色器学习记录

    曲面细分着色器学习记录 前言: 今天终于走通了Catlike大佬的曲面细分着色器教程,感慨一番,自己的学习之路还很漫长呢 今天的博客内容只是简单的记录一下Catlike大佬的教程 先上个链接:Catl ...

  2. UnityShader 曲面细分着色器 生成地形 高度贴图

    什么是曲面细分着色器 如下图 ​ 曲面细分着色器比较官方定义:可以将一个几何体细化为一个球体也能将一根直线无限向曲线逼近 曲面细分着色器将复杂的曲面转换为简单的点,线,三角形等.它分为三部分:曲面细分 ...

  3. unity曲面细分着色器详解

     前言:本文翻译自catlikecoding上一篇十分详细的英文blog并修改了几处错误,逐行解释了如何在自己的shader中添加曲面细分支持,并给出了多种计算细分因子的方案以及它们的优缺点. 原文链 ...

  4. Shader入门---曲面细分着色器和几何着色器

    Shader入门-曲面细分着色器和几何着色器 前记:学不可以停止-------------------------------mx 基础知识: 曲面细分着色器:可以将一个几何体细化为一个球体也能将一根 ...

  5. 曲面细分着色器---细分二维四边形

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一.曲面细分 二.细分二维四边形 参考 前言 术语Tessellation(镶嵌)是指一大类设计活动,通常是指在平坦的表面上,用各种 ...

  6. 曲面细分着色器与几何着色器

    着色器执行顺序 顶点着色器->曲面细分着色器->几何着色器->片元着色器 曲面细分着色器细分后的顶点属于重心空间. 曲面细分着色器 应用:海浪.雪地等 与置换贴图结合:只使用法线贴图 ...

  7. 曲面细分(subdivision)曲面细分着色器GPU的LOD

    曲面细分是指将一个模型的面合理的分成更多小的面,从而提升模型精度,提高渲染效果 曲面简化是指将一个模型的面合理的合成更少的面,从而降低模型精度,为特定情形下提供使用(如LOD技术) .这一过程是可以在 ...

  8. DirectX 12 曲面细分着色器笔记

    曲面细分着色器 1. 背景 2. 曲面细分工作机制 2.1 Hull Shader(外壳着色器) 2.2 Tessellator(曲面细分器) 2.3 Domain Shader(域细分器) 3. 编 ...

  9. Unity Shader:细分着色器(Tessellation Shader)在Unity顶点着色器中的写法以及各参数变量解释

    图1:在Unity内将sphere细分后 图2:在Unity内将sphere细分后 Unity官网关于细分着色器的资料比较少,只有在Surface Shader中使用的例子.我看了下Surface S ...

最新文章

  1. train_test_split()
  2. 赛迪展望 | 一文了解“2021年中国先进计算产业发展趋势”
  3. HDU 3973 AC's String 字符串哈希
  4. EAE:自编码器 + BN + 最大熵 = 生成模型
  5. redis之五大数据类型
  6. Maven学习总结(37)——利用GitHub或阿里云OSS对象存储、又拍云、七牛云存储等搭建个人Maven仓库
  7. vue 兼容IE报错解决方案
  8. clinit和init(转载)
  9. SQL 模糊表名查询
  10. 3dm java32位_3DM游戏运行库合集安装包v2.3
  11. 【稀饭】react native 实战系列教程之数据存储
  12. 【OTT】国内主要OTT平台背后的那些CDN服务商
  13. systrace如何使用
  14. android 自定义字体 ttf,Android使用自定义字体的方法
  15. 传奇客户端小地图上的文字描述修改方法
  16. 计算机芯片级维修包括哪些,计算机芯片级维修中心(芯片级维培训教材)b.doc
  17. 解析北斗部标协议_部标一体机北斗模块预测试
  18. 记录解决Win10底部任务栏转圈圈问题的过程(Windows假死)
  19. 牛客网C++刷题《华为机试》
  20. 一文弄懂JVM内存结构,垃圾回收器和垃圾回收算法

热门文章

  1. 【机器学习算法】模拟退火(Simulated Annealing)
  2. PP、PTFE、FEP、PVDF丝网除雾器 丝网除沫器种类规格介绍--A行业推荐A
  3. 6.1UiPath Orchestrator的注册
  4. 办公室各种办公用品集锦
  5. Felix笔记2-使用OBR(OSGi Bundel Repository)
  6. python在画布上显示动态图片_python Tkinter在画布上显示图像,它总是blin
  7. android--翻译混淆日志(retrace)
  8. 东北狼仙-织梦仿站获取网站的iconfont字体图标字体方法
  9. [2015-06-10 20:53:50 - Android SDK] Error when loading the SDK:
  10. 【MySQL】如何使用MySQL锁(全局锁、表级锁、行级锁)?