This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License
GLSL Geometry Shaders
Mike Bailey mjb@cs.oregonstate.edu
1
geometry_shaders.pptx mjb – January 2, 2021
Computer Graphics
1
Here’s What We Know So Far
2
= Fixed Function
= Programmable
Computer Graphics
mjb – January 2, 2021
2
1
Here’s What We Know So Far
One Vertex In
One Vertex Out
3
Computer Graphics
mjb – January 2, 2021
3
Here’s What We Have Next
One Vertex In
Array of Vertices Out
Arrays of Vertices Out, Possibly with a Change of Topology
4
Computer Graphics
mjb – January 2, 2021
= Fixed Function
= Programmable
4
2
The Geometry Shader: Where Does it Fit in the Pipeline?
= Fixed Function
5
Computer Graphics
mjb – January 2, 2021
= Programmable
If in use, it is always the last stop before the Rasterizer
5
Your application { generates these
The driver translates them { into one of these and feeds them one-at-a-time into the Geometry Shader
Geometry Shader: What Does it Do?
6
TheGeometryShader {
generates (almost) as many of these as it wants
Computer Graphics
ary 2, 2021
Points, Lines, Line Strip, Line Loop,,Lines with Adjacency, Line Strip with Adjacency, Triangles, Triangle Strip, Triangle Fan, Triangles with Adjacency, Triangle Strip with Adjacency
Point, Line, Line with Adjacency, Triangle, Triangle with Adjacency
Points, LineStrips, TriangleStrips
There needn’t be any correlation between Geometry Shader input type
and Geometry Shader output type. Points can generate triangles,
triangles can generate triangle strips, points can generate points, etc.
mjb – Janu
6
3
Additional Topologies that Geometry Shaders made Available:
GL_LINES_ADJACENCY
GL_LINE_STRIP_ADJACENCY GL_TRIANGLES_ADJACENCY GL_TRIANGLE_STRIP_ADJECENCY
7
Computer Graphics
mjb – January 2, 2021
7
Adjacency Primitives (and what they do when not using shaders)
0123
N=1
012345
8
This is what Fixed-Function OpenGL expects these topologies to mean. In Shader World, they can mean whatever you want them to mean. In Shader World, it’s just a way to get some number of vertices into a Geometry Shader.
4N vertices are given.
(where N is the number of line segments to draw).
A line segment is drawn between #1 and #2.
Vertices #0 and #3 are there to provide adjacency information.
Computer Graphics
mjb – January 2, 2021
Lines with Adjacency
Line Strip with Adjacency
N=3
N+3 vertices are given
(where N is the number of line segments to draw).
A line segment is drawn between #1 and #2, #2 and #3, …, #N and #N+1. Vertices #0 and #N+2 are there to provide adjacency information.
8
4
Adjacency Primitives (and what they do when not using shaders)
9
2 13
Triangles with Adjacency
6N vertices are given
(where N is the number of triangles to draw). 0 Points 0, 2, and 4 define the triangle.
Points 1, 3, and 5 tell where adjacent triangles are.
4 N = 1
59 2 6 10
5
Triangle Strip with Adjacency
1
4+2N vertices are given
(where N is the number of triangles to draw).
Points 0, 2, 4, 6, 8, 10, …define the triangles. 0 Points 1, 3, 5, 7, 9, 11, … tell where adjacent triangles are.
Computer Graphics
11
mjb – January 2, 2021
37
48
N=4
9
Adjacency Primitives (and what they do when you are using shaders)
10
In general, we will use the “with adjacency” primitives as a way of importing some number of vertices into the geometry shader.
These are the most useful:
GL_LINES_ADJACENCY GL_TRIANGLES_ADJACENCY
0123
4 vertices 6 vertices
2 13
04 5
Computer Graphics
mjb – January 2, 2021
10
5
If a Vertex Shader Writes Variables as:
gl_Position gl_PointSize
“out”
then the Geometry Shader will Read Them as:
gl_PositionIn[ ] gl_PointSizeIn[ ]
“in”
and will Write Them to the Fragment Shader as:
gl_Position gl_PointSize
“out”
What Do the Inputs to a Geometry Shader Look Like?
11
In the Geometry Shader, the dimensions indicated by
given by the variable gl_VerticesIn, although you will already know this by the type of geometry you are inputting
Computer Graphics
1 GL_POINTS
2 GL_LINES
4 GL_LINES_ADJACENCY
3 GL_TRIANGLES
6 GL_TRIANGLES_ADJACENCY
mjb – January 2, 2021
are
11
What Do the Outputs to a Geometry Shader Look Like?
12
• gl_Position
• gl_PointSize
• Plus, any of your own variables that you have declared as out
When the Geometry Shader calls
EmitVertex( )
this set of variables is copied to an entry in the shader’s Primitive Assembly step
When the Geometry Shader calls
EndPrimitive( )
the vertices that have been saved in the Primitive Assembly elements are then assembled, rasterized, etc.
Note: there is no “BeginPrimitive( )” function. It is implied by (1) the start of the
Geometry Shader, or (2) returning from the EndPrimitive( ) call. Also, there is no need
to call EndPrimitive( ) at the end of the Geometry Shader – it is implied.
Computer Graphics
mjb – January 2, 2021
12
6
If you are using a Geometry Shader, then the GS must be used if you want to pass information from the Vertex Shader to the Fragment Shader
V
G
Primitive Assembly
13
out vec4 gl_Position;
out vec4 vColor; vColor = gl_Color;
These are already declared for you
in vec4 gl_PositionIn[3];
in vec4 vColor[3];
out vec4 gl_Position;
out vec4 gColor; gColor = vColor[ k ];
F
Computer Graphics
Primitive Assembly
Rasterizer
in vec4 gColor;
gl_Position = gl_PositionIn[0]; gColor = vColor[0]; EmitVertex( );
…
mjb – January 2, 2021
13
P1
Example: A Bézier Curve
P2
P(u)(1u)3P 3u(1u)2P3u2(1u)P u3P 0123
14
P0
P3
Computer Graphics
mjb – January 2, 2021
Need to pass 4 points in to define the curve. You need to pass N points out to draw the curve as a Line Strip.
14
7
beziercurve.glib
beziercurve.vert
beziercurve.frag
Example: Expanding 4 Points into a Bezier Curve with a Variable Number of Line Segments
15
Computer Graphics
mjb – January 2, 2021
void main( ) {
gl_FragColor = vec4( 0., 1., 0., 1. );
}
Vertex beziercurve.vert
Geometry beziercurve.geom Fragment beziercurve.frag
Program BezierCurve uNum <2 4 50>
LineWidth 3.
LinesAdjacency [0. 0. 0.] [1. 1. 1.] [2. 1. 2.] [3. -1. 0.]
void main( ) {
}
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
15
beziercurve.geom
Example: Expanding 4 Points into a Bezier Curve with a Variable Number of Line Segments
16
#version 330 compatibility
#extension GL_EXT_gpu_shader4: enable #extension GL_EXT_geometry_shader4: enable layout( lines_adjacency ) in;
layout( line_strip, max_vertices=200 ) out; uniform int uNum;
void
main( )
{
float dt = 1. / float(uNum); float t = 0.;
for( int i = 0; i <= uNum; i++ ) {
} Co}mputer Graphics
mjb – January 2, 2021
float omt = 1. - t;
float omt2 = omt * omt; float omt3 = omt * omt2; float t2 = t * t;
float t3 = t * t2;
vec4 xyzw =
gl_Position = xyzw; EmitVertex( )
t += dt;
omt3 * gl_PositionIn[0].xyzw + 3. * t * omt2 * gl_PositionIn[1].xyzw + 3. * t2 * omt * gl_PositionIn[2].xyzw +
t3 * gl_PositionIn[3].xyzw;
Note: layout directives are a GLSL-ism and are used to define what the storage looks like
16
8
Example: Expanding 4 Points into a Bezier Curve with a Variable Number of Line Segments
17
Computer Graphics
mjb – January 2, 2021
uNum = 5 uNum = 25
17
beziercurve.vert
beziercurve.geom
Computer Graphics
mjb – January 2, 2021
Note: It would have made no Difference if the Matrix Transform had been done in the Geometry Shader Instead
18
void main( ) {
}
gl_Position = gl_Vertex;
...
} }
vec4 xyzw = omt3 * gl_PositionIn[0].xyzw + 3. * t * omt2 * gl_PositionIn[1].xyzw + 3. * t2 * omt * gl_PositionIn[2].xyzw +
t3 * gl_PositionIn[3].xyzw;
gl_Position = gl_ModelViewProjectionMatrix * xyzw; EmitVertex( )
t += dt;
18
9
Another Example: Shrinking Triangles
19
Computer Graphics
2021
mjb – January 2,
19
Example: Shrinking Triangles
20
P2
P0
Centroid = “CG”
P1
CG=(P0 +P1 +P2 )/3.; P0’=CG+uShrink*(P0 -CG) P1’=CG+uShrink*(P1 -CG) P2’=CG+uShrink*(P2 -CG)
Computer Graphics
mjb – January 2, 2021
20
10
shrink.geom
#version 330 compatibility
#extension GL_EXT_gpu_shader4: enable #extension GL_EXT_geometry_shader4: enable layout( triangles ) in;
layout( triangle_strip, max_vertices=200 ) out;
uniform float uShrink;
in vec3 vNormal[3];
out float gLightIntensity;
const vec3 LIGHTPOS = vec3( 0., 10., 0. ); vec3 V[3];
vec3 CG;
void
ProduceVertex( int v ) {
g LightIntensity = dot( normalize(LIGHTPOS- V[v]), vNormal[v] ); g LightIntensity = abs( gLightIntensity );
gl_Position = gl_ModelViewProjectionMatrix * vec4( CG + uShrink * ( V[v] - CG ), 1. );
EmitVertex( ); }
void main( ) {
21
Computer Graphi}cs
V[0] = gl_PositionIn[0].xyz; V[1] = gl_PositionIn[1].xyz; V[2] = gl_PositionIn[2].xyz; CG=( V[0]+V[1]+V[2] )/3.; ProduceVertex( 0 ); ProduceVertex( 1 ); ProduceVertex( 2 );
mjb – January 2, 2021
21
Another Example: Sphere Subdivision
V2
(0,1)
22
It’s often useful to be able to parameterize a triangle into (s,t), like this:
(0,0)
(1,0)
t
Note! There is no place in this triangle where s = t = 1.
t=0
V0 s V1
Computer Graphics
mjb – January 2, 2021
v(s,t) = V0 + s*(V1-V0) + t*(V2-V0)
22
11
Example: Sphere Subdivision
V2 V2 V2
23
V0 uLevel = 0 V1 V0 numLayers = 2level = 1
Computer Graphics
uLevel = 1 V1 V0 numLayers = 2
uLevel = 2 V1 numLayers = 4
mjb – January 2, 2021
23
spheresubd.glib
Example: Sphere Subdivision
24
Vertex spheresubd.vert
Geometry spheresubd.geom
Fragment spheresubd.frag
Program SphereSubd uLevel <0 0 10> uRadius <.5 1. 5.> uColor { 1. .5 .15 1. }
Triangles[0.0. 1.] [1.0. 0.] [0. 1.0.] Triangles [ 1. 0. 0.] [ 0. 0. -1.] [0. 1. 0.] Triangles [ 0. 0. -1.] [-1. 0. 0.] [0. 1. 0.] Triangles [-1. 0. 0.] [ 0. 0. 1.] [0. 1. 0.]
Triangles [ 0. 0. 1.] [ 1. 0. 0.] [0. -1. 0.] Triangles [ 1. 0. 0.] [ 0. 0. -1.] [0. -1. 0.] Triangles [ 0. 0. -1.] [-1. 0. 0.] [0. -1. 0.] Triangles [-1. 0. 0.] [ 0. 0. 1.] [0. -1. 0.]
Computer Graphics
mjb – January 2, 2021
24
12
spheresubd.vert
spheresubd.frag
Computer Graphics
mjb – January 2, 2021
Example: Sphere Subdivision
25
void main( ) {
}
gl_Position = gl_Vertex;
uniform vec4 uColor;
in float
void main( ) {
}
gLightIntensity;
gl_FragColor = vec4( gLightIntensity*uColor.rgb, 1. );
25
spheresubd.geom
Example: Sphere Subdivision
#version 330 compatibility
#extension GL_EXT_gpu_shader4: enable #extension GL_EXT_geometry_shader4: enable layout( triangles ) in;
layout( triangle_strip, max_vertices=200 ) out;
uniform int uLevel;
uniform float uRadius;
out float gLightIntensity;
const vec3 LIGHTPOS = vec3( 0., 10., 0. );
vec3 V0, V01, V02;
void
ProduceVertex( float s, float t ) {
vec3 v = V0 + s*V01 + t*V02;
v = normalize(v);
vec3 n = v;
vec3 tnorm = normalize( gl_NormalMatrix * n ); // the transformed normal
vec4 ECposition = gl_ModelViewMatrix * vec4( (uRadius*v), 1. );
gLightIntensity = abs( dot( normalize(LIGHTPOS – ECposition.xyz), tnorm ) );
gl_Position = gl_ProjectionMatrix * ECposition; EmitVertex( );
}
Computer Graphics
mjb – January 2, 2021
26
26
13
spheresubd.geom
Example: Sphere Subdivision
27
void main( ) {
V01 = ( gl_PositionIn[1] – gl_PositionIn[0] ).xyz; V02 = ( gl_PositionIn[2] – gl_PositionIn[0] ).xyz; V0 = gl_PositionIn[0].xyz;
int numLayers = 1 << uLevel; float dt = 1. / float( numLayers ); float t_top = 1.;
for( int it = 0; it < numLayers; it++ ) {
...
Computer Graphics
mjb – January 2, 2021
27
spheresubd.geom
Example: Sphere Subdivision
for( int it = 0; it < numLayers; it++ ) {
float t_bot = t_top - dt; float smax_top = 1. - t_top; float smax_bot = 1. - t_bot;
int nums = it + 1;
float ds_top = smax_top / float( nums - 1 ); float ds_bot = smax_bot / float( nums );
float s_top = 0.; float s_bot = 0.;
for( int is = 0; is < nums; is++ ) {
ProduceVertex( s_bot, t_bot ); ProduceVertex( s_top, t_top ); s_top += ds_top;
s_bot += ds_bot;
}
ProduceVertex( s_bot, t_bot ); EndPrimitive( );
t_top = t_bot; t_bot -= dt;
}
Computer Graphics
28
}
mjb – January 2, 2021
28
14
Level = 0
Example: Sphere Subdivision with One triangle
29
Level = 1
Level = 3
Level = 2
Computer Graphics
mjb – January 2, 2021
29
Example: Sphere Subdivision with the Whole Sphere (8 triangles)
Level = 0
30
Level = 1
Level = 3
Level = 2
Computer Graphics
mjb – January 2, 2021
30
15
V2
Another Example: Explosion
Time
31
V0
Level = 2 V1 numLayers = 4
Time
Computer Graphics
xx0 vxt
yy vt1at2 0y2y
Time
1. Breakthetrianglesintopoints
2. Treateachpoint’sdistancefromthetriangle’s CG as an initial velocity
3. Followthelawsofprojectilemotion:
mjb – January 2, 2021
31
explode.geom
Example: Explosion
32
#version 330 compatibility
#extension GL_EXT_gpu_shader4: enable #extension GL_EXT_geometry_shader4: enable layout( triangles ) in;
layout( points, max_vertices=200 ) out;
uniform int uLevel; uniform float uGravity; uniform float uTime; uniform float uVelScale;
vec3 V0, V01, V02; vec3 CG;
void
ProduceVertex( float s, float t ) {
vec3 v = V0 + s*V01 + t*V02;
vec3 vel = uVelScale * ( v - CG );
v = CG + vel*uTime + 0.5*vec3(0.,uGravity,0.)*uTime*uTime; gl_Position = gl_ProjectionMatrix * vec4( v, 1. ); EmitVertex( );
}
Computer Graphics
mjb – January 2, 2021
32
16
explode.geom
void main( ) {
Example: Explosion
V01 = ( gl_PositionIn[1] - gl_PositionIn[0] ).xyz;
V02 = ( gl_PositionIn[2] - gl_PositionIn[0] ).xyz;
V0 = gl_PositionIn[0].xyz;
CG = ( gl_PositionIn[0].xyz + gl_PositionIn[1].xyz + gl_PositionIn[2].xyz ) / 3.;
int numLayers = 1 << uLevel;
float dt = 1. / float( numLayers ); float t = 1.;
for( int it = 0; it <= numLayers; it++ ) {
float smax = 1. - t;
int nums = it + 1;
float ds = smax / float( nums - 1 ); float s = 0.;
for( int is = 0; is < nums; is++ ) {
ProduceVertex( s, t );
s += ds; }
t -= dt; }
}
Computer Graphics
mjb – January 2, 2021
33
33
Example: Explosion
34
Computer Graphics
mjb – January 2, 2021
34
17
Another Example: Silhouettes
2 13
04 5
Computer Graphics
mjb – January 2, 2021
35
1. Compute the normals of each of the four triangles
2. If there is a sign difference between the z component of the center triangle’s normal and the z component of an adjacent triangle’s normal, draw their common edge
I.e., you are looking for a crease.
35
silh.glib
Example: Silhouettes
36
Computer Graphics
mjb – January 2, 2021
Obj bunny.obj
Vertex silh.vert
Geometry silh.geom
Fragment silh.frag
Program Silhouette uColor { 0. 1. 0. 1. }
ObjAdj bunny.obj
36
18
silh.vert
silh.frag
Computer Graphics
mjb – January 2, 2021
Example: Silhouettes
37
void main( ) {
}
gl_Position = gl_ModelViewMatrix * gl_Vertex;
uniform vec4 uColor;
void main( ) {
}
gl_FragColor = vec4( uColor.rgb, 1. );
37
silh.geom
Example: Silhouettes
38
#version 330 compatibility
#extension GL_EXT_gpu_shader4: enable #extension GL_EXT_geometry_shader4: enable layout( triangles_adjacency ) in;
layout( line_strip, max_vertices=200 ) out;
void main( )
{
vec3 V0 = gl_PositionIn[0].xyz; vec3 V1 = gl_PositionIn[1].xyz; vec3 V2 = gl_PositionIn[2].xyz; vec3 V3 = gl_PositionIn[3].xyz; vec3 V4 = gl_PositionIn[4].xyz; vec3 V5 = gl_PositionIn[5].xyz;
vec3 N042 = cross( V4-V0, V2-V0 ); vec3 N021 = cross( V2-V0, V1-V0 ); vec3 N243 = cross( V4-V2, V3-V2 ); vec3 N405 = cross( V0-V4, V5-V4 );
if( dot( N042, N021 ) < 0. )
N021 = vec3(0.,0.,0.) - N021;
if( dot( N042, N243 ) < 0. )
N243 = vec3(0.,0.,0.) - N243;
if( dot( N042, N405 ) < 0. )
N405 = vec3(0.,0.,0.) - N405;
2 13
04 5
// the center triangle’s normal
// make sure each outer triangle’s
// normal is in the same general direction
Computer Graphics
mjb – January 2, 2021
38
19
silh.geom
if( N042.z * N021.z <= 0. ) {
Example: Silhouettes
39
gl_Position = gl_ProjectionMatrix * vec4( V0, EmitVertex( );
gl_Position = gl_ProjectionMatrix * vec4( V2, EmitVertex( );
EndPrimitive( );
1. ); 1. );
1. ); 1. );
1. ); 1. );
2 13
}
if( N042.z * N243.z <= 0. ) {
04 5
}
gl_Position = gl_ProjectionMatrix * vec4( V2, EmitVertex( );
gl_Position = gl_ProjectionMatrix * vec4( V4, EmitVertex( );
EndPrimitive( );
if( N042.z * N405.z <= 0. ) {
gl_Position = gl_ProjectionMatrix * vec4( V4, EmitVertex( );
gl_Position = gl_ProjectionMatrix * vec4( V0, EmitVertex( );
EndPrimitive( );
} C}omputer Graphics
mjb – January 2, 2021
39
Example: Bunny Silhouettes
40
Computer Graphics
mjb – January 2, 2021
40
20
Another Example: Hedgehog Plots
41
Computer Graphics
mjb – January 2, 2021
41
hedgehog.geom, I
#version 330 compatibility
#extension GL_EXT_gpu_shader4: enable #extension GL_EXT_geometry_shader4: enable layout( triangles ) in;
layout( line_strip, max_vertices=200 ) out;
uniform int uDetail; uniform float uDroop; uniform int uLength; uniform float uStep; in vec3 vTnorm[3]; in vec4 vColor[3]; out vec4 gColor;
int ILength;
vec3 Norm[3]; vec3 N0, N01, N02; vec4 V0, V01, V02;
void
ProduceVertices( float s, float t ) {
vec4 v = V0 + s*V01 + t*V02;
vec3 n = normalize( N0 + s*N01 + t*N02 );
for( int i = 0; i <= uLength; i++ ) {
gl_Position = gl_ProjectionMatrix * v; gColor = vColor[0];
EmitVertex( );
v.xyz += uStep * n;
v.y -= uDroop * float(i*i); }
EndPrimitive( ); }
42
Computer Graphics
mjb – January 2, 2021
42
21
hedgehog.geom, II
43
void main( ) {
V0 = gl_PositionIn[0];
V01 = ( gl_PositionIn[1] - gl_PositionIn[0] ); V02 = ( gl_PositionIn[2] - gl_PositionIn[0] ); Norm[0] = vTnorm[0];
Norm[1] = vTnorm[1];
Norm[2] = vTnorm[2];
if( dot( Norm[0], Norm[1] ) < 0. ) Norm[1] = -Norm[1];
if( dot( Norm[0], Norm[2] ) < 0. ) Norm[2] = -Norm[2];
N0 = normalize( Norm[0] );
N01 = normalize( Norm[1] - Norm[0] ); N02 = normalize( Norm[2] - Norm[0] );
int numLayers = 1 << uDetail;
Computer Graphics
mjb – January 2, 2021
43
hedgehog.geom, III
44
float dt = 1. / float( numLayers ); float t = 1.;
for( int it = 0; it <= numLayers; it++ ) {
float smax = 1. - t;
int nums = it + 1;
float ds = smax / float( nums - 1 );
float s = 0.;
for( int is = 0; is < nums; is++ ) {
ProduceVertices( s, t );
s += ds; }
t -= dt; }
}
Computer Graphics
mjb – January 2, 2021
44
22
Ducky Hedgehog Plot
45
Computer Graphics
mjb – January 2, 2021
45
Hedgehog Plots Gone Wild
46
Computer Graphics
mjb – January 2, 2021
46
23
A GLSL Built-in Variable for the Geometry Shaders
int gl_PrimitiveIDIn
• Tells the number of primitives processed since the last time glBegin( ) was called • Calling a vertex buffer drawing function counts as an implied glBegin( )
• gl_PrimitiveIDIn is 0 for the first primitive after the glBegin( )
47
Geometry shaders can set the built-in variable gl_PrimitiveID to send a primitive number to the fragment shader
Computer Graphics
mjb – January 2, 2021
47
What Happens if you Exceed the Maximum Allowed Emitted Vertices?
48
New in GLSL 4.x – you can loop
back through the Geometry Shader
multiple times
Computer Graphics
mjb – January 2, 2021
48
24