Simple Introduction to Geometry Shaders in GLSL (Part 2)

来源:互联网 发布:mysql修改数据库列名 编辑:程序博客网 时间:2024/06/05 09:39


Simple Introduction to Geometry Shaders in GLSL (Part 2)



Firenze...

Content:

  • 1 – Doubling the geometry with the geometry shader
  • 2 – The Demo

You missed the first part of this introduction to GS? No problem, you can find itHERE.

1 – Doubling the geometry with the geometry shader

Let’s see a more interesting use of the GS: a geometry doubler. This geometry doubler duplicates the input primitives and translates them along the vertex normal.

GeeXLab, geometry shader in GLSL
The GS doubler demo in GeeXLab – green: input geometry – yellow: duplicated geometry

Like in the first example, the GLSL program includes a VS, A GS and a PS.

The geometry doubler allows us to see how to pass data from vertex shader to geometry shader.

Vertex shader:

#version 330 compatibilityout vec4 normal;void main(){  gl_Position = gl_Vertex;  normal =  vec4(gl_Normal.xyz, 0.0);}

As you can see, this vertex shader is rather mininal (a pass-trought VS). Why? because the vertex transformation will be done in the geometry shader.

In this vertex shader, normal is a vertex attribute and is sent to the geometry shader like the built-in gl_Position. Now let’s see how to read the vertex normal in the GS.

Geomerty shader:

#version 330 compatibilitylayout(triangles) in;layout(triangle_strip, max_vertices=6) out;uniform mat4 viewMatrix;uniform mat4 projectionMatrix;uniform mat4 modelMatrix;in vec4 normal[];out vec4 vertex_color;void main(){  mat4 modelViewMatrix = viewMatrix * modelMatrix;  mat4 viewProjectionMatrix = projectionMatrix * viewMatrix;  int i;    //====== First triangle - identical to the input one.  //  for(i=0; i<3; i++)  {    vec4 view_pos = modelViewMatrix * gl_in[i].gl_Position;    gl_Position = projectionMatrix * view_pos;    vertex_color = vec4(0.0, 1.0, 0.0, 1.0);    EmitVertex();  }  EndPrimitive();    //====== Second triangle - translated version of the   // input triangle.  //  for(i=0; i<3; i++)  {    vec4 N =  normal[i];    vec4 world_pos = modelMatrix * (gl_in[i].gl_Position + normalize(N) * 10.0);    gl_Position = viewProjectionMatrix * world_pos;    vertex_color = vec4(1.0, 1.0, 0.0, 1.0);    EmitVertex();  }  EndPrimitive();}

Remember, we are in a geometry shader: that’s why we retrieve per-vertex normals in an array. There is one normal per vertex and the size of the array is… 3 elements because the GS takes a triangle as input data. The number of elements of the array is automatically set by the GLSL compiler according to the input layout (here a triangle).

The geometry doubler shader outputs two triangles: one the is input triangle and the second one is a new triangle: the double. This second triangle is translated along the vertex normal. The translation is done in object space (object space? refresh your memory with this article about transformation spaces) that’s why we do all the computations in the geometry shader. If you try to translate along the normal in another space (world, view, projection), you will end up with strange results…

In order to tell OpenGL we output two triangles, we must modify a bit the output layout compared to our first GS in thepart 1:

layout(triangle_strip, max_vertices=6) out;

The GS outputs now 6 vertices.

We used an array to retrieve the normals in the GS. But if you need to pass more vertex attributes between the VS and the GS, there is a more handy way to do it: by using aninterface block. An interface block allows to pack in a structure all vertex attributes and to pass a single array from the VS to the GS:

Vertex shader with interface block:

#version 330 compatibilityout VertexAttrib{  vec3 normal;  vec4 color;} vertex;void main(){  gl_Position = gl_Vertex;  vertex.normal =  vec4(gl_Normal.xyz, 0.0);  vertex.color =  vec4(1.0, 1.0, 0.0, 1.0);}

Geomerty shader with interface block:

#version 330 compatibilitylayout(triangles) in;layout(triangle_strip, max_vertices=6) out;uniform mat4 viewMatrix;uniform mat4 projectionMatrix;uniform mat4 modelMatrix;in VertexAttrib{  vec3 normal;  vec4 color;} vertex[];out vec4 vertex_color;void main(){  mat4 modelViewMatrix = viewMatrix * modelMatrix;  mat4 viewProjectionMatrix = projectionMatrix * viewMatrix;  int i;    //====== First triangle - identical to the input one.  //  for(i=0; i<3; i++)  {    vec4 view_pos = modelViewMatrix * gl_in[i].gl_Position;    gl_Position = projectionMatrix * view_pos;    vertex_color = vec4(0.0, 1.0, 0.0, 1.0);    EmitVertex();  }  EndPrimitive();    //====== Second triangle - translated version of the   // input triangle.  //  for(i=0; i<3; i++)  {    vec4 N =  vertex[i].normal;    vec4 world_pos = modelMatrix * (gl_in[i].gl_Position + normalize(N) * 10.0);    gl_Position = viewProjectionMatrix * world_pos;    vertex_color = vertex[i].color;    EmitVertex();  }  EndPrimitive();}

And the last shader of our GLSL program:
Pixel shader:

#version 330 compatibilityin vec4 vertex_color;void main(void){  gl_FragColor = vertex_color;}

Nothing special about the PS.

2 – The Demo

 The GeeXLab demo is available in the GLSL_Geometry_Shader/ folder of GeeXLab code sample pack:
[download#40#image]

This demo requires GeeXLab 0.3.2+ (GS support has been added in the 0.3.x branch of GeeXLab).

GeeXLab, geometry shader in GLSL
The GS doubler demo in GeeXLab with live coding



http://www.geeks3d.com/20111117/simple-introduction-to-geometry-shader-in-glsl-part-2/

0 0
原创粉丝点击