I'm using Vulkan (GTX 980), and I have this fragment shader:
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout (location = 0) in vec4 inColor;
layout (location = 0) out vec4 outFragColor;
void main() {
outFragColor = inColor;
gl_FragDepth = gl_FragCoord.z / gl_FragCoord.w;
}
but I noticed that the depth buffer wasn't working quite right, so I added:
if (gl_FragCoord.z == 0) {
discard;
}
and sure enough, nothing draws. Even if I do this in the geometry shader
gl_Position.z = 0.5;
EmitVertex();
gl_FragCoord.z
still comes back as zero. The x, y and w values seem fine (they're non-zero). If I don't set gl_FragDepth
at all, it seems to not default to anything (the output flickers, so I'm assuming garbage values).
For reference, this is my geometry shader. It creates narrow conic sections to represent the directions of a vector field.
#version 450
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
#define FACE_COUNT 16
#define PI 3.14159265
layout (points) in;
layout (triangle_strip, max_vertices = FACE_COUNT * 2 * 3) out;
layout (location = 0) in vec4 inPos[1];
layout (location = 0) out vec4 outColor;
layout (push_constant) uniform constants_t {
mat4x4 world;
mat4x4 projection;
vec4 boundsMin;
vec4 boundsMax;
uvec4 resolution;
float arrowSize;
} constants;
vec4 m(vec4 pos, mat4x4 matrix) {
pos.w = 1.0;
return matrix * pos;
}
vec4 transform(vec3 pos) {
vec4 temp = vec4(pos, 1);
temp = m(temp, constants.world);
temp = m(temp, constants.projection);
return temp;
}
vec3 demux() {
uint temp = gl_PrimitiveIDIn;
float xIndex = mod(temp, constants.resolution.x);
temp /= constants.resolution.x;
float yIndex = mod(temp, constants.resolution.y);
temp /= constants.resolution.y;
float zIndex = temp;
vec3 centeringOffset = vec3(.5);
return (vec3(xIndex, yIndex, zIndex) + centeringOffset) / constants.resolution.xyz * (constants.boundsMax - constants.boundsMin).xyz + constants.boundsMin.xyz;
}
// light a triangle based on surface normal and return color
vec4 light(vec3 a, vec3 b, vec3 c, vec4 color) {
vec3 normal = cross(normalize(b - a), normalize(c - a));
float upness = (normal.y + 1) * 0.5;
float lightenRange = 0.1;
float lighten = max(0, upness - 1 + lightenRange) / lightenRange;
float downness = 1.0 - upness;
float darkenRange = 0.4;
float darken = max(0, downness - 1 + darkenRange) / darkenRange;
return (color + vec4(0.5) * lighten) * (1 - darken * 0.5);
}
void draw(vec3 a, vec3 b, vec3 c, vec4 color) {
outColor = light(a, b, c, color);
gl_Position = transform(a);
EmitVertex();
gl_Position = transform(b);
EmitVertex();
gl_Position = transform(c);
EmitVertex();
EndPrimitive();
}
void main(void)
{
// world position of arrow base
vec3 base = demux();
// direction of arrow
vec3 forward = inPos[0].xyz;
float horizontalLen = length(forward.xz);
// a direction "right" of forward
vec3 right = horizontalLen > 0.00001 ? normalize(vec3(forward.z, 0, -forward.x)) : vec3(1, 0, 0);
// a direction "up" of forward
vec3 up = normalize(cross(forward.xyz, right.xyz));
// world position of arrow tip
vec3 tip = base + forward * constants.arrowSize * 10;
// populate world positions of "rim" vertices
vec3 pos[FACE_COUNT];
for (int i = 0; i < FACE_COUNT; ++i) {
float theta = i * PI * 2 / FACE_COUNT;
pos[i] = base + (up * cos(theta) + right * sin(theta)) * constants.arrowSize;
}
for (int i = 0; i < FACE_COUNT; ++i) {
int j = (i + 1) % FACE_COUNT;
draw(pos[i], pos[j], tip, vec4(1, 0, 0, 1));
draw(pos[j], pos[i], base, vec4(0, 1, 0, 1));
}
}