2012-09-01 3 views
4

OpenGL에서 부드러운 질감 기반 윤곽 효과가 적용됩니다. 지금까지 나는 거의 모든 종류의 가장자리 감지 알고리즘을 시도했는데 대부분 원유 및 들쭉날쭉 한 윤곽선으로 나타났습니다. 그런 다음 Distance Field에 대해 읽었습니다. 꽤 좋은 거리 필드를 보여주는 예를 발견했습니다. 다음은 GLSL 코드는 다음과 같습니다GLSL 거리 필드 투명도

#version 420 
layout(binding=0) uniform sampler2D colorMap; 
flat in vec4 diffuseOut; 
in vec2 uvsOut; 
out vec4 outputColor; 
const float ALPHA_THRESHOLD = 0.9; 
const float NUM_SPOKES = 36.0; // Number of radiating lines to check in. 
const float ANGULAR_STEP =360.0/NUM_SPOKES; 
const int ZERO_VALUE =128; // Color channel containing 0 => -128, 128 => 0, 255 => +127 
int in_StepSize=15; // Distance to check each time (larger steps will be faster, but less accurate). 
int in_MaxDistance=30; // Maximum distance to search out to. Cannot be more than 127! 

vec4 distField(){ 

    vec2 pixel_size = 1.0/vec2(textureSize(colorMap, 0)); 
    vec2 screenTexCoords = gl_FragCoord.xy * pixel_size; 
    int distance; 

    if(texture(colorMap, screenTexCoords).a == 0.0) 
    { 
     // Texel is transparent, search for nearest opaque. 
     distance = ZERO_VALUE + 1; 
     for(int i = in_StepSize; i < in_MaxDistance; i += in_StepSize) 
     { 
      if(find_alpha_at_distance(screenTexCoords, float(i) * pixel_size, 1.0)) 
      { 
       i = in_MaxDistance + 1; // BREAK! 
      } 
      else 
      { 
       distance = ZERO_VALUE + 1 + i; 
      } 
     } 
    } 
    else 
    { 
     // Texel is opaque, search for nearest transparent. 
     distance = ZERO_VALUE; 
     for(int i = in_StepSize; i <= in_MaxDistance; i += in_StepSize) 
     { 
      if(find_alpha_at_distance(screenTexCoords, float(i) * pixel_size, 0.0)) 
      { 
       i = in_MaxDistance + 1; // BREAK! 
      } 
      else 
      { 
       distance = ZERO_VALUE - i; 
      } 
     } 
    } 

    return vec4(vec3(float(distance)/255.0) * diffuseOut.rgb, 1.0 - texture(colorMap, screenTexCoords).a); 

} 

void main() 
{ 
    outputColor= distField(); 
} 

이 쉐이더의 결과는 거리 필드 outline.Here 외부 화면 영역을 채우는 확산 색상을 사용하여 전체 화면을 보이는 방법을 덮는 같은 : enter image description here

내가 필요한 것은 거리 필드 외부의 단색 빨강 채우기가있는 모든 영역을 투명하게 유지하는 것입니다.

+1

블렌딩을 활성화 했습니까? 알파 값을 출력하는 것만으로는 충분하지 않습니다. 알파를 올바른 투명도로 해석하는 방법을 알고있는 블렌드 모드를 활성화해야합니다. – Tim

+0

나는 아마도 당신의 문제를 해결하는 @Tim에 동의한다. 완전을 위해, 전체 화면 쿼드를 렌더링하고 있습니까? – pauluss86

+0

제공된 스크린 샷을주의 깊게 살펴보면서, 나는 인공물로 간주 될 수있는 것을 발견했습니다. 빨간색 획 내부에 흰색 선이 나타나고 뇌졸중 자체가 약간 들쭉날쭉 해 보입니다. 특히 '볼록한'부분. 첫 번째 방법은 텍스처 좌표가 텍스처 맵의 픽셀 중심을 참조하는지 확인하여 해결할 수 있습니다. 두 번째 문제는 링크 된 기사에는 나타나지 않지만 알파 블렌딩 문제와 관련 될 수 있습니다. – pauluss86

답변

2

나는 Distance Field 그레이 스케일 8 비트 알파 맵을 사용하여 해결책을 찾았습니다. Stefan Gustavson자세한 방법을 설명합니다. 원래는 원 텍스쳐의 거리 필드 버전을 생성해야합니다. 그런 다음이 텍스처는 일반적으로 FBO에 첫 번째 패스의 프리미티브로 렌더링됩니다. 두 번째 패스에서 알파 블렌딩 모드는 이 단계에서는 조각 쉐이더가 해당 텍스처의 알파를 샘플링합니다. 이렇게하면 부드러운 가장자리와 가장자리의 알파 투명도가 모두 발생합니다. 결과는 다음과 같습니다. enter image description here

+0

아주 좋아 보이는데 더 이상 공예품이 보이지 않습니다. 얼마나 오래이 구현에 소비 했습니까? – pauluss86

+0

글쎄, 내 경우에는 CPU 측 (Stefan Gustavson의 Distance 필드 프로세스 메소드)을 C++에서 Java로 이식하는 데는 몇 시간이 걸렸다.하지만 기본적으로 C++을 사용한다면 그의 예제에서 붙여 넣기를 복사 할 수있다. :) –

0

스크린 샷을 기반으로 전체 화면 쿼드를 렌더링한다고 가정합니다. 그것이 팀이 방금 답을 제공 한 경우라면

glEnable(GL_BLEND); 
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 

쿼드를 렌더링하기 전에 시도하십시오. 분명히 투명하지 않은 것을 렌더링하려고한다면, 먼저 렌더링하는 것이 좋습니다. 그러면 깊이 버퍼 문제가 발생하지 않을 것입니다. 투명한 소재를 그릴 때 다음을 호출하십시오.

glDisable(GL_BLEND); 

알파 블렌딩을 다시 해제하려면 다음을 수행하십시오.

+0

이전 패스 FBO의 전체 화면 텍스처로 스크린 쿼드 패스를 사용하기 때문에이 방법이 도움이되지 않습니다. –

+0

아, 기술에 익숙하지 않은 당신이 한 번에 그렇게 생각. – pauluss86