diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 0bb383af430..17bf77f9320 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -157,6 +157,8 @@ data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_smooth_vert.glsl SRC) data_to_c_simple(shaders/gpu_shader_2D_point_uniform_size_outline_smooth_vert.glsl SRC) 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_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) diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index e19588a5b1b..aead5baaaf1 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -90,7 +90,10 @@ typedef enum GPUBuiltinShader { GPU_SHADER_SMOKE = 2, GPU_SHADER_SMOKE_FIRE = 3, + /* specialized drawing */ GPU_SHADER_TEXT, + GPU_SHADER_EDGES_FRONT_BACK_PERSP, + GPU_SHADER_EDGES_FRONT_BACK_ORTHO, /* for simple 2D drawing */ GPU_SHADER_2D_UNIFORM_COLOR, diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 21fd5385f79..6b6cdfb5ae5 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -77,6 +77,8 @@ extern char datatoc_gpu_shader_2D_point_uniform_size_smooth_vert_glsl[]; 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_ortho_vert_glsl[]; extern char datatoc_gpu_shader_text_vert_glsl[]; extern char datatoc_gpu_shader_text_frag_glsl[]; @@ -105,8 +107,10 @@ static struct GPUShadersGlobal { GPUShader *smoke_fire; /* cache for shader fx. Those can exist in combinations so store them here */ GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; - /* for drawing text */ + /* specialized drawing */ GPUShader *text; + GPUShader *edges_front_back_persp; + GPUShader *edges_front_back_ortho; /* for drawing images */ GPUShader *image_modulate_alpha_3D; GPUShader *image_rect_modulate_alpha_3D; @@ -656,6 +660,22 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) NULL, NULL, NULL, 0, 0, 0); retval = GG.shaders.text; 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_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.edges_front_back_persp; + break; + case GPU_SHADER_EDGES_FRONT_BACK_ORTHO: + if (!GG.shaders.edges_front_back_ortho) + GG.shaders.edges_front_back_ortho = GPU_shader_create( + datatoc_gpu_shader_edges_front_back_ortho_vert_glsl, + datatoc_gpu_shader_flat_color_frag_glsl, + NULL, NULL, NULL, 0, 0, 0); + retval = GG.shaders.edges_front_back_ortho; + break; case GPU_SHADER_3D_IMAGE_MODULATE_ALPHA: if (!GG.shaders.image_modulate_alpha_3D) GG.shaders.image_modulate_alpha_3D = GPU_shader_create( @@ -938,6 +958,16 @@ void GPU_shader_free_builtin_shaders(void) GG.shaders.text = NULL; } + if (GG.shaders.edges_front_back_persp) { + GPU_shader_free(GG.shaders.edges_front_back_persp); + GG.shaders.edges_front_back_persp = NULL; + } + + if (GG.shaders.edges_front_back_ortho) { + GPU_shader_free(GG.shaders.edges_front_back_ortho); + GG.shaders.edges_front_back_ortho = NULL; + } + if (GG.shaders.image_modulate_alpha_3D) { GPU_shader_free(GG.shaders.image_modulate_alpha_3D); GG.shaders.image_modulate_alpha_3D = NULL; diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl new file mode 100755 index 00000000000..0648bf18f99 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_ortho_vert.glsl @@ -0,0 +1,64 @@ + +// Draw "fancy" wireframe, displaying front-facing, back-facing and +// silhouette lines differently. +// Mike Erwin, April 2015 + +uniform bool drawFront = true; +uniform bool drawBack = true; +uniform bool drawSilhouette = true; + +uniform vec4 frontColor; +uniform vec4 backColor; +uniform vec4 silhouetteColor; + +uniform vec4 eye; // direction we are looking + +uniform mat4 ModelViewProjectionMatrix; + +#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 both endpoints to nowhere +// and it won't produce any fragments +const vec4 nowhere = vec4(vec3(0.0), 1.0); + +void main() +{ + bool face_1_front = dot(N1, eye) > 0.0; + bool face_2_front = dot(N2, eye) > 0.0; + + vec4 position = ModelViewProjectionMatrix * vec4(pos, 1.0); + + if (face_1_front && face_2_front) { + // front-facing edge + gl_Position = drawFront ? position : nowhere; + finalColor = frontColor; + } + else if (face_1_front || face_2_front) { + // exactly one face is front-facing, silhouette edge + gl_Position = drawSilhouette ? position : nowhere; + finalColor = silhouetteColor; + } + else { + // back-facing edge + gl_Position = drawBack ? position : nowhere; + finalColor = backColor; + } +} diff --git a/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl new file mode 100755 index 00000000000..baf69c3e272 --- /dev/null +++ b/source/blender/gpu/shaders/gpu_shader_edges_front_back_persp_vert.glsl @@ -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; + } +}