OpenGL: further wireframe shaders

As seen at #bcon16

Geometry shader version is automatically used on modern GL runtimes. Legacy version is used on pre-3.2 systems (Mac, Mesa compat profile). They have the same inputs and visual result.

TODO: specialized versions that are less flexible -- draw ALL edges or draw JUST silhouette edges.

Part of T49165
This commit is contained in:
Mike Erwin 2016-11-05 18:56:57 +01:00
parent c25c3bb6cb
commit a85f68e9c7
5 changed files with 175 additions and 57 deletions

View File

@ -159,6 +159,8 @@ data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.gl
data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_geom.glsl SRC)
data_to_c_simple(shaders/gpu_shader_edges_front_back_persp_legacy_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_edges_front_back_ortho_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_text_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_text_frag.glsl SRC)

View File

@ -79,6 +79,8 @@ extern char datatoc_gpu_shader_2D_point_uniform_size_outline_smooth_vert_glsl[];
extern char datatoc_gpu_shader_2D_point_uniform_size_varying_color_outline_smooth_vert_glsl[];
extern char datatoc_gpu_shader_edges_front_back_persp_vert_glsl[];
extern char datatoc_gpu_shader_edges_front_back_persp_geom_glsl[];
extern char datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl[];
extern char datatoc_gpu_shader_edges_front_back_ortho_vert_glsl[];
extern char datatoc_gpu_shader_text_vert_glsl[];
extern char datatoc_gpu_shader_text_frag_glsl[];
@ -671,10 +673,20 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
break;
case GPU_SHADER_EDGES_FRONT_BACK_PERSP:
if (!GG.shaders.edges_front_back_persp)
GG.shaders.edges_front_back_persp = GPU_shader_create(
datatoc_gpu_shader_edges_front_back_persp_vert_glsl,
datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl,
NULL, NULL, NULL, 0, 0, 0);
if (GLEW_VERSION_3_2) {
/* this version is magical but slooow */
GG.shaders.edges_front_back_persp = GPU_shader_create(
datatoc_gpu_shader_edges_front_back_persp_vert_glsl,
datatoc_gpu_shader_flat_color_frag_glsl,
datatoc_gpu_shader_edges_front_back_persp_geom_glsl,
NULL, NULL, 0, 0, 0);
}
else {
GG.shaders.edges_front_back_persp = GPU_shader_create(
datatoc_gpu_shader_edges_front_back_persp_legacy_vert_glsl,
datatoc_gpu_shader_flat_color_alpha_test_0_frag_glsl,
NULL, NULL, NULL, 0, 0, 0);
}
retval = GG.shaders.edges_front_back_persp;
break;
case GPU_SHADER_EDGES_FRONT_BACK_ORTHO:

View File

@ -0,0 +1,60 @@
// Draw "fancy" wireframe, displaying front-facing, back-facing and
// silhouette lines differently.
// Mike Erwin, April 2015
// After working with this shader a while, convinced we should make
// separate shaders for perpective & ortho. (Oct 2016)
// Due to perspective, the line segment's endpoints might disagree on
// whether the adjacent faces are front facing. This geometry shader
// decides which edge type to use if endpoints disagree.
uniform mat4 ProjectionMatrix;
uniform bool drawFront = true;
uniform bool drawBack = true;
uniform bool drawSilhouette = true;
uniform vec4 frontColor;
uniform vec4 backColor;
uniform vec4 silhouetteColor;
layout(lines) in;
layout(line_strip, max_vertices = 2) out;
in vec4 MV_pos[];
in float edgeClass[];
flat out vec4 finalColor;
void emitLine(vec4 color)
{
gl_Position = ProjectionMatrix * MV_pos[0];
EmitVertex();
gl_Position = ProjectionMatrix * MV_pos[1];
finalColor = color;
EmitVertex();
EndPrimitive();
}
void main()
{
float finalEdgeClass = max(edgeClass[0], edgeClass[1]);
if (finalEdgeClass > 0.0f) {
// front-facing edge
if (drawFront)
emitLine(frontColor);
}
else if (finalEdgeClass < 0.0f) {
// back-facing edge
if (drawBack)
emitLine(backColor);
}
else {
// exactly one face is front-facing, silhouette edge
if (drawSilhouette)
emitLine(silhouetteColor);
}
}

View File

