This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License
Mike Bailey mjb@cs.oregonstate.edu
Computer Graphics
geometry_shaders.pptx
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
Computer Graphics
= Fixed Function = Programmable
Arrays of Vertices Out, Possibly with a Change of Topology
GLSL Geometry Shaders
12
Here’s What We Know So Far
3
Here’s What We Have Next
4
One Vertex In
One Vertex Out
Array of Vertices Out
34
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
1
Here’s What We Know So Far
2
= Fixed Function = Programmable
One Vertex In
1
Computer Graphics
Computer Graphics
triangles can generate triangle strips, points can generate points, etc.
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
The Geometry Shader: Where Does it Fit in the Pipeline?
5
6
= Fixed Function = Programmable
There needn’t be any correlation between Geometry Shader input type
56
Additional Topologies that Geometry Shaders made Available:
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.
GL_LINES_ADJACENCY
GL_LINE_STRIP_ADJACENCY GL_TRIANGLES_ADJACENCY GL_TRIANGLE_STRIP_ADJECENCY
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.
78
If in use, it is always the last stop before the Rasterizer
The Geometry Shader {
Points, LineStrips, TriangleStrips
mjb – January 2, 2021
mjb – January 2, 2021
7
Adjacency Primitives (and what they do when not using shaders) 8
Yourapplication{ Points,Lines,LineStrip,LineLoop,,Lineswith generates these Adjacency, Line Strip with Adjacency, Triangles, Triangle
generates (almost) as many of these as it wants
Lines with Adjacency
Line Strip with Adjacency
012345
Geometry Shader: What Does it Do?
Strip, Triangle Fan, Triangles with Adjacency, Triangle Strip with Adjacency
The driver translates them { Point, Line, Line with Adjacency, into one of these and feeds
them one-at-a-time Triangle, Triangle with Adjacency into the Geometry Shader
and Geometry Shader output type. Points can generate triangles,
0123
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.
N=1
N=3
2
Adjacency Primitives (and what they do when not using shaders)
9
Adjacency Primitives (and what they do when you are using shaders) 10
Triangles with Adjacency 1
3
In general, we will use the “with adjacency” primitives as a way of importing some number of vertices into the geometry shader.
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.
These are the most useful:
Triangle Strip with Adjacency 1
2
59 6 10
0 1
2 3
2
1 3
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.
11
If a Vertex Shader Writes Variables as:
then the Geometry Shader will Read Them as:
and will Write Them to the Fragment Shader as:
EmitVertex( )
gl_Position gl_PointSize
gl_PositionIn[ ] gl_PointSizeIn[ ]
gl_Position gl_PointSize
this set of variables is copied to an entry in the shader’s Primitive Assembly step
Computer Graphics
to call EndPrimitive( ) at the end of the Geometry Shader – it is implied.
11
12
“out”
“in”
“out”
the vertices that have been saved in the Primitive Assembly elements are then assembled, rasterized, etc.
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
1 2 4 3 6
GL_POINTS
GL_LINES GL_LINES_ADJACENCY GL_TRIANGLES GL_TRIANGLES_ADJACENCY
2
5
GL_LINES_ADJACENCY GL_TRIANGLES_ADJACENCY
4 vertices 6 vertices
are
4
N = 1
Computer Graphics 3
9 10
What Do the Inputs to a Geometry Shader Look Like?
11
What Do the Outputs to a Geometry Shader Look Like?
12
48N=4 04
7
5
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
• gl_Position
• gl_PointSize
• Plus, any of your own variables that you have declared as out
Note: there is no “BeginPrimitive( )” function. It is implied by (1) the start of the
When the Geometry Shader calls
When the Geometry Shader calls
Geometry Shader, or (2) returning from the EndPrimitive( ) call. Also, there is no need
EndPrimitive( )
3
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
Example: A Bézier Curve
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
13
14
beziercurve.glib
#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( )
{
beziercurve.vert
float omt = 1. – t;
float omt2 = omt * omt; float omt3 = omt * omt2; float t2 = t * t;
float t3 = t * t2;
vec4 xyzw =
beziercurve.frag
t3 * gl_PositionIn[3].xyzw;
Computer Graphics
mjb – January 2, 2021
mjb – January 2, 2021
15
16
G
in vec4 vColor[3];
F
in vec4 gColor;
}
void main( ) {
gl_Position = xyzw; EmitVertex( )
t += dt;
out vec4 gl_Position;
V
These are already declared for you
out vec4 vColor; vColor = gl_Color;
Primitive Assembly
P2
in vec4 gl_PositionIn[3];
gl_Position = gl_PositionIn[0]; gColor = vColor[0]; EmitVertex( );
…
out vec4 gl_Position;
P0
P3
out vec4 gColor; gColor = vColor[ k ];
Primitive Assembly Rasterizer
Example: Expanding 4 Points into a Bezier Curve with a Variable Number of Line Segments
beziercurve.geom
Example: Expanding 4 Points into a Bezier Curve with a Variable Number of Line Segments
Vertex beziercurve.vert
Geometry beziercurve.geom Fragment beziercurve.frag
Program BezierCurve uNum <2 4 50>
Note: layout directives are a GLSL-ism and are used to define what the storage looks like
LineWidth 3.
LinesAdjacency [0. 0. 0.] [1. 1. 1.] [2. 1. 2.] [3. -1. 0.]
void main( ) {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
omt3 * gl_PositionIn[0].xyzw + 3. * t * omt2 * gl_PositionIn[1].xyzw + 3. * t2 * omt * gl_PositionIn[2].xyzw +
gl_FragColor = vec4( 0., 1., 0., 1. ); }
} Co}mputer Graphics
13
14
15
16
float dt = 1. / float(uNum); float t = 0.;
for( int i = 0; i <= uNum; i++ ) {
P1
P(u)(1u)3P 3u(1u)2P3u2(1u)P u3P 0123
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.
4
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
17
18
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
19
20
Example: Expanding 4 Points into a Bezier Curve with a Variable Number of Line Segments
Note: It would have made no Difference if the Matrix Transform had been done in the Geometry Shader Instead
uNum = 5
uNum = 25
} }
Another Example: Shrinking Triangles
19
Example: Shrinking Triangles
20
17
18
beziercurve.vert
void main( ) {
}
beziercurve.geom
...
gl_Position = gl_Vertex;
P0
P1
vec4 xyzw =
omt3 * gl_PositionIn[0].xyzw + 3. * t * omt2 * gl_PositionIn[1].xyzw + 3. * t2 * omt * gl_PositionIn[2].xyzw +
gl_Position = gl_ModelViewProjectionMatrix * xyzw; EmitVertex( )
t += dt;
P2
CG=(P0 +P1 +P2 )/3.; P0’ = CG + uShrink * ( P0 - CG ) P1’ = CG + uShrink * ( P1 - CG ) P2’ = CG + uShrink * ( P2 - CG )
t3 * gl_PositionIn[3].xyzw;
Centroid = “CG”
5
Computer Graphi}cs 21
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
V0
uLevel = 0 numLayers = 2level = 1
V1
V0
uLevel = 1 numLayers = 2
V1
V0
uLevel = 2 numLayers = 4
V1
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
Computer Graphics
mjb – January 2, 2021
23
24
#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;
Another Example: Sphere Subdivision
uniform float uShrink;
in vec3 vNormal[3];
out float gLightIntensity;
const vec3 LIGHTPOS = vec3( 0., 10., 0. ); vec3 V[3];
It’s often useful to be able to parameterize a triangle into (s,t), like this:
vec3 CG;
(0,1)
void
ProduceVertex( int v ) {
Note! There is no place in this triangle where s = t = 1.
void main( ) {
t=0
V0 s V1
shrink.geom
21
22
g LightIntensity = dot( normalize(LIGHTPOS- V[v]), vNormal[v] ); g LightIntensity = abs( gLightIntensity );
t
gl_Position = gl_ModelViewProjectionMatrix * vec4( CG + uShrink * ( V[v] - CG ), 1. );
EmitVertex( ); }
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 );
(0,0)
(1,0)
Example: Sphere Subdivision
Example: Sphere Subdivision
V2 V2 V2
Vertex
Geometry spheresubd.geom
Fragment spheresubd.frag
Program SphereSubd uLevel <0 0 10> uRadius <.5 1. 5.> uColor { 1. .5 .15 1. }
23
24
22
spheresubd.glib
spheresubd.vert
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.]
V2
v(s,t) = V0 + s*(V1-V0) + t*(V2-V0)
6
spheresubd.vert
#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;
spheresubd.frag
vec3 V0, V01, V02;
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
25
26
spheresubd.geom
for( int it = 0; it < numLayers; it++ ) {
void main( ) {
float t_bot = t_top - dt; float smax_top = 1. - t_top; float smax_bot = 1. - t_bot;
void main( ) {
uniform int uLevel;
uniform float uRadius;
out float gLightIntensity;
const vec3 LIGHTPOS = vec3( 0., 10., 0. );
}
uniform vec4 uColor;
void
ProduceVertex( float s, float t ) {
in float
gLightIntensity;
void main( ) {
vec3 v = V0 + s*V01 + t*V02;
v = normalize(v);
vec3 n = v;
vec3 tnorm = normalize( gl_NormalMatrix * n ); // the transformed normal
}
V01 = ( gl_PositionIn[1] - gl_PositionIn[0] ).xyz; V02 = ( gl_PositionIn[2] - gl_PositionIn[0] ).xyz; V0 = gl_PositionIn[0].xyz;
int nums = it + 1;
float ds_top = smax_top / float( nums - 1 ); float ds_bot = smax_bot / float( nums );
int numLayers = 1 << uLevel; float dt = 1. / float( numLayers ); float t_top = 1.;
float s_top = 0.; float s_bot = 0.;
for( int it = 0; it < numLayers; it++ ) {
ProduceVertex( s_bot, t_bot ); ProduceVertex( s_top, t_top ); s_top += ds_top;
s_bot += ds_bot;
Computer Graphics
}
27
28
...
Example: Sphere Subdivision
spheresubd.geom
Example: Sphere Subdivision
gl_Position = gl_Vertex;
gl_FragColor = vec4( gLightIntensity*uColor.rgb, 1. );
Example: Sphere Subdivision
spheresubd.geom
Example: Sphere Subdivision
mjb – January 2, 2021
}
mjb – January 2, 2021
25
26
27
28
}
vec4 ECposition = gl_ModelViewMatrix * vec4( (uRadius*v), 1. ); gLightIntensity = abs( dot( normalize(LIGHTPOS - ECposition.xyz), tnorm )
);
gl_Position = gl_ProjectionMatrix * ECposition; EmitVertex( );
Computer Graphics
for( int is = 0; is < nums; is++ ) {
}
ProduceVertex( s_bot, t_bot ); EndPrimitive( );
t_top = t_bot; t_bot -= dt;
7
V0
Level = 2 V1 numLayers = 4
Time
uniform int uLevel; uniform float uGravity; uniform float uTime; uniform float uVelScale;
Level = 0
Level = 2
Level = 2
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
29
30
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
31
32
V2
Another Example: Explosion
Example: Explosion
Example: Sphere Subdivision with One triangle
29
Example: Sphere Subdivision with the Whole Sphere (8 triangles) 30 Level = 0
1. Breakthetrianglesintopoints
vec3 V0, V01, V02; vec3 CG;
xxvt 0x
Time
2. Treateachpoint’sdistancefromthetriangle’s CG as an initial velocity
void
ProduceVertex( float s, float t ) {
3. Followthelawsofprojectilemotion:
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();
yy vt at2 0y2y
}
1
Time
Level = 1
Level = 1
Level = 3
Level = 3
31
32
explode.geom
#version 330 compatibility
#extension GL_EXT_gpu_shader4: enable #extension GL_EXT_geometry_shader4: enable layout( triangles ) in;
layout( points, max_vertices=200 ) out;
8
explode.geom
Example: Explosion
Example: Explosion
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
33
34
void main( ) {
}
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++ ) {
t -= dt; }
ProduceVertex( s, t );
s += ds; }
2 13
silh.glib
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
35
36
04 5
Vertex silh.vert
Geometry silh.geom
Fragment silh.frag
Program Silhouette uColor { 0. 1. 0. 1. }
Another Example: Silhouettes
Example: Silhouettes
1. 2.
Compute the normals of each of the four triangles
ObjAdj bunny.obj
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.
33
34
35
36
Obj bunny.obj
9
silh.vert
#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( )
{
2 13
silh.frag
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
37
38
silh.geom
Example: Silhouettes
} C}omputer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
39
40
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;
}
uniform vec4 uColor;
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 );
// the center triangle’s normal
void main( ) {
if( dot( N042, N021 ) < 0. )
N021 = vec3(0.,0.,0.) - N021;
// make sure each outer triangle’s
// normal is in the same general direction
}
if( N042.z * N021.z <= 0. ) {
}
}
Example: Silhouettes
silh.geom Example: Silhouettes
gl_Position = gl_ModelViewMatrix * gl_Vertex;
04 5
gl_FragColor = vec4( uColor.rgb, 1. );
gl_Position = gl_ProjectionMatrix * vec4( V0, 1. ); EmitVertex( );
gl_Position = gl_ProjectionMatrix * vec4( V2, 1. ); EmitVertex( );
2 13
EndPrimitive( );
if( N042.z * N243.z <= 0. ) {
04 5
gl_Position = gl_ProjectionMatrix * vec4( V2, 1. ); EmitVertex( );
gl_Position = gl_ProjectionMatrix * vec4( V4, 1. ); EmitVertex( );
EndPrimitive( );
if( N042.z * N405.z <= 0. ) {
gl_Position = gl_ProjectionMatrix * vec4( V4, 1. ); EmitVertex( );
gl_Position = gl_ProjectionMatrix * vec4( V0, 1. ); EmitVertex( );
EndPrimitive( );
37
38
39
Example: Bunny Silhouettes
40
if( dot( N042, N243 ) < 0. )
N243 = vec3(0.,0.,0.) - N243;
if( dot( N042, N405 ) < 0. )
N405 = vec3(0.,0.,0.) - N405;
10
Computer Graphics
Computer Graphics
EndPrimitive( ); }
41
42
Computer Graphics
mjb – January 2, 2021
Computer Graphics
mjb – January 2, 2021
43
44
void main( ) {
float dt = 1. / float( numLayers ); float t = 1.;
for( int it = 0; it <= numLayers; it++ ) {
Another Example: Hedgehog Plots
41
hedgehog.geom, I
42
hedgehog.geom, II
43
hedgehog.geom, III
44
V0 =
V01 = ( gl_PositionIn[1] - V02 = ( gl_PositionIn[2] - Norm[0] = vTnorm[0]; Norm[1] = vTnorm[1]; Norm[2] = vTnorm[2];
gl_PositionIn[0];
if( dot( Norm[0], Norm[1] Norm[1] = -Norm[1]; if( dot( Norm[0], Norm[2] Norm[2] = -Norm[2];
) < 0. ) ) < 0. )
float s = 0.; for(intis=0;is