2017-03-06 96 views
0

我有使用SDF函数关于GLSL球体跟踪/光线跟踪一些问题:GLSL:如何使用投影矩阵计算光线方向?

我的主程序(C++,使用福尔康)生成画面四并将该顶点着色器与每顶点inPosition。顶点着色器可以访问窗口分辨率,投影矩阵和视图矩阵。投影矩阵由glm::perspective(45.0, 1920/1080, 0.1, 100.0);生成。

在顶点着色器中,我尝试通过图像平面计算从原点vec4(0.0, 0.0, 0.0, 1.0)来的光线(使用齐次坐标的位置和方向)。我很困惑放置图像平面的位置,现在选择vec4(inPosition.xy, -5.0, 1.0)来查看负Z轴。

以下代码表示我的顶点着色器:

#version 450 
#extension GL_ARB_separate_shader_objects : enable 

struct Ray 
{ 
    vec4 pos; 
    vec4 dir; 
}; 

layout(binding = 0) uniform UniformBufferObject { 
    vec3 res; 
    mat4 projection; 
    mat4 view; 
} ubo; 

layout(location = 0) in vec3 inPosition; 

layout(location = 0) out vec3 iResolution; 
layout(location = 1) out Ray iRay; 

out gl_PerVertex { 
    vec4 gl_Position; 
}; 

void main() { 
    fragCoord = vec2(
    ((inPosition.x+1)/2) * (ubo.res.x-1), 
    ((inPosition.y+1)/2) * (ubo.res.y-1) 
); 
    iResolution = ubo.res; 
    gl_Position = vec4(inPosition, 1.0); 
    vec4 direction = inverse(ubo.projection) * vec4(inPosition.xy, -5.0, 1.0); 
    iRay.dir = direction; 
    iRay.pos = vec4(direction.xy, 0.0, 1.0); 
} 

我使用的投影矩阵的方向变换到世界空间和扭曲单位立方体到窗口的分辨率。但是,在我的片段着色器中,SDF函数和交叉点无法正常工作。如果为距离和半径设置相同的值,我只能看到一个球体。看片段着色器:

#version 450 
#extension GL_ARB_separate_shader_objects : enable 

struct Ray 
{ 
    vec4 pos; 
    vec4 dir; 
}; 

layout(location = 0) in vec3 iResolution; 
layout(location = 1) in Ray iRay; 

layout(location = 0) out vec4 outColor; 

float sdfSphere(vec3 p, float r) 
{ 
    return length(p) - r; 
} 

bool intersect(Ray ray) 
{ 
    for(int i = 0; i < 100; i++) { 
    float hit = sdfSphere((ray.pos.xyz + vec3(0.0, 0.0, -11.0)), 11.0); 
    ray.pos += hit * ray.dir; 
    if (hit < 0.001) { 
     return true; 
    } 
    } 
    return false; 
} 

void main() 
{ 
    bool result = intersect(iRay); 
    if(result == false) { 
    outColor = vec4(0.0, 0.0, 0.0, 1.0); 
    } else { 
    outColor = vec4(1.0, 0.0, 0.0, 1.0); 
    } 
} 

我的问题是:如何正确应用投影矩阵?如果它已经正确应用,为什么我无法为SDF球体设置不同的位置/半径?

+1

如果你使用Vulkan,你应该这样标记而不是使用OpenGL标记。 – BDL

回答

1

这是我的代码,从片段的坐标计算世界空间中的光线。它使用一组统一变量来模拟以下代码中的旧固定功能流水线(GLUP统一变量)。棘手的部分是正确应用视口变换,并考虑到一些变量位于[-1,1]中,而其他变量位于[0,1]中(使我感到头疼)。

struct Ray { 
    vec3 O; // Origin 
    vec3 V; // Direction vector 
}; 

// Notes: GLUP.viewport = [x0,y0,width,height] 
// clip-space coordinates are in [-1,1] (not [0,1]) ! 

// Computes the ray that passes through the current fragment 
// The ray is in world space. 
Ray glup_primary_ray() { 
    vec4 near = vec4(
    2.0 * ((gl_FragCoord.x - GLUP.viewport[0])/GLUP.viewport[2] - 0.5), 
    2.0 * ((gl_FragCoord.y - GLUP.viewport[1])/GLUP.viewport[3] - 0.5), 
     0.0, 
     1.0 
    ); 
    near = GLUP.inverse_modelviewprojection_matrix * near ; 
    vec4 far = near + GLUP.inverse_modelviewprojection_matrix[2] ; 
    near.xyz /= near.w ; 
    far.xyz /= far.w ; 
    return Ray(near.xyz, far.xyz-near.xyz) ; 
} 

// Updates fragment depth from a point in world space 
void glup_update_depth(in vec3 M_world_space) { 
    vec4 M_clip_space = GLUP.modelviewprojection_matrix * vec4(M_world_space,1.0); 
    float z = 0.5*(1.0 + M_clip_space.z/M_clip_space.w); 
    glup_FragDepth = (1.0-z)*gl_DepthRange.near + z*gl_DepthRange.far; 
} 

一个例子片段着色器,吸引用glup_primary_ray()光线跟踪球:

in vec3 C; // center in world space; 
in float r; 

void main(void) { 
    Ray R = glup_primary_ray(); 
    vec3 M,N; 

    if(
    glupIsEnabled(GLUP_CLIPPING) && 
    GLUP.clipping_mode == GLUP_CLIP_SLICE_CELLS 
    ) { 
    N = GLUP.world_clip_plane.xyz; 
    float w = GLUP.world_clip_plane.w; 
    float t = -(w + dot(N,R.O))/dot(N,R.V); 
    M = R.O + t*R.V; 
    if(dot(M-C,M-C) > r*r) { 
     discard; 
    } 
    } else { 
    vec3 D = R.O-C;  
    float a = dot(R.V,R.V); 
    float b = 2.0*dot(R.V,D); 
    float c = dot(D,D)-r*r; 
    float delta = b*b-4.0*a*c; 

    if(delta < 0.0) { 
     discard; 
    } 
    float t = (-b-sqrt(delta))/(2.0*a); 
    M = R.O + t*R.V; 
    N = M-C; 
    //insert here code to compute the shading with N 

    //update the depth buffer 
    glup_update_depth(M); 
    } 
} 

的完整代码是在我的GEOGRAM库中可用的:http://alice.loria.fr/software/geogram/doc/html/index.html(SRC/LIB/geogram_gfx/GLUP /着色器)。