2017-03-06 2 views
0

나는 SDF 기능을 사용하여 GLSL에서 구 추적/레이 행진에 관한 몇 가지 문제가있다. 버텍스 쉐이더는 윈도우 해상도, 프로젝션 매트릭스 및 뷰 매트릭스에 액세스 할 수 있습니다. 투영 행렬은 glm::perspective(45.0, 1920/1080, 0.1, 100.0);으로 생성됩니다.GLSL : 투영 행렬을 사용하여 광선 방향을 계산하는 방법은 무엇입니까? 가 화면에 쿼드를 생성하고 버텍스 쉐이더를 제공합니다 (VULKAN를 사용하여, C++)</p> <p>내 주요 프로그램 당 정점 <code>inPosition</code> :

버텍스 셰이더에서는 이미지 평면을 통해 vec4(0.0, 0.0, 0.0, 1.0)에있는 원점에서 오는 광선 (위치와 방향이 균질 좌표로 계산 됨)을 계산하려고합니다. 나는 이미지 평면을 어디에 두어야하는지 혼란스럽고 이제는 음수의 z 축을 보려고 vec4(inPosition.xy, -5.0, 1.0)을 선택했습니다.

#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]에 있다는 점을 고려하면 (벽에 머리를 얹어 놓았습니다). glup_primary_ray를 사용하여 광선 추적 구체()를 그립니다

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; 
} 

예 조각 쉐이더 :

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/쉐이더).

관련 문제