当前位置: 首页 > news >正文

怎么简单做网站排名网站建设方法冫金手指排名26

怎么简单做网站排名,网站建设方法冫金手指排名26,外贸营销系统,网站制作书籍推荐目录 一、概念 1、图元 2、几何着色器 1、输入类型 2、输出类型 3、输出顶点数量最大值限制 二、使用几何着色器 三、应用举例——造几个房子 四、应用举例——爆破物体 1、获取法向量 2、显示法线 五、应用举例——细分三角形 六、应用举例——广告牌技术 一、概…目录 一、概念 1、图元 2、几何着色器 1、输入类型 2、输出类型 3、输出顶点数量最大值限制 二、使用几何着色器 三、应用举例——造几个房子 四、应用举例——爆破物体 1、获取法向量 2、显示法线 五、应用举例——细分三角形 六、应用举例——广告牌技术 一、概念 1、图元 再正式介绍几何着色器后续简称为GS之前我们先来搞清楚什么是图元。 在三维空间中一个图元指的是构成一个3D实体的顶点集合。例如空间中的一个点对应一个顶点一条线段对应两个顶点一个三角形对应三个顶点这些都是图元。 通常情况下图元为多边形对应的顶点而最简单的多边形即为三角形。DirectX使用三角形来构造其它的多边形例如两个三角形可以构成一个四边形。这是因为三角形的三个顶点一定是共面的可以提高渲染性能渲染非共面的顶点效率很低。通过这种组合三角形的方式可以获得更大更复杂的多边形和网格如下图为立方体图元与球体图元 除了使用三角形以外我们也可以使用一系列的点图元或者线段图元来组成一些复杂的图元。DirectX支持的基本图元类型Primitive Type有下面五种 Point ListLine ListLine StripTriangle ListTriangle Strip 假如在渲染管线的Input Assembler阶段拿到如下6个顶点数字代表对应顶点的顺序我们来看看不同的图元类型对应的绘制结果。 如果图元类型为Point List则每个顶点都被单独的作为一个点被绘制出来效果图和上图一样可以用它来模拟天空中的星星或者绘制由点构成的虚线等。 如果图元类型为Line List或者Line Strip则每两个顶点构成一个线段图元。它们的区别在于如果是Line List这些线段都是独立的而Line Strip的线段都是互相连接的如下图。Line List可以用来实现场景中雨水的效果而Line Strip可以用来绘制非闭合的多边形。 如果图元类型为Triangle List或者Triangle Strip则每三个顶点构成一个三角形图元。与Line类型的一样Triangle List的三角形都是独立的而Triangle Strip的三角形都是互相连接的如下图。使用Triangle List可以创建由不相交的片段构成的物体含有缝隙此外还常被用于创建带有锐利边缘并使用高洛德着色Gouraud shading的图元。3D场景中的大多数物体图元都是由Triangle Strip组成的这是因为用Triangle Strip构成的复杂的对象可以有效地节省内存和减少处理时间。 注Triangle Strip中第奇数个三角形和第偶数个三角形如果按顶点顺序绘制的话会导致三角形的绘制顺序相反。例如第一个三角形的顶点顺序是012三角形的绘制顺序是顺时针在DirectX中显示正面。第二个三角形的顶点顺序是123那么三角形的绘制顺序是逆时针显示背面。为了保证三角形的绘制顺序统一GPU内部会将所有偶数位三角形的后两个顶点顺序对调例如第二个三角形的顶点顺序变为132从而变成顺时针。 使用Triangle Strip也可以模拟Triangle List效果需要利用到面积为0的三角形被称为degenerate triangle。例如上面的例子中我们在第三个和第四个顶点之间新增两个顶点2, 3其坐标分别和2, 3相同构成顺序为0, 1, 2, 2, 3, 3, 4, 5八个顶点组成的Triangle Strip其绘制结果如下 其中△122△223△233△334都是面积为0的三角形变成了一条线段图中红色虚线但是该线段不会被绘制出来。因此上述Triangle Strip只能绘制出△012和△354两个独立的三角形。 从Direct3D 10开始除了Point List外的图元类型都新增了一个带有邻接关系Adjacency的版本 Line List AdjacencyLine Strip AdjacencyTriangle List AdjacencyTriangle Strip Adjacency 带有邻接关系的图元额外包含了一些环绕在图元周边的顶点其目的是为了提供更多的几何信息并且只能通过几何着色器可见常被用于silhouette detectionshadow volume extrusion等。 每个带有Adjacency的Line都需要额外2个顶点作邻接关系因此每个带有Adjacency的Line都对应4个顶点。Line List Adjacency与Line Strip Adjacency示意图如下新增两个顶点否则List中无法有两个完整的Line Adjacency图元 注虚线部分为与邻接点所构成的图元它们不会被实际渲染出来。在Strip中中间的线段同样有邻接点例如线段3,4的邻接点为2,5。 每个带有Adjacency的Triangle都需要额外3个顶点作邻接关系因此每个带有Adjacency的Triangle都对应6个顶点。Triangle List Adjacency与Triangle Strip Adjacency示意图如下为了好显示顶点重新搞了下 从顶点顺序中可以发现不管是List还是Strip下标为偶数的顶点都是非邻接三角形的顶点而下标为奇数的顶点都是邻接点。 总结对于pointlinetriangleline adjacencytriangle adjacency我们可以称之为基础图元然后利用list或strip的组成方式可以将这些基础图元组成更复杂的图元。这些复杂图元根据其基础图元和组成方式对应不同的图元类型例如Point ListLine StripTriangle List等等。 2、几何着色器 在顶点和片段着色器之间有一个可选的着色器叫做几何着色器(Geometry Shader)。几何着色器以一个或多个表示为一个单独基本图形primitive的顶点作为输入比如可以是一个点或者三角形。几何着色器在将这些顶点发送到下一个着色阶段之前可以将这些顶点转变为它认为合适的内容。几何着色器有意思的地方在于它可以把一个或多个顶点转变为完全不同的基本图形primitive从而生成比原来多得多的顶点。 从OpenGL 3.2开始支持几何着色器阶段并在OpenGL 4.0引入了一些新的特性。 与顶点着色器输入的都是单个顶点不同几何着色器的输入为单个基础图元。对于strip类型同样会被当作是一个个单独的基础图元完整的输入到GS中因此GS不需要去区分图元类型是line还是strip。例如四个顶点的triangle strip构成两个三角形会调用两次GS第一次按顺序传入下标为0,1,2的三个顶点第二次按顺序传入下标为1,3,2的三个顶点strip里第偶数位三角形的后两个顶点会自动对调。这种情况会产生额外的性能消耗因为一些图元共享的顶点会在GS中被多次处理。 在顶点着色器中不能新增或者删除顶点但是在几何着色器中我们可以新增和删除顶点来改变图元输入与输出的图元可以不一样从而实现一些特殊效果。GS的输出只可以是point listline strip和triangle strip但是我们可以通过一些方法来模拟line list以及triangle list后续介绍。 比如GS的输入为line我们可以通过新增顶点将其扩展成triangle strip进行输出。还可以把line中的某一个顶点变成point进行输出另个顶点被舍弃甚至根据一些条件都不输出两个顶点都被舍弃从而达到删除顶点的效果。 在只有顶点着色器和像素着色器的渲染管线中VS输出的顶点信息要在齐次裁剪空间下后续执行光栅化阶段包括视椎体剔除透视除法视口变换到屏幕空间图元映射到像素等操作最后进入到PS阶段。而如果我们启用了几何着色器那么VS输出的顶点信息会先进入到GS中。由于我们往往在模型空间下编写GS逻辑因此此时VS的输出不需要在齐次裁剪空间下变成了GS输出的顶点信息需要在齐次裁剪空间下然后GS输出的顶点信息执行光栅化操作最后进入到PS阶段。 几何着色器在实现一些特殊效果的时候例如广告牌技术动态粒子系统毛发系统Shadow Volume等可以提供很大的性能提升此外还常被用于实现可视化法线物体爆破等效果。下图为在Unity中利用几何着色器实现的广告牌效果 由于GS可以新增顶点以及改变图元的特性使得我们可以将一些操作放到GS中从而提升性能。拿广告牌的功能举例要使得广告牌始终对着Camera一种做法就是在CPU端每帧更新广告牌四个顶点的位置然后将这些顶点信息传递给GPU渲染。由于每帧要更新顶点信息所以这些顶点只能存放在upload heap中并且使用memcpy来将更新后的顶点信息拷贝到GPU Buffer中。当广告牌多时例如用其渲染大量的植被会造成不小的性能开销以及占用大量内存。而如果我们利用GS我们只需要在一开始将这些广告牌的中心点传递给GPU因为这些中心点位置是不会随着Camera变的因此可以放在default heap中从而提升性能并且由于此时一个广告牌只对应一个顶点信息也减少了内存的占用。然后每帧在GS中去新增广告牌的四个顶点并且根据Camera计算对应位置。在广告牌很多的情况下在GPU中做顶点信息的计算同样可以提升性能具体实现后面介绍。 当然了几何着色器也有对应的缺点当几何着色器输出的顶点信息过多时其性能会变得很差后续会介绍。 我们直接用一个例子深入了解一下 #version 330 core layout (points) in; layout (line_strip, max_vertices 2) out;void main() {gl_Position gl_in[0].gl_Position vec4(-0.1, 0.0, 0.0, 0.0);EmitVertex();gl_Position gl_in[0].gl_Position vec4(0.1, 0.0, 0.0, 0.0);EmitVertex();EndPrimitive(); } 1、输入类型 每个几何着色器开始位置我们需要声明输入的基本图形(primitive)类型这个输入是我们从顶点着色器中接收到的。我们在in关键字前面声明一个layout标识符。这个输入layout修饰符可以从一个顶点着色器接收以下基本图形值 基本图形描述points绘制GL_POINTS基本图形的时候1lines当绘制GL_LINES或GL_LINE_STRIP2时lines_adjacencyGL_LINES_ADJACENCY或GL_LINE_STRIP_ADJACENCY4trianglesGL_TRIANGLES, GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN3triangles_adjacencyGL_TRIANGLES_ADJACENCY或GL_TRIANGLE_STRIP_ADJACENCY6 这是我们能够给渲染函数的几乎所有的基本图形。如果我们选择以GL_TRIANGLES绘制顶点我们要把输入修饰符设置为triangles。括号里的数字代表一个基本图形所能包含的最少的顶点数。 不同基本图形下数组中顶点的下标对应关系如下图 如下图的Triangle Strip Adjacency第一次会依次给GS输入0, 1, 2, 6, 4, 3这6个顶点第二次会依次输入2, 5, 6, 8, 4, 0这6个顶点以此类推。 2、输出类型 当我们需要指定一个几何着色器所输出的基本图形类型时我们就在out关键字前面加一个layout修饰符。和输入layout标识符一样输出的layout标识符也可以接受以下基本图形值 pointsline_striptriangle_strip 使用这3个输出修饰符我们可以从输入的基本图形创建任何我们想要的形状。为了生成一个三角形我们定义一个triangle_strip作为输出然后输出3个顶点。 3、输出顶点数量最大值限制 在GS开头我们需要使用max_vertices 关键字来声明该GS单次调用可以输出的最大顶点数量VertexNum。每次调用时输出的顶点数量是可以变化的但是不能超出设定的最大数目。例如[max_vertices 4]代表每次调用可以输出0到4个顶点但是不能多于4个顶点。 max_vertices 值会直接决定几何着色器的运行速度出于性能的考虑maxvertexcount的值应该尽可能的小GS的性能和其输出的buffer大小成反比。 几何着色器同时希望我们设置一个它能输出的顶点数量的最大值如果你超出了这个数值OpenGL就会忽略剩下的顶点我们可以在out关键字的layout标识符上做这件事。在这个特殊的情况中我们将使用最大值为2个顶点来输出一个line_strip。 这种情况你会奇怪什么是线条一个线条是把多个点链接起来表示出一个连续的线它最少有两个点来组成。每个后一个点在前一个新渲染的点后面渲染你可以看看下面的图其中包含5个顶点 上面的着色器我们只能输出一个线段因为顶点的最大值设置为2。 为生成更有意义的结果我们需要某种方式从前一个着色阶段获得输出。GLSL为我们提供了一个内建变量它叫做gl_in它的内部看起来可能像这样 in gl_Vertex {vec4 gl_Position;float gl_PointSize;float gl_ClipDistance[]; } gl_in[]; 这里它被声明为一个接口块(interface block前面的教程已经讨论过详见Android OpenGL ES详解——高级GLSL-CSDN博客)它包含几个有意思的变量其中最有意思的是gl_Position它包含着和我们设置的顶点着色器的输出相似的向量。 要注意的是它被声明为一个数组因为大多数渲染基本图形由一个以上顶点组成几何着色器接收一个基本图形的所有顶点作为它的输入。几何着色器的输入参数为一个顶点数组。 使用从前一个顶点着色阶段的顶点数据我们就可以开始生成新的数据了这是通过2个几何着色器函数EmitVertex和EndPrimitive来完成的。几何着色器需要你去生成/输出至少一个你定义为输出的基本图形。在我们的例子里我们打算至少生成一个线条line strip基本图形。 void main() {gl_Position gl_in[0].gl_Position vec4(-0.1, 0.0, 0.0, 0.0);EmitVertex();gl_Position gl_in[0].gl_Position vec4(0.1, 0.0, 0.0, 0.0);EmitVertex();EndPrimitive(); } 每次我们调用EmitVertex当前设置到gl_Position的向量就会被添加到基本图形上。无论何时调用EndPrimitive所有为这个基本图形发射出去的顶点都将结合为一个特定的输出渲染基本图形。一个或多个EmitVertex函数调用后重复调用EndPrimitive就能生成多个基本图形。这个特殊的例子里发射了两个顶点它们被从顶点原来的位置平移了一段距离然后调用EndPrimitive将这两个顶点结合为一个单独的有两个顶点的线条。 现在你了解了几何着色器的工作方式你就可能猜出这个几何着色器做了什么。这个几何着色器接收一个基本图形——点作为它的输入使用输入点作为它的中心创建了一个水平线基本图形。如果我们渲染它结果就会像这样 并不是非常引人注目但是考虑到它的输出是使用下面的渲染命令生成的就很有意思了 glDrawArrays(GL_POINTS, 0, 4);这是个相对简单的例子它向你展示了我们如何使用几何着色器来动态地在运行时生成新的形状。本章的后面我们会讨论一些可以使用几何着色器获得有趣的效果但是现在我们将以创建一个简单的几何着色器开始。 二、使用几何着色器 为了展示几何着色器的使用我们将渲染一个简单的场景在场景中我们只绘制4个点这4个点在标准化设备坐标的z平面上。这些点的坐标是 GLfloat points[] {-0.5f, 0.5f, // 左上方0.5f, 0.5f, // 右上方0.5f, -0.5f, // 右下方-0.5f, -0.5f // 左下方 };顶点着色器只在z平面绘制点所以我们只需要一个基本顶点着色器 #version 330 core layout (location 0) in vec2 position;void main() {gl_Position vec4(position.x, position.y, 0.0f, 1.0f); } 我们会简单地为所有点输出绿色我们直接在片段着色器里进行硬编码 #version 330 core out vec4 color;void main() {color vec4(0.0f, 1.0f, 0.0f, 1.0f); }为点的顶点生成一个VAO和VBO然后使用glDrawArrays进行绘制 shader.Use(); glBindVertexArray(VAO); glDrawArrays(GL_POINTS, 0, 4); glBindVertexArray(0); 效果是黑色场景中有四个绿点虽然很难看到 但我们不是已经学到了所有内容了吗对现在我们将通过为场景添加一个几何着色器来为这个小场景增加点活力。 出于学习的目的我们将创建一个叫pass-through的几何着色器它用一个point基本图形作为它的输入并把它无修改地传pass到下一个着色器。 #version 330 core layout (points) in; layout (points, max_vertices 1) out;void main() {gl_Position gl_in[0].gl_Position;EmitVertex();EndPrimitive(); }现在这个几何着色器应该很容易理解了。它简单地将它接收到的输入的无修改的顶点位置发射出去然后生成一个point基本图形。 一个几何着色器需要像顶点和片段着色器一样被编译和链接但是这次我们将使用GL_GEOMETRY_SHADER作为着色器的类型来创建这个着色器 geometryShader glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(geometryShader, 1, gShaderCode, NULL); glCompileShader(geometryShader); ... glAttachShader(program, geometryShader); glLinkProgram(program);编译着色器的代码和顶点、片段着色器的基本一样。要记得检查编译和链接错误 如果你现在编译和运行就会看到和下面相似的结果 它和没用几何着色器一样我承认有点无聊但是事实上我们仍能绘制证明几何着色器工作了的点所以现在是时候来做点更有意思的事了 三、应用举例——造几个房子 绘制点和线没什么意思所以我们将在每个点上使用几何着色器绘制一个房子。我们可以通过把几何着色器的输出设置为triangle_strip来达到这个目的总共要绘制3个三角形两个用来组成方形和另表示一个屋顶。 在OpenGL中三角形带(triangle strip)绘制起来更高效因为它所使用的顶点更少。第一个三角形绘制完以后每个后续的顶点会生成一个毗连前一个三角形的新三角形每3个毗连的顶点都能构成一个三角形。如果我们有6个顶点它们以三角形带的方式组合起来那么我们会得到这些三角形1, 2, 3、2, 3, 4、3, 4, 5、4,5,6因此总共可以表示出4个三角形。一个三角形带至少要用3个顶点才行它能生曾N-2个三角形6个顶点我们就能创建6-24个三角形。下面的图片表达了这点 使用一个三角形带作为一个几何着色器的输出我们可以轻松创建房子的形状只要以正确的顺序来生成3个毗连的三角形。下面的图像显示我们需要以何种顺序来绘制点才能获得我们需要的三角形图上的蓝点代表输入点 上图的内容转变为几何着色器 #version 330 core layout (points) in; layout (triangle_strip, max_vertices 5) out;void build_house(vec4 position) {gl_Position position vec4(-0.2f, -0.2f, 0.0f, 0.0f);// 1:左下角EmitVertex();gl_Position position vec4( 0.2f, -0.2f, 0.0f, 0.0f);// 2:右下角EmitVertex();gl_Position position vec4(-0.2f, 0.2f, 0.0f, 0.0f);// 3:左上EmitVertex();gl_Position position vec4( 0.2f, 0.2f, 0.0f, 0.0f);// 4:右上EmitVertex();gl_Position position vec4( 0.0f, 0.4f, 0.0f, 0.0f);// 5:屋顶EmitVertex();EndPrimitive(); }void main() {build_house(gl_in[0].gl_Position); } 这个几何着色器生成5个顶点每个顶点是点point的位置加上一个偏移量来组成一个大三角形带。接着最后的基本图形被像素化片段着色器处理整三角形带结果是为我们绘制的每个点生成一个绿房子 可以看到每个房子实则是由3个三角形组成都是仅仅使用空间中一点来绘制的。绿房子看起来还是不够漂亮所以我们再给每个房子加一个不同的颜色。我们将在顶点着色器中为每个顶点增加一个额外的代表颜色信息的顶点属性。 下面是更新了的顶点数据 GLfloat points[] {-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // 左上0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // 右上0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // 右下-0.5f, -0.5f, 1.0f, 1.0f, 0.0f // 左下 }; 然后我们更新顶点着色器使用一个接口块来项几何着色器发送颜色属性 #version 330 core layout (location 0) in vec2 position; layout (location 1) in vec3 color;out VS_OUT {vec3 color; } vs_out;void main() {gl_Position vec4(position.x, position.y, 0.0f, 1.0f);vs_out.color color; }接着我们还需要在几何着色器中声明同样的接口块(使用一个不同的接口名) in VS_OUT {vec3 color; } gs_in[]; 因为几何着色器把多个顶点作为它的输入从顶点着色器来的输入数据总是被以数组的形式表示出来即使现在我们只有一个顶点。 我们不是必须使用接口块来把数据发送到几何着色器中。我们还可以这么写 in vec3 vColor[]; 如果顶点着色器发送的颜色向量是out vec3 vColor那么接口块就会在比如几何着色器这样的着色器中更轻松地完成工作。事实上几何着色器的输入可以非常大把它们组成一个大的接口块数组会更有意义。 然后我们还要为下一个像素着色阶段声明一个输出颜色向量 out vec3 fColor; 因为片段着色器只需要一个已进行了插值的颜色传送多个颜色没有意义。fColor向量这样就不是一个数组而是一个单一的向量。当发射一个顶点时为了它的片段着色器运行每个顶点都会储存最后在fColor中储存的值。对于这些房子来说我们可以在第一个顶点被发射对整个房子上色前只使用来自顶点着色器的颜色填充fColor一次 fColor gs_in[0].color; //只有一个输出颜色所以直接设置为gs_in[0] gl_Position position vec4(-0.2f, -0.2f, 0.0f, 0.0f); // 1:左下 EmitVertex(); gl_Position position vec4( 0.2f, -0.2f, 0.0f, 0.0f); // 2:右下 EmitVertex(); gl_Position position vec4(-0.2f, 0.2f, 0.0f, 0.0f); // 3:左上 EmitVertex(); gl_Position position vec4( 0.2f, 0.2f, 0.0f, 0.0f); // 4:右上 EmitVertex(); gl_Position position vec4( 0.0f, 0.4f, 0.0f, 0.0f); // 5:屋顶 EmitVertex(); EndPrimitive(); 所有发射出去的顶点都把最后储存在fColor中的值嵌入到他们的数据中和我们在他们的属性中定义的顶点颜色相同。所有的分房子便都有了自己的颜色 为了好玩儿我们还可以假装这是在冬天给最后一个顶点一个自己的白色就像在屋顶上落了一些雪。 fColor gs_in[0].color; gl_Position position vec4(-0.2f, -0.2f, 0.0f, 0.0f); EmitVertex(); gl_Position position vec4( 0.2f, -0.2f, 0.0f, 0.0f); EmitVertex(); gl_Position position vec4(-0.2f, 0.2f, 0.0f, 0.0f); EmitVertex(); gl_Position position vec4( 0.2f, 0.2f, 0.0f, 0.0f); EmitVertex(); gl_Position position vec4( 0.0f, 0.4f, 0.0f, 0.0f); fColor vec3(1.0f, 1.0f, 1.0f); EmitVertex(); EndPrimitive(); 结果就像这样 你可以看到使用几何着色器你可以使用最简单的基本图形就能获得漂亮的新玩意。因为这些形状是在你的GPU超快硬件上动态生成的这要比使用顶点缓冲自己定义这些形状更为高效。几何缓冲在简单的经常被重复的形状比如体素voxel的世界和室外的草地上是一种非常强大的优化工具。 四、应用举例——爆破物体 绘制房子的确很有趣但我们不会经常这么用。这就是为什么现在我们将撬起物体缺口形成爆炸式物体的原因虽然这个我们也不会经常用到但是它能向你展示一些几何着色器的强大之处。 当我们说对一个物体进行爆破(Explode)的时候并不是说我们将要把之前的那堆顶点炸掉但是我们打算把每个三角形沿着它们的法线向量移动一小段距离。效果是整个物体上的三角形看起来就像沿着它们的法线向量爆炸了一样。纳米服上的三角形的爆炸式效果看起来是这样的 这样一个几何着色器效果的一大好处是它可以用到任何物体上无论它们多复杂。 1、获取法向量 因为我们打算沿着三角形的法线向量移动三角形的每个顶点我们需要先计算它的法线向量。我们要做的是计算出一个向量它垂直于三角形的表面使用这三个我们已经的到的顶点就能做到。你可能记得变换教程中我们可以使用叉乘获取一个垂直于两个其他向量的向量。如果我们有两个向量a和b它们平行于三角形的表面我们就可以对这两个向量进行叉乘得到法线向量了。下面的几何着色器函数做的正是这件事它使用3个输入顶点坐标获取法线向量 vec3 GetNormal() {vec3 a vec3(gl_in[0].gl_Position) - vec3(gl_in[1].gl_Position);vec3 b vec3(gl_in[2].gl_Position) - vec3(gl_in[1].gl_Position);return normalize(cross(a, b)); } 这里我们使用减法获取了两个向量a和b它们平行于三角形的表面。两个向量相减得到一个两个向量的差值由于所有3个点都在三角形平面上任何向量相减都会得到一个平行于平面的向量。一定要注意如果我们调换了a和b的叉乘顺序我们得到的法线向量就会使反的顺序很重要 知道了如何计算法线向量我们就能创建一个explode函数函数返回的是一个新向量它把位置向量沿着法线向量方向平移 vec4 explode(vec4 position, vec3 normal) {float magnitude 2.0f;vec3 direction normal * ((sin(time) 1.0f) / 2.0f) * magnitude;return position vec4(direction, 0.0f); } 函数本身并不复杂sin正弦函数把一个time变量作为它的参数它根据时间来返回一个-1.0到1.0之间的值。因为我们不想让物体坍缩所以我们把sin返回的值做成0到1的范围。最后的值去乘以法线向量direction向量被添加到位置向量上。 爆炸效果的完整的几何着色器是这样的它使用我们的模型加载器绘制出一个模型 #version 330 core layout (triangles) in; layout (triangle_strip, max_vertices 3) out;in VS_OUT {vec2 texCoords; } gs_in[];out vec2 TexCoords;uniform float time;vec4 explode(vec4 position, vec3 normal) { ... }vec3 GetNormal() { ... }void main() {vec3 normal GetNormal();gl_Position explode(gl_in[0].gl_Position, normal);TexCoords gs_in[0].texCoords;EmitVertex();gl_Position explode(gl_in[1].gl_Position, normal);TexCoords gs_in[1].texCoords;EmitVertex();gl_Position explode(gl_in[2].gl_Position, normal);TexCoords gs_in[2].texCoords;EmitVertex();EndPrimitive(); } 注意我们同样在发射一个顶点前输出了合适的纹理坐标。 也不要忘记在OpenGL代码中设置time变量 glUniform1f(glGetUniformLocation(shader.Program, time), glfwGetTime());最后的结果是一个随着时间持续不断地爆炸的3D模型不断爆炸不断回到正常状态。尽管没什么大用处它却向你展示出很多几何着色器的高级用法。你可以用[完整的源码](http://learnopengl.com/code_viewer.php?codeadvanced/geometry_shader_explode)和[着色器](http://learnopengl.com/code_viewer.php?codeadvanced/geometry_shader_explode_shaders)对比一下你自己的。# 显示法向量在这部分我们将使用几何着色器写一个例子非常有用显示一个法线向量。当编写光照着色器的时候你最终会遇到奇怪的视频输出问题你很难决定是什么导致了这个问题。通常导致光照错误的是不正确的加载顶点数据以及给它们指定了不合理的顶点属性又或是在着色器中不合理的管理导致产生了不正确的法线向量。我们所希望的是有某种方式可以检测出法线向量是否正确。把法线向量显示出来正是这样一种方法恰好几何着色器能够完美地达成这个目的。思路是这样的我们先不用几何着色器正常绘制场景然后我们再次绘制一遍场景但这次只显示我们通过几何着色器生成的法线向量。几何着色器把一个三角形基本图形作为输入类型用它们生成3条和法线向量同向的线段每个顶点一条。伪代码应该是这样的c shader.Use(); DrawScene(); normalDisplayShader.Use(); DrawScene(); 这次我们会创建一个使用模型提供的顶点法线而不是自己去生成。为了适应缩放和旋转我们会在把它变换到裁切空间坐标前使用法线矩阵来生成法线几何着色器用他的位置向量做为裁切空间坐标所以我们还要把法线向量变换到同一个空间。这些都能在顶点着色器中完成 #version 330 core layout (location 0) in vec3 position; layout (location 1) in vec3 normal;out VS_OUT {vec3 normal; } vs_out;uniform mat4 projection; uniform mat4 view; uniform mat4 model;void main() {gl_Position projection * view * model * vec4(position, 1.0f);mat3 normalMatrix mat3(transpose(inverse(view * model)));vs_out.normal normalize(vec3(projection * vec4(normalMatrix * normal, 1.0))); } 经过变换的裁切空间法线向量接着通过一个接口块被传递到下个着色阶段。几何着色器接收每个顶点带有位置和法线向量从每个位置向量绘制出一个法线向量 #version 330 core layout (triangles) in; layout (line_strip, max_vertices 6) out;in VS_OUT {vec3 normal; } gs_in[];const float MAGNITUDE 0.4f;void GenerateLine(int index) {gl_Position gl_in[index].gl_Position;EmitVertex();gl_Position gl_in[index].gl_Position vec4(gs_in[index].normal, 0.0f) * MAGNITUDE;EmitVertex();EndPrimitive(); }void main() {GenerateLine(0); // First vertex normalGenerateLine(1); // Second vertex normalGenerateLine(2); // Third vertex normal } 到现在为止像这样的几何着色器的内容就不言自明了。需要注意的是我们我们把法线向量乘以一个MAGNITUDE向量来限制显示出的法线向量的大小否则它们就太大了。 2、显示法线 由于把法线显示出来通常用于调试的目的我们可以在片段着色器的帮助下把它们显示为单色的线如果你愿意也可以更炫一点。 #version 330 core out vec4 color;void main() {color vec4(1.0f, 1.0f, 0.0f, 1.0f); }现在先使用普通着色器来渲染你的模型然后使用特制的法线可视着色器你会看到这样的效果 除了我们的纳米服现在看起来有点像一个带着隔热手套的全身多毛的家伙外它给了我们一种非常有效的检查一个模型的法线向量是否有错误的方式。你可以想象下这样的几何着色器也经常能被用在给物体添加毛发上。 五、应用举例——细分三角形 利用几何着色器我们可以将triangle list或strip中的每个三角形通过如下图添加三个顶点的方式细分成四个小三角形。 需要注意的是细分后的图元没法利用一个含有6个顶点的triangle strip来构成需要拆分成两个triangle stripv0m0m2m1v2和m0v1m1一共8个顶点其中m0和m1重复一次。 六、应用举例——广告牌技术 广告牌技术简单来说就是通过渲染一张一直朝向Camera的模型图片渲染一张图片只需要4个顶点组成的方块来模拟3D模型模型具有较多的顶点来达到以假乱真的目的常用于植被的渲染以及一些特效上例如火焰。 要使得广告牌一直对着Camera我们就要一直更新广告牌的四个顶点信息简单的几何关系如下图 广告牌四个顶点和几个向量的关系图 设世界坐标下Camera坐标为(x, y, z)广告牌中心点坐标为center (i, j, k)图中三个向量的值为 LookAt normalize( (x, 0, z) - (i, 0, k) ) up (0, 1, 0) right cross(up, LookAt) 再假设广告牌的宽高分别为w和h那么我们就可以计算出四个顶点在世界坐标下的位置 v[0] center w / 2 * right - h / 2 * up; v[1] center w / 2 * right h / 2 * up; v[2] center - w / 2 * right - h / 2 * up; v[3] center - w / 2 * right h / 2 * up; 若不使用几何着色器广告牌四个顶点的坐标更新的操作应该在CPU端每帧进行这就导致每个广告牌要在CPU端存储4个顶点信息然后每帧还要将它们传递给GPU因此顶点信息只能存放在upload heap中对性能和内存都不友好。聪明一点的做法是CPU端顶点位置保持不变在顶点着色器中去计算顶点的位置信息这样可以把顶点信息存放在default heap中提升GPU的读取速度但是依旧要存放4n个顶点。 但是如果使用几何着色器我们就可以在CPU端只存储广告牌的中心点n个顶点且可存放在default heap中然后利用GS将其扩展为四个顶点方块并计算对应的顶点信息即可如下图 利用GS将point变为triangle strip 参考文章 几何着色器 - LearnOpenGL-CN OpenGL学习笔记一之高级OpenGL篇九 几何着色器_opengl adjacency-CSDN博客 https://zhuanlan.zhihu.com/p/585436751
http://www.w-s-a.com/news/268110/