@ -0,0 +1,78 @@
// Draw "fancy" wireframe, displaying front-facing, back-facing and
// silhouette lines differently.
// Mike Erwin, April 2015
// After working with this shader a while, convinced we should make
// separate shaders for perpective & ortho. (Oct 2016)
// This shader is an imperfect stepping stone until all platforms are
// ready for geometry shaders.
// Due to perspective, the line segment's endpoints might disagree on
// whether the adjacent faces are front facing. Need to use a geometry
// shader or pass in an extra position attribute (the other endpoint)
// to do this properly.
uniform bool drawFront = true;
uniform bool drawBack = true;
uniform bool drawSilhouette = true;
uniform vec4 frontColor;
uniform vec4 backColor;
uniform vec4 silhouetteColor;
uniform mat4 ModelViewMatrix;
uniform mat4 ModelViewProjectionMatrix;
uniform mat3 NormalMatrix;
#if __VERSION__ == 120
attribute vec3 pos;
// normals of faces this edge joins (object coords)
attribute vec3 N1;
attribute vec3 N2;
flat varying vec4 finalColor;
#else
in vec3 pos;
// normals of faces this edge joins (object coords)
in vec3 N1;
in vec3 N2;
flat out vec4 finalColor;
#endif
// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley
// to discard an entire line, set its color to invisible
// (must have GL_BLEND enabled, or discard in fragment shader)
const vec4 invisible = vec4(0.0);
bool front(vec3 N)
{
vec4 xformed = ModelViewMatrix * vec4(pos, 1.0);
return dot(NormalMatrix * N, normalize(-xformed.xyz)) > 0.0;
}
void main()
{
bool face_1_front = front(N1);
bool face_2_front = front(N2);
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
if (face_1_front && face_2_front) {
// front-facing edge
finalColor = drawFront ? frontColor : invisible;
}
else if (face_1_front || face_2_front) {
// exactly one face is front-facing, silhouette edge
finalColor = drawSilhouette ? silhouetteColor : invisible;
}
else {
// back-facing edge
finalColor = drawBack ? backColor : invisible;
}
}

View File

@ -6,73 +6,39 @@
// After working with this shader a while, convinced we should make
// separate shaders for perpective & ortho. (Oct 2016)
// This shader is an imperfect stepping stone until all platforms are
// ready for geometry shaders.
// Due to perspective, the line segment's endpoints might disagree on
// whether the adjacent faces are front facing. Need to use a geometry
// shader or pass in an extra position attribute (the other endpoint)
// to do this properly.
uniform bool drawFront = true;
uniform bool drawBack = true;
uniform bool drawSilhouette = true;
uniform vec4 frontColor;
uniform vec4 backColor;
uniform vec4 silhouetteColor;
// whether the adjacent faces are front facing. We use a geometry
// shader to resolve this properly.
uniform mat4 ModelViewMatrix;
uniform mat4 ModelViewProjectionMatrix;
uniform mat3 NormalMatrix;
#if __VERSION__ == 120
attribute vec3 pos;
in vec3 pos;
in vec3 N1, N2; // normals of faces this edge joins (object coords)
// normals of faces this edge joins (object coords)
attribute vec3 N1;
attribute vec3 N2;
flat varying vec4 finalColor;
#else
in vec3 pos;
// normals of faces this edge joins (object coords)
in vec3 N1;
in vec3 N2;
flat out vec4 finalColor;
#endif
out vec4 MV_pos;
out float edgeClass;
// TODO: in float angle; // [-pi .. +pi], + peak, 0 flat, - valley
// to discard an entire line, set its color to invisible
// (must have GL_BLEND enabled, or discard in fragment shader)
const vec4 invisible = vec4(0.0);
bool front(vec3 N)
bool front(vec3 N, vec3 eye)
{
vec4 xformed = ModelViewMatrix * vec4(pos, 1.0);
return dot(NormalMatrix * N, normalize(-xformed.xyz)) > 0.0;
return dot(NormalMatrix * N, eye) > 0.0;
}
void main()
{
bool face_1_front = front(N1);
bool face_2_front = front(N2);
MV_pos = ModelViewMatrix * vec4(pos, 1.0);
gl_Position = ModelViewProjectionMatrix * vec4(pos, 1.0);
vec3 eye = normalize(-MV_pos.xyz);
if (face_1_front && face_2_front) {
// front-facing edge
finalColor = drawFront ? frontColor : invisible;
}
else if (face_1_front || face_2_front) {
// exactly one face is front-facing, silhouette edge
finalColor = drawSilhouette ? silhouetteColor : invisible;
}
else {
// back-facing edge
finalColor = drawBack ? backColor : invisible;
}
bool face_1_front = front(N1, eye);
bool face_2_front = front(N2, eye);
if (face_1_front && face_2_front)
edgeClass = 1.0; // front-facing edge
else if (face_1_front || face_2_front)
edgeClass = 0.0; // exactly one face is front-facing, silhouette edge
else
edgeClass = -1.0; // back-facing edge
}