在Vulkan与OpenGL中重建深度编码图像中的场景

时间:2017-01-25 01:41:18

标签: c++ opengl vulkan

我正在将一段OpenGL代码翻译成Vulkan。代码使用编码的深度信息从图像(在半球投影上)重新创建渲染场景。请注意,我还加载用于投影的模型视图矩阵以重新创建场景。翻译非常简单,但由于新的Vulkan坐标系,我遇到了问题。

带有注释的原始OpenGL着色器如下:

#version 430

layout (triangles) in;
layout (triangle_strip,  max_vertices = 3) out;

in vec2 posGeom[];

out vec2 texCoord;

uniform mat4 view;
uniform mat4 projection;
uniform float threshold;
uniform vec3 quantization;
uniform mat4 inverseStaticView;
uniform sampler2D rgbdTexture;

//get the image space for each pixel of our hemisphere image
vec3 getSphereRay(const vec2 coord) {
    //get length of ray from camera to point on image plane
    float len = 1 - coord.x * coord.x - coord.y * coord.y;
    if (len > 0)
        return vec3(coord, -sqrt(len));//scale to unit length vector as viewing ray
    else
        return vec3(0);
}
vec4 getPosition(const in vec2 inCoord, const in float depth) {
    vec2 coord = inCoord;
    //reverse the stretching from sphere to quad (based on y-coordinate)
    float percent = sqrt(1.0 - coord.y * coord.y);
    coord.x = coord.x * percent;

    //scale ray with corresponding depth
    vec3 normal = getSphereRay(coord) * depth;
    //move from image space to world space by inverse view matrix
    return inverseStaticView * vec4(normal, 1);
}

bool hasZeroDepth = false;

//get the real depth from quantized and packed depth by inverting the gamma correction and inverting min, max
float getDepth(int idx) {
    float depth = texture(rgbdTexture, posGeom[idx] * 0.5 + 0.5).w;
    if(depth == 0)
        hasZeroDepth = true;
    float minDepth = quantization.x;
    float maxDepth = quantization.y;
    float gamma = quantization.z;
    depth = pow(depth, gamma);
    depth = depth * (maxDepth - minDepth) + minDepth;

    return depth;
}


//emit the position and texcoord
void emitPosition(int idx, float depth) {
    texCoord = posGeom[idx] * 0.5 + 0.5;
    gl_Position = projection * view * getPosition(posGeom[idx], depth);
    EmitVertex();
}


void main() {
    float d0 = getDepth(0);
    float d1 = getDepth(1);
    float d2 = getDepth(2);

    //do not emit tris with zero (invalid) depth
    if(!hasZeroDepth) {
        float minDepth = min(d0, min(d1, d2));
        float maxDepth = max(d0, max(d1, d2));
        float minDist = maxDepth - minDepth;

        float avgDepth = (d0 + d1 + d2) / 3;

        float thres = threshold;
        //look at tri stretching factor
        if(minDist / avgDepth < thres) {
            //emit original tri
            emitPosition(0, d0);
            emitPosition(1, d1);
            emitPosition(2, d2);
        } else {
            //emit tri with maxDepth to only show background
            emitPosition(0, maxDepth);
            emitPosition(1, maxDepth);
            emitPosition(2, maxDepth);
        }
    }
}

在Vulkan着色器中,我通过反转y值来说明Vulkan坐标系。我也必须将世界价值观正常化,原因我不清楚(否则所呈现的内容完全是无稽之谈)。着色器代码如下:

#version 450

layout (triangles) in;
layout (triangle_strip,  max_vertices = 3) out;

layout(binding = 0) uniform UniformBufferObject {
    mat4 modelView;
    mat4 inverseStaticModelView;
    float quantization;
} ubo;

layout(binding = 1) uniform sampler2D texSampler;

layout(location = 0) in vec2 posGeom[];

layout(location = 0) out vec2 texCoord;

bool hasZeroDepth = false;
float minDepth = 0;
float maxDepth = 1.0;

vec3 unproject(vec2 win) {
    float scale = 1 - win.y * win.y;
    // Invert y to account for Vulkan coordinate system.
    float y = win.y * -1;
    // Scale x to account for hemisphere projection.
    float x = win.x * scale;
    float z = -sqrt(1 - x * x - y * y); 
    if(z < 0){
        vec4 outVals = ubo.inverseStaticModelView * vec4(x, y, z, 1.0);
        return vec3(outVals[0], outVals[1], outVals[2]) / outVals.w;
    }else
        return vec3(0);

}

vec3 reconstructWorldPosition(vec2 ndc, float depth) {
    vec3 pos = unproject(ndc);
    return depth * normalize(pos);
}

float getDepth(int idx) {
    float depth = texture(texSampler, posGeom[idx] * 0.5 + 0.5).w;
    if(depth == 0)
        hasZeroDepth = true;

    depth = pow(depth, ubo.quantization);
    return depth;
}

void emitPosition(int idx, float depth) {
    vec2 pos = posGeom[idx].xy;
    texCoord = pos * 0.5 + 0.5;

    vec3 positionFromDepth = reconstructWorldPosition(pos, depth);
    gl_Position = ubo.modelView * vec4(positionFromDepth,1);
    EmitVertex();
}

void main() {
    float d0 = getDepth(0);
    float d1 = getDepth(1);
    float d2 = getDepth(2);

    if(!hasZeroDepth) {
        float minDepth = min(d0, min(d1, d2));
        float maxDepth = max(d0, max(d1, d2));
        float minDist = maxDepth - minDepth;

        float avgDepth = (d0 + d1 + d2) / 3.0;

        float thres = 0.1;

        if(minDist / avgDepth < thres ) {
            emitPosition(0, d0);
            emitPosition(1, d1);
            emitPosition(2, d2);
        } else {
            emitPosition(0, maxDepth);
            emitPosition(1, maxDepth);
            emitPosition(2, maxDepth);
        }
    }
}

这两个节目的输出图像包含在这张专辑中:http://imgur.com/a/KUl57

Vulkan输出似乎几乎是正确的,除了场景左下角的一些奇怪的伪像。我怀疑是缩放到x坐标以解释半球投影是导致问题的原因。我已经玩过缩放和着色器的其他部分,但我似乎无法做到正确。我是否忽略了Vulkan和OpenGL之间的其他不同之处,特别是在坐标系方面?

0 个答案:

没有答案
相关问题