//pref
Ambient|float|0.0|0.5|1
Diffuse|float|0.0|0.7|1
Specular|float|0.0|0.2|1
Shininess|float|1|60|120
GapSize|float|0.0|0.5|1.0
BackfaceType|int|0|2|2
Disks|bool|true
BackfaceType: 0=none, 1=gaps, 2=solid. Copyright 2018 Chris Rorden, BSD2clause.|note
//vert
#version 330
layout(location = 0) in vec3 Vert;
layout(location = 3) in vec3 Norm;
layout(location = 6) in vec4 Clr;
out vec3 vN, vL, vV;
out vec4 vPmvp, vClr, vP;
uniform mat4 ModelViewProjectionMatrix;
uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform vec3 LightPos = vec3(0.0, 20.0, 30.0); //LR, -DU+, -FN+
void main() {
    vN = normalize((NormalMatrix * Norm));
    vP = vec4(Vert, 1.0);
    gl_Position = ModelViewProjectionMatrix * vec4(Vert, 1.0);
    vPmvp = gl_Position;
    vL = normalize(LightPos);
    vV = -vec3(ModelViewMatrix*vec4(Vert,1.0));
    vClr = Clr;
}
//geom
#version 330

in vec3 vL[3], vN[3], vV[3];
in vec4 vP[3], vPmvp[3], vClr[3];
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

out vec3 gE, gL, gN, gV;
out vec4 gP, gClr;

void main(void) {
    for(int i=0; i < 3; i++) {
    	gl_Position = vPmvp[i];
    	if (i == 0)
    		gE = vec3(1.0, 0.0, 0.0);
    	else if (i == 1)
    		gE = vec3(0.0, 1.0, 0.0);
    	else
    		gE = vec3(0.0, 0.0, 1.0);
    	gL = vL[i];
    	gN = vN[i];
    	gV = vV[i];
    	gP = vP[i];
    	gClr = vClr[i];
        EmitVertex();
    }
    EndPrimitive();
}
//frag
#version 330
uniform float Ambient, Diffuse, Specular, Shininess, GapSize;
uniform int BackfaceType = 0;
uniform bool Disks = true;
uniform vec4 ClipPlane;
in vec3 gE, gL, gN, gV;
in vec4 gP, gClr;
out vec4 color;

vec3 desaturate(vec3 color, float amount) {
    vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), color));
    return vec3(mix(color, gray, amount));
}

void main() {
	if ((ClipPlane[0] < 1.5) && (dot( ClipPlane, gP) > 0.0)) discard;
	vec3 n = normalize(gN);
	float backface = step(0.0, n.z); //1=backface
	if ((BackfaceType == 0) && (backface < 0.5)) discard;
	//float e = mix(1.0-max(max(gE.x, gE.y), gE.z), length(gE), float(Disks));
	//float sz = mix((GapSize * 0.48) + 0.2, (GapSize * 0.36) + 0.59, float(Disks));

	//float e = mix(1.0 - min(min(gE.x, gE.y), gE.z), length(gE), float(Disks));
	//float sz = mix((GapSize * 0.3) + 0.7, (GapSize * 0.36) + 0.59, float(Disks));
	float e = mix( ((1.0-min(min(gE.x, gE.y), gE.z))-0.67) * 3.0 ,pow( max(length(gE)-0.59,0.0) * 2.4, 0.5), float(Disks));
	//float sz = mix((GapSize * 0.5) + 0.5, (GapSize * 0.36) + 0.59, float(Disks));
//float sz = (GapSize * 0.5) + 0.5;

float sz = GapSize;
	if ((backface > 0.5) && (e > sz))  discard;
	if ((BackfaceType == 1) && (e > sz))  discard;
	n = mix(-n, n, backface ); //reverse normal if backface AND two-sided lighting
	vec3 l = normalize(gL);
	vec3 h = normalize(l+normalize(gV));
	vec3 a = gClr.rgb;
	vec3 d = a * Diffuse;
	a *= Ambient;
	d *= max(dot( l, n), 0.0);
	float s = pow(max(0.0,dot(n,h)), Shininess) * Specular;
	vec4 face = vec4(a + d + s, 1.0);
	vec3 backcolor = desaturate(face.rgb, 0.7) * 0.7; //desaturate and darken backface
	face.rgb = mix(backcolor.rgb, face.rgb,  backface);
	color = face;
}
