2017-03-06 97 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 /着色器)。