相关文章:

  • 企业如何制作网站管理系统慈溪住房和城乡建设部网站
  • 青岛网站建设有哪些公司区块链网站开发价格
  • 怎么设置网站的logo微信公众号的h5网站开发6
  • 粉色的网站绍兴市建设局网站
  • 个人网站的基本风格是wordpress 模板选择
  • 南昌专业做网站公司有哪些广州市住房城乡建设部门户网站
  • 福州网站建设团队淘宝联盟网站怎么建设
  • 福州企业网站建站模板国内黑色风格的网站
  • 好看的网站首页设计android移动开发
  • 域名注册完成后如何做网站域名 删除 wordpress
  • wordpress xml导入大小东莞seo优化方案
  • 网站建设效益网站销售怎么做的
  • 利用网站空间做代理设计方案的格式范文
  • 无锡建设工程质量监督网站遵义做手机网站建设
  • 衡阳商城网站制作ps做网站首页规范尺寸
  • 微信网站应用开发营销推广的方案
  • 广州做网站商城的公司制作一个app的完整流程
  • 湖南城乡建设厅网站163注册企业邮箱
  • 做网站怎么调整图片间距织梦做的网站如何去掉index
  • 凡科网免费建站步骤及视频网页设计基础教程第二版课后答案
  • 建设一个旅游网站毕业设计企业网站要更新文章吗
  • 做网站需要简介中山网站设计公司
  • 网站怎么做导航栏微信公众号官网登录
  • 1_ 掌握网站开发的基本流程 要求:熟悉网站开发与设计的基本流程.电子商城网站开发
  • 百度网站怎么建设河北省工程造价信息网官网
  • 阿里云网站模板网页设计的合适尺寸是多少
  • 做小程序和做网站哪个好让别人做网站推广需要多少钱
  • 做外贸的几个网站查询网域名解析
  • 酒泉如何做百度的网站seo研究中心好客站
  • 网站设计建设平台户县做网站