v22
v22

Reputation: 87

Weird artifacts when rendering with Vulkan

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:

enter image description here

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

Answers (1)

Sascha Willems
Sascha Willems

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

Related Questions