OpenGL 细分控制着色器执行次数

Tessellation Control Shader

细分控制着色器执行模式与大多数其他着色器阶段不同;它与计算着色器最相似。与几何着色器每个调用都可以输出多个图元不同,每个细分控制着色器调用只负责生成输出面片中的单个顶点。

对于渲染期间提供的每个面片,将执行n次细分控制着色器调用,其中n是输出面片中的顶点数。因此,如果一个绘制命令绘制了20个面片,并且每个输出有4个顶点,那么总共将有80个单独的细分控制着色器调用。

为同一面片提供数据的不同调用是相互连接的。这些调用都共享它们的输出值。它们可以读取同一面片的其他调用写入的输出值。但是为了做到这一点,他们必须使用同步机制(barrier)来确保细分控制着色器的所有其他调用至少已经执行了写入。

因此,细分控制着色器不同调用可以共享数据并彼此通信。

输出面片的顶点数量可以通过布局限定符(layout)来设置,也即设置了控制着色器执行的次数:

layout(vertices = patch_size) out;

patch_size 的大小不是必须与输入面片顶点的大小(glPatchParameteri(GL_PATCH_VERTICES, n))匹配。

细分控制着色器的输出变量直接传递到细分计算着色器,而不需要任何形式的插值(这是细分计算着色器的主要工作)。这些可以是逐顶点输出或逐面片输出。

下面来测试下执行的次数:

// 创建原子计数器缓存
glGenBuffers(1, &atomic_counter_buffer);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomic_counter_buffer);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_READ);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomic_counter_buffer);
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomic_counter_buffer);
GLuint*  data = (GLuint *)glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY);
data[0] = 0;
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);

//设置输入面片的顶点数
glPatchParameteri(GL_PATCH_VERTICES, 3);
//绘制六个顶点
glDrawArrays(GL_PATCHES, 0, 6);
//输出执行次数
data = (GLuint *)glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY);
cout << "invocations:" << *data << endl;		
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);

逐顶点输出:


//顶点着色器
#version 440 core

layout(location = 0) in vec4 VsInPos;
layout(location = 1) in vec4 VsInColor;

out vec4 color;
out vec4 pos;
void main()
{
	gl_Position = VsInPos;
	color = VsInColor;
}

//细分控制着色器
#version 440 core
//输出顶点数为3
layout(vertices = 3) out;
layout (binding = 0, offset = 0) uniform atomic_uint TessCoord;

in vec4 color[];

out	vec4 TCcolor[];

void main()
{
	atomicCounterIncrement(TessCoord);

	gl_TessLevelInner[0] = 2.0;

	gl_TessLevelOuter[0] = 2.0;
	gl_TessLevelOuter[1] = 2.0;
	gl_TessLevelOuter[2] = 2.0;

	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
	TCcolor[gl_InvocationID] = color[gl_InvocationID];		
}

//细分计算着色器
#version 440 core

layout(triangles, equal_spacing, cw) in;

in vec4 TCcolor[]; 
    
flat out vec4 color;
 
void main()
{
	float u = gl_TessCoord.x;
	float v = gl_TessCoord.y;
	float w = gl_TessCoord.z;
	
	gl_Position = u * gl_in[0].gl_Position + v * gl_in[1].gl_Position + w * gl_in[2].gl_Position;	
	color = TCcolor[0]*u + TCcolor[1]*v +TCcolor[2]*w;
}

OpenGL 细分控制着色器执行次数

逐面片输出:

//顶点着色器
#version 440 core

layout(location = 0) in vec4 VsInPos;
layout(location = 1) in vec4 VsInColor;

out vec4 color;
out vec4 pos;
void main()
{
	pos = VsInPos;
	color = VsInColor;
}


//细分控制着色器
#version 440 core
//输出顶点数为1
layout(vertices = 1) out;
layout (binding = 0, offset = 0) uniform atomic_uint TessCoord;

in vec4 color[];
in vec4 pos[];

struct OutputPatch
{
	//必须指定数组大小
	vec4 TCpos[3];
	vec4 TCcolor[3];
};
out patch OutputPatch oPatch;       

void main()
{
	atomicCounterIncrement(TessCoord);
	
	gl_TessLevelInner[0] = 2.0;

	gl_TessLevelOuter[0] = 2.0;
	gl_TessLevelOuter[1] = 2.0;
	gl_TessLevelOuter[2] = 2.0;

	for(int i=0;i<3;i++)
	{
		oPatch.TCpos[i] = pos[i];
		oPatch.TCcolor[i] = color[i];	
	}	
}


//细分计算着色器
#version 440 core

layout(triangles, equal_spacing, cw) in;

struct OutputPatch
{
	vec4 TCpos[3];
	vec4 TCcolor[3];
};

in patch OutputPatch oPatch;           
flat out vec4 color;
 
void main()
{
	float u = gl_TessCoord.x;
	float v = gl_TessCoord.y;
	float w = gl_TessCoord.z;
	
	gl_Position = u * oPatch.TCpos[0] + v * oPatch.TCpos[1] + w * oPatch.TCpos[2];	
	color = oPatch.TCcolor[0]*u + oPatch.TCcolor[1]*v +oPatch.TCcolor[2]*w;
}

OpenGL 细分控制着色器执行次数

上一篇:OpenGL学习记录(6)顶点着色器和片段着色器


下一篇:shader之双色渐变(cesium)