OpenGL - Tessellation Shader 【转】
http://blog.sina.com.cn/s/blog_8c7d49f20102v4qm.html
Patch is just an ordered list of vertices (在tessellation shader里面比较重要的概念就是这个patch,patch是一系列的顶点,OpenGL规定patch的vertex数量必须至少大于等于3)
The tessellation process doesn’t operate on OpenGL’s classic geometric primitives: points, lines, and triangles, but uses a new primitive called a patch (Tessellation shader就是针对patch来进行处理的而并非点,县,三角形)
Patch – are processed by all of active shading stage in the pipeline (patch可被所有的shader处理)
Two shading stages of Tessellation shading:
1. Tessellation Control Shader (optional)
In tessellation control shader, gl_PatchVerticesIn provides the number of elements in gl_in (gl_in 用于在tessellation control shader里面访问传进的来patch里面的顶点)
gl_out 用于控制patch里面的vertex从tessellation control shader输出后的属性
gl_InvocationID is used to access the specific vertex of a patch (gl_InvocationID 用于访问传入patch里的特定顶点)
Layout (vertices = *) out; (用于指定输出的patch里面有多少个顶点)
gl_TessLevelInner
Specify how the interior of the domain is subdivided and stored in
a two element array named gl_TessLevelInner(指定多边形内部如何细分)
gl_TessLevelOuter:
Control how the perimeter of the domain is subdivided, and is
stored in an implicitly declared four-element array named
gl_TessLevelOuter(指定多边形边界上的边被如何细分)
gl_TessLevelInner & gl_TessLevelOuter
根据多边形内部区域的类型会有不同的分割法
Tessellation Evaluation Shader (optional)
The TES is executed on all
generated domain
locations.Positions each of the
vertices in the final mesh (TES是针对从tessellation control shader
里面通过细分生成的顶点来进行运算,通过gl_in和gl_VocationID来访问我们传入的patch的一系列顶点信息,结合gl_TessCoord访问我们生成的新顶点的纹理信息来计算新的坐标位置,从而实现细分多边形的效果)
layout (quads, equal_spacing, ccw) in;
(指定新生成的多边形类型等信息)
glPatchParameteri() -- 告诉程序我们定义多少个顶点为一个patch
barrier() – .....
If you have additional per-vertex attribute values, either for
input or output, these need to be declared as either in or out
arrays in your tessellation control shader (需要传入TCS额外的顶点信息,需要定义额外in
& out array)
glPatchParameterfv() -- can be used to set the inner and
outer-tessellation levels(可以用于指定inner和outer的数值,当然我们也可以在tessellation
control shader里面通过gl_TessLevelInner &
gl_TessLevelOuter直接指定)
三中不同类型的domain -- 会决定我们inner和outer的具体含义:
Quad Tessellation:
…..
Isoline Tessellation:
Use only two of the outer-tessellation levels to determine the
amount of subdivision
…..
Triangle Tessellation:
Triangular domains use barycentric coordinates to specify their
Tessellation coordinates
…..
最终渲染效果:
- Tessellation Shader" title="OpenGL - Tessellation Shader" height="291" width="452">
- Tessellation Shader" title="OpenGL - Tessellation Shader" height="318" width="448">
- Tessellation Shader" title="OpenGL - Tessellation Shader" height="291" width="455">
- Tessellation Shader" title="OpenGL - Tessellation Shader" height="298" width="444">
Main.cpp Source Code below:
#include
#include
#include
// TODO: 在此处引用程序需要的其他头文件
#include
#include "vgl.h"
#include "mat.h"
#include "LoadShaders.h"
#include "Shapes/Teapot.h"
using namespace std;
GLuint PM; // Projection
matrix
GLuint
MVM;
// Model view matrix
GLuint InnerL; // Inner
tessellation paramter
GLuint OuterL; // Outer
tessellation paramter
GLfloat Inner = 1.0;
GLfloat Outer = 1.0;
#define SQUARE_VERTEX_NUMBER 4
//----------------------------------------------------------------------------
void init( void )
{
//create
shader and link program first
ShaderInfo
shaders[] = {
{
GL_VERTEX_SHADER,
"square.vert" },
{
GL_TESS_CONTROL_SHADER,
"square.cont" },
{
GL_TESS_EVALUATION_SHADER, "square.eval" },
{
GL_FRAGMENT_SHADER,
"square.frag" },
{ GL_NONE,
NULL }
};
//Shader
program
GLuint
program;
//load
shaders
program =
LoadShaders(shaders);
//link
shader program and use it
glUseProgram(program);
//vertex
array
GLuint
VA;
glGenVertexArrays(1, &VA);
glBindVertexArray(VA);
//Vertex
buffer
GLuint
VB;
glGenBuffers(1, &VB);
glBindBuffer(GL_ARRAY_BUFFER, VB);
//define
square vertex data
const
GLfloat square_vertex_data[SQUARE_VERTEX_NUMBER][2] = {
{ 1.0, 1.0
},
{ -1.0,
1.0},
{ -1.0,
-1.0},
{ 1.0,
-1.0}
};
//vertex
buffer data
glBufferData(GL_ARRAY_BUFFER, sizeof(square_vertex_data),
square_vertex_data, GL_STATIC_DRAW);
//Obtain
vertex position in program
GLint
vPostionIndex = glGetAttribLocation(program, "vPosition");
//Enable
vertex attribute
glEnableVertexAttribArray( vPostionIndex );
//define an
array of generic vertex attribute data for shader
(让shader知道怎么去读取我们传入的vertex 信息)
glVertexAttribPointer(vPostionIndex, 2, GL_FLOAT, GL_FALSE, 0,
BUFFER_OFFSET(0));
//Obtain
uniform variable of program
PM =
glGetUniformLocation(program, "PJ");
MVM =
glGetUniformLocation(program, "MV");
InnerL =
glGetUniformLocation(program, "inner");
OuterL =
glGetUniformLocation(program, "outer");
//Set some
default value for uniform variable
glUniform1f(InnerL, Inner);
glUniform1f(OuterL, Outer);
mat4 modelview = Translate( 0.0, 0.0, -2.0 )
* RotateX(
-50.0 );
glUniformMatrix4fv( MVM, 1, GL_TRUE, modelview );
//Define how
many vertices composed one patch (定义多少个vertices定义一个patch)
glPatchParameteri(GL_PATCH_VERTICES, 4);
//Enable
some relative setting
glEnable(GL_DEPTH_TEST);
glClearColor( 0.0, 0.0, 0.0, 1.0 );
}
//----------------------------------------------------------------------------
void display( void )
{
glClear(
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glUniform1f(InnerL, Inner);
glUniform1f(OuterL, Outer);
glDrawArrays(GL_PATCHES, 0, SQUARE_VERTEX_NUMBER);
glutSwapBuffers();
}
//----------------------------------------------------------------------------
void reshape( int width, int height )
{
glViewport(
0, 0, width, height );
GLfloat aspect = GLfloat(width)/height;
mat4 projection = Perspective( 60.0, aspect, 1, 3
);
glUniformMatrix4fv( PM, 1, GL_TRUE, projection );
glutPostRedisplay();
}
//----------------------------------------------------------------------------
void keyboard( unsigned char key, int x, int y )
{
switch ( key
) {
case 'q':
case 'Q': case 033 :
exit(
EXIT_SUCCESS );
break;
case
'i':
Inner--;
if ( Inner
< 1.0 ) Inner = 1.0;
glUniform1f(
InnerL, Inner );
break;
case
'I':
Inner++;
if ( Inner
> 64 ) Inner = 64.0;
glUniform1f(
InnerL, Inner );
break;
case
'o':
Outer--;
if ( Outer
< 1.0 ) Outer = 1.0;
glUniform1f(
OuterL, Outer );
break;
case
'O':
Outer++;
if ( Outer
> 64 ) Outer = 64.0;
glUniform1f(
OuterL, Outer );
break;
case
'r':
Inner =
1.0;
Outer =
1.0;
glUniform1f(
InnerL, Inner );
glUniform1f(
OuterL, Outer );
break;
case 'm':
{
static
GLenum mode = GL_FILL;
mode = (
mode == GL_FILL ? GL_LINE : GL_FILL );
glPolygonMode( GL_FRONT_AND_BACK, mode );
} break;
}
glutPostRedisplay();
}
//----------------------------------------------------------------------------
int main( int argc, char *argv[] )
{
glutInit(
&argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 512, 512 );
glutInitContextVersion( 3, 2 );
glutInitContextProfile( GLUT_CORE_PROFILE );
glutCreateWindow( "teapot" );
glewExperimental =
GL_TRUE;
//注意这里有个坑 --
这一句很关键,不加这一句gl_GenVertexArray()会报错,好像说是GLEW对openGL的core
context有一些问题
GLenum error
= glewInit();
if( error !=
GLEW_OK )
{
cout<<"glewInit failed, aborting"<<endl;
}
if (
GLEW_ARB_vertex_array_object == NULL )
{
cout<<"GLEW_ARB_vertex_array_object =
NULL"<<endl;
}
cout<<"Error info:"<<glGetError()<<endl;
init();
glutDisplayFunc( display );
glutReshapeFunc( reshape );
glutKeyboardFunc( keyboard );
glutMainLoop();
return
0;
}
square.vert source code below:
#version 400 core
in vec4 vPosition;
void main()
{
//gl_Position is used to access the vertex position that is input
from application
gl_Position
= vPosition;
}
square.cont source code below:
#version 400 core
//The main purpose of tessellation control shader is:
//Generate the tessellation output patch vertices that are passed
to the tessellation
//evaluation shader, as well as update any per-vertex
//Define how many vertices will be used as one patch
layout (vertices = 4) out;
//uniform type is used to define the variable that can be used to
communicate between shader and application
uniform float inner;
uniform float outer;
void main()
{
//gl_TessLevelInner is used to define:
//how the
interior of the domain is subdivided and stored in a two element
array named
gl_TessLevelInner[0] = inner;
gl_TessLevelInner[1] = inner;
//gl_TessLevelOuter is used to define:
//how the
perimeter of the domain is subdivided, and is stored in an
//implicitly
declared four-element array
gl_TessLevelOuter[0] = outer;
gl_TessLevelOuter[1] = outer;
gl_TessLevelOuter[2] = outer;
gl_TessLevelOuter[3] = outer;
//gl_in is
used to access the number of elements that are define by
glPatchParameteri()
//glPatchParameteri() define how many vertices as a patch
//gl_out is
used to access the output vertex position of tessellation control
shader
//gl_in
vertex shader structure below:
//in
gl_PerVertex {
//
vec4
gl_Position;
//
float
gl_PointSize;
//
float
gl_ClipDistance[]
//}
gl_in[gl_PatchVerticesIn];
//gl_out
vertex shader structure is similar to gl_in structure
//gl_InvocationID is used to access the specific vertex of a
patch
gl_out[gl_InvocationID].gl_Position =
gl_in[gl_InvocationID].gl_Position;
}
square.eval source code below:
#version 400 core
//The main purpose of tessellation evaluation shader is:
//configure the primitive generator, which is done using a layout
directive
//Specifying the face winding for generated primitives
//(the order the vertices are issued determines the facedness of
the primitive)
layout (quads, equal_spacing, ccw) in;
//The TES is executed on all generated domain locations.
//The bound tessellation evaluation shader is
//executed one for each tessellation coordinate that the primitive
generator
//Tessellation Shaders emits, and is responsible for determining
the position
//of the vertex derived from the tessellation coordinate.
uniform mat4 PJ;
uniform mat4 MV;
#define M_PI
3.14159265358979323846
//----------------------------------------------------------------------------
float Hanning( vec2 p )
{
p -= 0.5; //
map unit square to [-.5, .5]
float r =
length( p );
r = cos(
M_PI * r / 2.0 );
r *=
r;
return
r;
}
void main()
{
//gl_TessCoord is used to access the Tessellation coordinates that
are
//generated
by tessellation control shader
float u =
gl_TessCoord.x;
float v =
gl_TessCoord.y;
//use
Tessellation coordinates to calculate position for new vertex
that
//is
generated by tessellation control shader
#define
p(i) gl_in[i].gl_Position
vec4 pos =
v*(u*p(0) + (1-u)*p(1)) + (1-v)*(u*p(3) + (1-u)*p(2));
pos.z =
Hanning( gl_TessCoord.xy );
gl_Position
= PJ * MV * pos;
}
square.frag source code below:
#version 400 core
out vec4 fColor;
void main()
{
fColor = (1
- gl_FragCoord.z) * vec4( 1.0, 0.0, 0.0, 1.0 );
}
总结:
tessellation shader是可选的shader,不是必须的
tessellation shader与vertex shader不一样,tessellation
shader是针对patch(一系列顶点)来处理而不是一个顶点 (因为tessellation
shader需要通过传入的patch(一系列顶点)来计算新顶点的位置信息)
tessellation control shader负责对patch的细分设定
tessellation evaluation
shader负责对TCS细分出来的顶点进行位置等信息运算从而实现LOD(level of detail --
根据与camera的距离不同而细分程度不同)等效果
Bezier曲线在这里是一种细分后位置的计算方法来实现曲面的平滑效果
tessellation shader有个重要的应用就是LOD(Level of
Detail),通过在判断物体与视线的距离来设定tessellation control里面的factor
level从而实现近细分多,远细分少的效果
还有一个应用叫displacement mapping,在tessellation evaluation
shader里面通过tessellation coordinate的值来映射纹理(sample a texture)
OpenGL - Tessellation Shader 【转】的更多相关文章
- OpenGL 4.0的Tessellation Shader(细分曲面着色器)
细分曲面着色器(Tessellation Shader)处于顶点着色器阶段的下一个阶段,我们可以看以下链接的OpenGL渲染流水线的图:https://www.opengl.org/wiki/Rend ...
- Modern OpenGL用Shader拾取VBO内单一图元的思路和实现
Modern OpenGL用Shader拾取VBO内单一图元的思路和实现 什么意思? 拾取 最简单的理解拾取的方式大概是到(http://www.yakergong.net/nehe/course/t ...
- Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(2)
Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(2) 上一篇里介绍了Color-Coded Picking的思路和最基本的实现.在处理GL_POINTS时已经没有问题,但是处 ...
- Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(3)
Modern OpenGL用Shader拾取VBO内单一图元的思路和实现(3) 到上一篇为止,拾取一个VBO里的单个图元的问题已经彻底解决了.那么来看下一个问题:一个场景里可能会有多个VBO,此时每个 ...
- OpenGL Compute Shader靠谱例子及读取二进制Shader,SPIR-V
学OpenGL以来一直苦恼没有像DX那样可以读取二进制Shader使用的方法,除去有时不想公开自己写的牛逼Shader的心理(虽然目前还从没写过什么牛逼的Shader), 主要是不用现场编译,加快读取 ...
- 【OpenGL】Shader实例分析(七)- 雪花飘落效果
转发请保持地址:http://blog.csdn.net/stalendp/article/details/40624603 研究了一个雪花飘落效果.感觉挺不错的.分享给大家,效果例如以下: 代码例如 ...
- OpenGL中shader使用
学了接近一个月的OpenGL,最终要排上用场了...好吧,就从学到的shader(着色器)开刀吧. 先简单的介绍shader,shader事实上是显卡的功能,就是利用显卡的GPU去做图像处理的工作,而 ...
- OpenGL中shader读取实现
1.需要shader在OpenGL中工作,必须经过如下过程 2.代码实现 /********** * loadshader.h **********/ #pragma once #define _CR ...
- OpenGL之shader着色器的应用,三色渐变的三角形
学习自: https://learnopengl-cn.github.io/01%20Getting%20started/05%20Shaders/#_7 首先放一张效果图: 本次教程,将着色器单独定 ...
随机推荐
- [automator篇][9] 列表,找孩子
private boolean ClickByCollInfo(int CLICK, String classname, String id, String text) { UiSelector ui ...
- Linux删除非空目录的方法
rmdir 无法删除非空目录. rm -rf 可以递归,强制,删除目录
- 九度oj 题目1513:二进制中1的个数
题目描述: 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 输入: 输入可能包含多个测试样例. 对于每个输入文件,第一行输入一个整数T,代表测试样例的数量.对于每个测试样例输入为一个 ...
- 【bzoj2150】部落战争 有上下界最小流
题目描述 lanzerb的部落在A国的上部,他们不满天寒地冻的环境,于是准备向A国的下部征战来获得更大的领土. A国是一个M*N的矩阵,其中某些地方是城镇,某些地方是高山深涧无人居住.lanzerb把 ...
- 【Luogu】P2634聪聪可可(树形DP)
题目链接 水题,时限放得非常宽,暴力DP随便套上一波register就能卡过去. 唯一的遗憾是5A. 树形DP,s[i][j]表示以i为根的子树里距i的距离%3=j的点数,f[i]表示i为根的子树内一 ...
- NBOJv2——Problem 1037: Wormhole(map邻接表+优先队列SPFA)
Problem 1037: Wormhole Time Limits: 5000 MS Memory Limits: 200000 KB 64-bit interger IO format: ...
- BZOJ1856 [SCOI2010]生成字符串 【组合数】
题目 lxhgww最近接到了一个生成字符串的任务,任务需要他把n个1和m个0组成字符串,但是任务还要求在组成的字符串中,在任意的前k个字符中,1的个数不能少于0的个数.现在lxhgww想要知道满足要求 ...
- LibreOJ2097 - 「CQOI2015」任务查询系统
Portal Description 给出\(n(n\leq10^5)\)个任务,和总时间范围\(m(m\leq10^5)\).每个任务有开始/结束时间\(s_i,e_i(1\leq s_i \leq ...
- POJ3071 Football 【概率dp】
题目 Consider a single-elimination football tournament involving 2n teams, denoted 1, 2, -, 2n. In eac ...
- javascript之进阶
一 模态框 1 什么是模态框 模态框(Modal)是覆盖在父窗体上的子窗体.指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应.如单击[确定]或[取消]按钮等将该对话框关闭. 2 ...