曲面细分着色器学习记录
曲面细分着色器学习记录
前言:
今天终于走通了Catlike大佬的曲面细分着色器教程,感慨一番,自己的学习之路还很漫长呢
今天的博客内容只是简单的记录一下Catlike大佬的教程
先上个链接:Catlike的曲面细分教程
什么是曲面细分
学习过建模的朋友们都一定知道曲面细分,在Blender中也有曲面细分修改器工具,用来细分图元,帮助我们获得更细腻的模型表面
闫令琪在Games101中的Geometry章节中也降到了曲面细分的原理(Loop细分和Catmull-Clark细分,我回顾了一下感觉和今天的原理不太一样)
渲染管线中的曲面细分着色器
1. 渲染流水线
乐乐女神在《入门精要》中说明,曲面细分着色器处于几何阶段,并且可编程控制,同时这是一个可以选的shader
2. 输入与输出:
- 输入:patch以及三角形索引,patch就是多个顶点的集合,可以指定一个patch包含几个顶点
- 输出:细分之后的顶点
3. shader组成
在曲面细分着色器中,包含三个部分:
Hull shader
Tessellation
Domain shader
这三者中,Tessellation操作是计算机进行的,我们不可以操作,因此,我们需要配置的就是Hull shader
和Domain shader
Hull shader
:准备曲面细分的方法等基础数据,传递给Tessellation后进行细分操作
Dmain shader
:对细分后的点进行处理,将其从重心坐标转到相应的空间(可以转到模型空间、投影空间等等)
Hull shader
Hull shader的结构与vert 或 frag shader的结构明显不同,除了一个主要的方法外,还需要在前定义5个属性,用来说明Hull应如何准备数据。
属性说明:
1.[UNITY_domain("tri")]
:这个属性可以指定patch的类型,除了tri(三角形)之外,还包括quad、isoline。
2.[UNITY_outputcontrolpoints(3)]
:输出的控制点的数量,不一定与输入数量相同,也可以新增控制点。
3.[UNITY_outputtopology("triangle_cw")]
:输出拓扑结构。有三种:triangle_cw(顺时针)、trianglle_ccw(逆时针)、line(线段)。
4.[UNITY_partitioning("fractional_odd")]
:分割模式。有三种:integer、fractional_even、fractional_odd。说白了就是integer只可以整数分割,剩余两者可以小数分割,一般都用odd,分割更自然。
5.[UNITY_patchconstantfunc("patchEdgeFunction")]
:一个函数,patchEgdeFunction是教程里的函数名,这个函数需要在前面自行定义,用来说明细分中,边和图元里面的点内的细分数量。
6.[maxtessfactor(64.0f)]
:上面的代码里没写,但是有一位知乎大佬说明了,在这里补充以下。最大细分度,告知驱动程序shader用到的最大细分度,硬件可能会针对这个做出优化。Direct3D 11和OpenGL Core都至少支持64。
Patch Constant Function
这个函数指定了一个patch如何细分,每个patch只调用一次这个函数,而不是每个控制点调用一次。Patch Constant Function
与Hull shader
并行运行。
为了确定如何细分三角形,GPU使用四个细分因子,三角形的每条边都有一个因子,三角形内部也有一个因子,这两种细分因子都具有相应的语义。
因此,需要为这个细分因子创建一个结构体:
struct TessellationFactors
{float edge[3] : SV_TessFactor;float inside : SV_InsideTessFactor;
};
现在,我们可以定义Patch Constant Function
函数了:
TessellationFactors MyPatchConstantFunction (InputPatch<VertexData, 3> patch) {TessellationFactors f;f.edge[0] = 1;f.edge[1] = 1;f.edge[2] = 1;f.inside = 1;return f;
}
上述的代码中,MyPatchConstantFunction
是函数的名称,传入的数据是patch,在函数中定义了每条边以及三角形内部的细分因子,最后输出TessellationFactors
。这里的细分因子的参数只是暂时的,可以根据不同需求更改:
不同的Tessellation Factors计算:
1 . _Tessellation
:使用_Tessellation变量要求我们在shader中定义相应的Properties。此时,MyPatchConstantFunction
应如下:
TessellationFactors MyPatchConstantFunction (InputPatch<VertexData, 3> patch) {TessellationFactors f;f.edge[0] = _Tessellation;f.edge[1] = _Tessellation;f.edge[2] = _Tessellation;f.inside = _Tessellation;return f;
}
在这里,edge与inside上的细分因子是相同的,他们不同的时候,有着不同的效果,具体可以参照原文。
2 .使用观察空间中的距离设置相应的因子。因此,还需要定义一个设置edge上细分因子的函数,这个函数需要根据每个三角形点的参数进行设置(因为需要计算顶点与相机之间的距离)。因此,代码应该包含两部分:
float TessellationEdgeFactor(TessellationControlPoint cp0, TessellationControlPoint cp1){float3 p0 = mul(unity_ObjectToWorld, float4(cp0.vertex.xyz, 1)).xyz;float3 p1 = mul(unity_ObjectToWorld, float4(cp1.vertex.xyz, 1)).xyz;float edgeLength = distance(p0, p1);float3 edgeCenter = (p0 + p1) * 0.5;float viewDistance = distance(edgeCenter, _WorldSpaceCameraPos);return edgeLength * _ScreenParams.y / (_TessellationEdgeLength * viewDistance);
}
TessellationFactors patchEdgeFunction (InputPatch<TessellationControlPoint, 3> patch){TessellationFactors f;f.edge[0] = TessellationEdgeFactor(patch[1], patch[2]);f.edge[1] = TessellationEdgeFactor(patch[2], patch[0]);f.edge[2] = TessellationEdgeFactor(patch[0], patch[1]);f.inside = (f.edge[0] + f.edge[1] + f.edge[2]) / 3;return f;
}
由于上述的距离是在世界坐标中进行计算的,所以需要进行一个缩放,才能在屏幕中看到正确的效果。这里只乘以一个_ScreenParams.y
进行一个简化的缩放。
至此,一个完整的Hull shader应包含以下部分:
// 曲面细分因素
struct TessellationFactors
{float edge[3] : SV_TessFactor;float inside : SV_InsideTessFactor;
};struct TessellationControlPoint{float4 vertex : POSITION;float3 normal : NORMAL;float4 tangent : TANGENT;
};vertexOutput TessellationVertex (MyTessVertex v){return v;
}float TessellationEdgeFactor(TessellationControlPoint cp0, TessellationControlPoint cp1){float3 p0 = mul(unity_ObjectToWorld, float4(cp0.vertex.xyz, 1)).xyz;float3 p1 = mul(unity_ObjectToWorld, float4(cp1.vertex.xyz, 1)).xyz;float edgeLength = distance(p0, p1);float3 edgeCenter = (p0 + p1) * 0.5;float viewDistance = distance(edgeCenter, _WorldSpaceCameraPos);return edgeLength * _ScreenParams.y / (_TessellationEdgeLength * viewDistance);
}
TessellationFactors patchEdgeFunction (InputPatch<TessellationControlPoint, 3> patch){TessellationFactors f;f.edge[0] = TessellationEdgeFactor(patch[1], patch[2]);f.edge[1] = TessellationEdgeFactor(patch[2], patch[0]);f.edge[2] = TessellationEdgeFactor(patch[0], patch[1]);f.inside = (f.edge[0] + f.edge[1] + f.edge[2]) / 3;return f;
}[UNITY_domain("tri")]
[UNITY_outputcontrolpoints(3)]
[UNITY_outputtopology("triangle_cw")]
[UNITY_partitioning("fractional_odd")]
[UNITY_patchconstantfunc("patchEdgeFunction")]
TessellationControlPoint myHullProgram (InputPatch<TessellationControlPoint, 3> patch, uint id : SV_OutputControlPointID)
{return patch[id];
}
上述的代码中,有一个TessellationControlPoint
结构体,在原作者中的描述是说可能会产生语义上的错误,专门为曲面细分过程中的顶点进行一个INTERNALTESSPOS
语义的定义:
TessellationControlPoint MyTessellationVertexProgram (VertexData v) {TessellationControlPoint p;p.vertex = v.vertex;p.normal = v.normal;p.tangent = v.tangent;return p;
}
但是不知道为什么,我按照作者的意思却一直不能显示正确的结果,所以我还是使用原始的顶点的结构体。估计是平台兼容的问题?
Domain shader
已经完成了Hull shader,接下来就是定义Domain shader。
Tessellation阶段为我们提供了重心坐标,我们需要在Domain shader中将其转换导出正确空间下的顶点。
[UNITY_domain("tri")]
vertexOutput myDomainProgram(TessellationFactors factors,
OutputPatch<TessellationControlPoint, 3> patch,
float3 barycentricCoordinates : SV_DomainLocation)
{vertexOutput 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 TessellationVert(v);
}
完整代码如上,还是有几点需要注意:
- Domain shader前面仍然需要添加[UNITY_domain(“tri”)]
- Domain shader的输入包括:细分因子、patch数据、重心坐标
- shader内部的重心计算可以设置为一个宏,方便我们计算其他的信息,如顶点、法线、切线等
- 目前位置,我们没有进行任何将顶点转换到裁剪空间中的操作,原作者是将domain shader的计算结果返回到一个将顶点转换到裁剪空间中的shader,再进行空间变换。知乎大佬也是直接在domain shader中将顶点变换至裁剪空间,这里面在哪里变换选择很多。
- 还有一点是Hull shader的返回,似乎Hull shader已经计算好了所有的数据,各位大佬返回什么的都有。这里只返回了patch的id
参考:
1 . https://zhuanlan.zhihu.com/p/42550699
2 . https://catlikecoding.com/unity/tutorials/advanced-rendering/tessellation/
曲面细分着色器学习记录相关推荐
- Shader学习_曲面细分着色器
曲面细分 详细介绍 当然除了细分与简化之外,还有另外一种同属一类的操作叫做==曲面规则化(Mesh Regularization)==其所作的便是将三角面都变的尽可能相同,从而也达到提升模型效果的目的 ...
- 曲面细分着色器---细分二维四边形
openGL系列文章目录 文章目录 openGL系列文章目录 前言 一.曲面细分 二.细分二维四边形 参考 前言 术语Tessellation(镶嵌)是指一大类设计活动,通常是指在平坦的表面上,用各种 ...
- Shader入门---曲面细分着色器和几何着色器
Shader入门-曲面细分着色器和几何着色器 前记:学不可以停止-------------------------------mx 基础知识: 曲面细分着色器:可以将一个几何体细化为一个球体也能将一根 ...
- 曲面细分着色器与几何着色器
着色器执行顺序 顶点着色器->曲面细分着色器->几何着色器->片元着色器 曲面细分着色器细分后的顶点属于重心空间. 曲面细分着色器 应用:海浪.雪地等 与置换贴图结合:只使用法线贴图 ...
- UnityShader 曲面细分着色器 生成地形 高度贴图
什么是曲面细分着色器 如下图 曲面细分着色器比较官方定义:可以将一个几何体细化为一个球体也能将一根直线无限向曲线逼近 曲面细分着色器将复杂的曲面转换为简单的点,线,三角形等.它分为三部分:曲面细分 ...
- 曲面细分(subdivision)曲面细分着色器GPU的LOD
曲面细分是指将一个模型的面合理的分成更多小的面,从而提升模型精度,提高渲染效果 曲面简化是指将一个模型的面合理的合成更少的面,从而降低模型精度,为特定情形下提供使用(如LOD技术) .这一过程是可以在 ...
- unity曲面细分着色器详解
前言:本文翻译自catlikecoding上一篇十分详细的英文blog并修改了几处错误,逐行解释了如何在自己的shader中添加曲面细分支持,并给出了多种计算细分因子的方案以及它们的优缺点. 原文链 ...
- DirectX 12 曲面细分着色器笔记
曲面细分着色器 1. 背景 2. 曲面细分工作机制 2.1 Hull Shader(外壳着色器) 2.2 Tessellator(曲面细分器) 2.3 Domain Shader(域细分器) 3. 编 ...
- Unity初学Shadergraph创建着色器学习教程
MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 语言:英语+中英文字幕(根据原英文字幕机译更准确) |时长:51节课(4h 44m) |大小解压后:2.55 G ...
最新文章
- HDFS数据定时采集demo 简单
- 数据解析系统中需改进的几点
- activemq的使用场景
- java状态模式和策略模式_Java状态和策略设计模式之间的差异
- 虚拟同步发电机_一种光储型虚拟同步机介绍
- 56 - II. 数组中数字出现的次数 II
- 美团算法 SP | NLP 三面复盘
- 02-Go语言数据类型与变量
- win10-ubuntu-软件配置-开机root无密码-风扇转速调节
- MP3格式音频数据文件解析
- 今日头条信息流广告怎么做?(今日头条信息流广告费用解析)
- vue 项目实践 -ele 表单验证
- zblog mysql修改_手把手教修正zblog默认阅读量
- Microsoft自家的虚拟光驱 Virtual CD-ROM Control Panel for Wind
- trs 同步模版 栏目修改(高级)
- 网关是什么,一文带你快速入门腾讯技术工程
- 微信小程序助力社区便利店利润破百万
- 2006年安全软件全球纵览(转
- 十条网站盈利模式分析总结 1
- 如何快速查看将C反汇编的代码