Qt 3D: Wireframe QML Example▲
Sélectionnez
#version 330 core
layout( triangles ) in;
layout( triangle_strip, max_vertices =
3
) out;
in EyeSpaceVertex {
vec3 position;
vec3 normal;
}
gs_in[];
out WireframeVertex {
vec3 position;
vec3 normal;
noperspective vec4 edgeA;
noperspective vec4 edgeB;
flat int
configuration;
}
gs_out;
uniform mat4 viewportMatrix;
const
int
infoA[] =
int
[]( 0
, 0
, 0
, 0
, 1
, 1
, 2
);
const
int
infoB[] =
int
[]( 1
, 1
, 2
, 0
, 2
, 1
, 2
);
const
int
infoAd[] =
int
[]( 2
, 2
, 1
, 1
, 0
, 0
, 0
);
const
int
infoBd[] =
int
[]( 2
, 2
, 1
, 2
, 0
, 2
, 1
);
vec2 transformToViewport( const
in vec4 p )
{
return
vec2( viewportMatrix *
( p /
p.w ) );
}
void
main()
{
gs_out.configuration =
int
(gl_in[0
].gl_Position.z &
lt; 0
) *
int
(4
)
+
int
(gl_in[1
].gl_Position.z &
lt; 0
) *
int
(2
)
+
int
(gl_in[2
].gl_Position.z &
lt; 0
);
// If all vertices are behind us, cull the primitive
if
(gs_out.configuration ==
7
)
return
;
// Transform each vertex into viewport space
vec2 p[3
];
p[0
] =
transformToViewport( gl_in[0
].gl_Position );
p[1
] =
transformToViewport( gl_in[1
].gl_Position );
p[2
] =
transformToViewport( gl_in[2
].gl_Position );
if
(gs_out.configuration ==
0
)
{
// Common configuration where all vertices are within the viewport
gs_out.edgeA =
vec4(0.0
);
gs_out.edgeB =
vec4(0.0
);
// Calculate lengths of 3 edges of triangle
float
a =
length( p[1
] -
p[2
] );
float
b =
length( p[2
] -
p[0
] );
float
c =
length( p[1
] -
p[0
] );
// Calculate internal angles using the cosine rule
float
alpha =
acos( ( b *
b +
c *
c -
a *
a ) /
( 2.0
*
b *
c ) );
float
beta =
acos( ( a *
a +
c *
c -
b *
b ) /
( 2.0
*
a *
c ) );
// Calculate the perpendicular distance of each vertex from the opposing edge
float
ha =
abs( c *
sin( beta ) );
float
hb =
abs( c *
sin( alpha ) );
float
hc =
abs( b *
sin( alpha ) );
// Now add this perpendicular distance as a per-vertex property in addition to
// the position and normal calculated in the vertex shader.
// Vertex 0 (a)
gs_out.edgeA =
vec4( ha, 0.0
, 0.0
, 0.0
);
gs_out.normal =
gs_in[0
].normal;
gs_out.position =
gs_in[0
].position;
gl_Position =
gl_in[0
].gl_Position;
EmitVertex();
// Vertex 1 (b)
gs_out.edgeA =
vec4( 0.0
, hb, 0.0
, 0.0
);
gs_out.normal =
gs_in[1
].normal;
gs_out.position =
gs_in[1
].position;
gl_Position =
gl_in[1
].gl_Position;
EmitVertex();
// Vertex 2 (c)
gs_out.edgeA =
vec4( 0.0
, 0.0
, hc, 0.0
);
gs_out.normal =
gs_in[2
].normal;
gs_out.position =
gs_in[2
].position;
gl_Position =
gl_in[2
].gl_Position;
EmitVertex();
// Finish the primitive off
EndPrimitive();
}
else
{
// Viewport projection breaks down for one or two vertices.
// Caclulate what we can here and defer rest to fragment shader.
// Since this is coherent for the entire primitive the conditional
// in the fragment shader is still cheap as all concurrent
// fragment shader invocations will take the same code path.
// Copy across the viewport-space points for the (up to) two vertices
// in the viewport
gs_out.edgeA.xy =
p[infoA[gs_out.configuration]];
gs_out.edgeB.xy =
p[infoB[gs_out.configuration]];
// Copy across the viewport-space edge vectors for the (up to) two vertices
// in the viewport
gs_out.edgeA.zw =
normalize( gs_out.edgeA.xy -
p[ infoAd[gs_out.configuration] ] );
gs_out.edgeB.zw =
normalize( gs_out.edgeB.xy -
p[ infoBd[gs_out.configuration] ] );
// Pass through the other vertex attributes
gs_out.normal =
gs_in[0
].normal;
gs_out.position =
gs_in[0
].position;
gl_Position =
gl_in[0
].gl_Position;
EmitVertex();
gs_out.normal =
gs_in[1
].normal;
gs_out.position =
gs_in[1
].position;
gl_Position =
gl_in[1
].gl_Position;
EmitVertex();
gs_out.normal =
gs_in[2
].normal;
gs_out.position =
gs_in[2
].position;
gl_Position =
gl_in[2
].gl_Position;
EmitVertex();
// Finish the primitive off
EndPrimitive();
}
}