Tessellation Shader
Download
Report
Transcript Tessellation Shader
Tessellation Shader
提纲
•
•
•
•
细分(tessellation)的作用
细分硬件的历史
示例程序
在自己程序中的应用
细分的作用
• 用来增加mesh细节的一种技术
• 通过将mesh上的多边形分割成更小的多边
形实现
• 如果需要,可以移动生成的新顶点,使
mesh更好地逼近物体的实际形状
细分的作用
• 通常用于离线绘制软件,用于增加模型的
细节
• 也用于实时绘制的预处理阶段
• 在预处理阶段细分,然后将细分后的模型
用于实时绘制的问题:即使最新的显卡也
没有足够的带宽和显存去处理如此大量的
数据
• 将细分功能集成到GPU可以解决上述大部分
问题
细分硬件的历史
•
•
•
•
Shade model 5.0
OpenGL 4.0
DirectX 11
已经有很长的历史
细分硬件的历史
• ATI Radeon 8500 2001年
• TruForm
• 通过GL_ATI_pn_triangles扩展访问
TruForm
• 固定的功能
• 选项:细分等级
• 选项:细分之后如何插值生成顶点位置和
法向
• 主要缺点:不可编程,displacement
mapping之类的功能无法实现
TruForm
• 并不被开发者看好
– 给美工带来额外负担
– 缺乏编程灵活性
• 没有成为OpenGL或DirectX标准
• 缺乏其他厂商的支持
TruForm之后
• Matrox
• ATI Radeon 9700
Geometry Shader
•
•
•
•
Shader Model 4.0
位于vertex shader之后,图元装配之前
作用于整个图元
输入和输出的图元类型不一定相同
Geometry Shader
• 可以增加几何信息,可以插值定点的属性
• 给开发者提供了很大的编程空间
• 很多人使用geometry shader完成细分功能
Geometry Shader不适合于细分的原因
• 和早期的GPU功能相比,它是一个革命性的
功能
• 与现有的GPU架构有较大区别
• 原有的硬件:输入输出数量固定,便于创
建一个同步的流水线架构使得计算单元在
大多数时间都是繁忙的
• Geometry shader:违反了上述原则
Geometry Shader不适合于细分的原因
• 解决方法:需要有一个缓存存放还没有来
得及被流水线下面的部分消耗的数据
• AMD:引入一个新的缓存,专门用来存放
geometry shader发射出来的图元
• NVIDIA:限制geometry shader的并发数量,
如果用于细分,会严重影响速度
• 另一个问题:图元的生成是在单个shader当
中循环地生成的,对GPU这种高度并行的架
构来说是个巨大的浪费。
Geometry Shader不适合于细分的原因
• Geometry shader的输入和输出图元相等时
可以达到最高性能(三角形->三角形)
• 结论:Geometry shader不适于细分
Radeon HD2000系列的细分功能
• 成功的细分硬件
• Xbox 360和PC的Radeon HD2000 GPU上
• 与Radeon 8500类似的固定功能,但是附加
一些了可编程的功能
• 这些功能通过
GL_AMD_vertex_shader_tessellator扩展访问
• 没有进入OpenGL或DirectX标准
• 缺乏NVIDIA的支持
Radeon HD2000系列的tessellation
• GL_AMD_vertex_shader_tessellator扩展将vertex
shader变为一个tessellation evaluation shader
Radeon HD2000系列的tessellation
• transform feedback
Tessellation shader
• Shader model 5.0
• OpenGL 4.0 DirectX 11
• 两个新的shader:
– tessellation control shader (hull shader)
– tessellation evaluation shader (domain shader)
示例程序
基础知识
• Tessellation作用于一种新的OpenGL图元:
patch
• Patch:一个顶点序列
• void glPatchParameteri(GLenum pname, GLint
value);
• glPatchParameteri(GL_PATCH_VERTICES, 3);
Vertex Shader
• in vec4 Position;
• out vec3 vPosition;
• void main()
• {
vPosition = Position.xyz;
• }
Tessellation Control Shader作用
• 生成顶点列表,传递给tessellator
• 通过 gl_TessLevelInner 和gl_TessLevelOuter,
制定细分的等级
Tessellation Control Shader
•
•
•
•
•
layout(vertices = 3) out;
in vec3 vPosition[];
out vec3 tcPosition[];
uniform float TessLevelInner;
uniform float TessLevelOuter;
•
#define ID gl_InvocationID
•
•
•
•
•
•
•
•
•
•
•
void main()
{
tcPosition[ID]=vPosition[ID];
if (ID == 0)
{
glTessLevelInner[0] = TessLevelInner;
glTessLevelOuter[0] = TessLevelOuter;
glTessLevelOuter[1] = TessLevelOuter;
glTessLevelOuter[2] = TessLevelOuter;
}
}
细分等级的控制
Inner和Outer的作用
Tessellation Evaluation Shader的作用
• 计算由tessellator生成的新顶点的坐标等属
性
重心坐标
Tessellation Evaluation Shader
•
•
•
•
•
•
layout(triangles, equal_spacing, cw) in;
in vec3 tcPosition[];
out vec3 tePosition;
out vec3 tePatchDistance;
uniform mat4 Projection;
uniform mat4 Modelview;
• void main()
• {
•
vec3 p0 = gl_TessCoord.x * tcPosition[0];
•
vec3 p1 = gl_TessCoord.y * tcPosition[1];
•
vec3 p2 = gl_TessCoord.z * tcPosition[2];
•
tePatchDistance = gl_TessCoord;
•
tePosition = normalize(p0 + p1 + p2);
•
gl_Position = Projection * Modelview * vec4(tePosition, 1);
• }
Geometry Shader
•
•
•
•
•
•
•
•
•
uniform mat4 Modelview;
uniform mat3 NormalMatrix;
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec3 tePosition[3];
in vec3 tePatchDistance[3];
out vec3 gFacetNormal;
out vec3 gPatchDistance;
out vec3 gTriDistance;
•
•
•
•
•
Geometry Shader
void main()
{
vec3 A = tePosition[2] – tePosition[0];
vec3 B = tePosition[1] – tePosition[0];
gFaceNormal = NormalMatrix * normalize(cross(A, B));
•
•
•
gPatchDistance = tePatchDistance[0];
gTriDistance = vec3(1, 0, 0);
gl_Position = gl_in[0].gl_Position; EmitVertex();
•
•
•
gPatchDistance = tePatchDistance[1];
gTriDistance = vec3(0, 1, 0);
gl_Position = gl_in[1].gl_Position; EmitVertex();
•
•
•
gPatchDistance = tePatchDistance[2];
gTriDistance = vec3(0, 0, 1);
gl_Position = gl_in[2].gl_Position; EmitVertex();
•
•
EndPrimitive();
}
Fragment Shader
•
•
•
•
•
•
•
•
out vec4 FragColor;
in vec3 gFacetNormal;
in vec3 gTriDistance;
in vec3 gPatchDistance;
in float gPrimitive;
uniform vec3 LightPosition;
uniform vec3 DiffuseMaterial;
uniform vec3 AmbientMaterial;
• float amplify(float d, float scale, float offset)
• {
•
d = scale * d + offset;
•
d = clamp(d, 0, 1);
•
d = 1 – exp2(-2 * d * d);
•
return d;
• }
Fragment Shader
• void main()
• {
•
vec3 N = normalize(gFacetNormal);
•
vec3 L = LightPosition;
•
float df = abs(dot(N, L));
•
vec3 color = AmbientMaterial + df * DiffuseMaterial;
•
float d1 = min(min(gTriDistance.x, gTriDistance.y),
gTriDistance.z);
•
float d2 = min(min(gPatchDistance.x, gPatchDistance.y),
gPatchDistance.z);
•
color = amplify(d1, 40, -0.5) * amplify(d2, 60, -0.5) * color;
•
• }
FragColor = vec4(color, 1.0);
结果
在自己程序中的应用
• 使用CUDA计算出Bezier曲面片的控制顶点
• 使用CUDA在裁剪Bezier曲面片的参数域上采
样,计算采样点的Bezier 曲面片值
• 使用OpenGL绘制三角面片
在自己程序中的应用
• 优点
– 无需手动生成顶点之间的连接信息
• 缺点
– shader无法访问CUDA资源
– 需要将第一步的结果放入一个OpenGL纹理
– CUDA无法直接对一个OpenGL纹理进行操作
– 将CUDA的计算结果拷贝到一个OpenGL纹理中
(device to device)