Reputation: 87
So i made a vulkan renderer which uses instanced triangles to render the scene. As you can see in the image below, there are random artifacts all over the screen:
This would be the vertex shader:
#version 460
#extension GL_EXT_scalar_block_layout : enable
precision highp float;
struct Transform {
vec2 translation;
vec2 origin;
vec2 scale;
float rotation;
int _align;
};
struct Triangle {
Transform transform;
Transform canvasTransform;
vec4 colors[3];
vec2 points[3];
vec2 texCoords[3];
float z;
float texId;
float blending;
int _align;
};
layout(location = 0) out vec2 outTexCoord;
layout(location = 1) out vec4 outColor;
layout(location = 2) out float outTexId;
layout(location = 3) out float outBlending;
layout(set = 0, binding = 0) uniform Matrices {
mat4 view;
mat4 proj;
vec2 screenSize;
} mat;
layout(set = 1, binding = 0, scalar) readonly buffer ObjectUbo {
Triangle triangles[];
} triangles;
void main() {
Triangle tri = triangles.triangles[gl_InstanceIndex];
vec2 pos = tri.points[gl_VertexIndex];
Transform transform = tri.transform;
Transform canvasTransform = tri.canvasTransform;
mat2 rot;
rot[0] = vec2(cos(transform.rotation), 0 - sin(transform.rotation));
rot[1] = vec2(sin(transform.rotation), cos(transform.rotation));
pos -= transform.origin;
pos = rot * (pos * transform.scale);
pos += transform.origin;
mat2 canvasRot;
canvasRot[0] = vec2(cos(canvasTransform.rotation), 0 - sin(canvasTransform.rotation));
canvasRot[1] = vec2(sin(canvasTransform.rotation), cos(canvasTransform.rotation));
pos -= canvasTransform.origin;
pos = canvasRot * (pos * canvasTransform.scale);
pos += canvasTransform.origin;
pos = pos + canvasTransform.translation + transform.translation;
gl_Position = mat.proj * mat.view * vec4(pos, tri.z, 1.0);
outTexCoord = tri.texCoords[gl_VertexIndex];
outColor = tri.colors[gl_VertexIndex];
outTexId = tri.texId;
outBlending = tri.blending;
}
and fragment shader:
#version 420
#extension GL_EXT_nonuniform_qualifier : enable
layout(location = 0) out vec4 outColor;
layout(location = 0) in vec2 inTexCoords;
layout(location = 1) in vec4 inColor;
layout(location = 2) in float texId;
layout(location = 3) in float blending;
layout(set = 2, binding = 0) uniform sampler2D textures[];
layout(set = 2, binding = 1) uniform sampler2D fonts[];
float screenPxRange(sampler2D texture) {
const float pxRange = 2.0f;
vec2 unitRange = vec2(pxRange) / vec2(textureSize(texture, 0));
vec2 screenTexSize = vec2(1.0) / fwidth(inTexCoords);
return max(0.5 * dot(unitRange, screenTexSize), 1.0);
}
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
int iTexId = int(texId);
if (blending < 0.0f) {
// font
vec3 msd = texture(fonts[iTexId], inTexCoords).rgb;
float sd = median(msd.r, msd.g, msd.b);
float screenPxDistance = screenPxRange(fonts[iTexId]) * (sd - 0.5);
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
if (opacity <= 0) discard;
outColor = vec4(vec3(1.0f), opacity);
}
else {
// no font
outColor = iTexId == -1 ? inColor : mix(texture(textures[iTexId], inTexCoords), inColor, blending);
}
}
By the way, the fragments change across the whole screen, when something is rendered differently (i.e. moving the camera around).
Upvotes: 1
Views: 57
Reputation: 5808
Your texture access is non-uniform. To avoid the artifacts you see, you need to let the implementation know that you do non-uniform access by enabling the shaderSampledImageArrayNonUniformIndexing
feature from the VK_EXT_descriptor_indexing
extension in your application, the GL_EXT_nonuniform_qualifier
extension in your shader (which you already do) and then (which you don't yet do) surround your texture indexing with the non-uniform qualifier.
So
texture(textures[iTexId]
becomes
texture(textures[nonuniformEXT(iTexId)]
Upvotes: 3