[gpu gems3] chapter 28. practical post process depth of field

40
GPU Gems3 Chapter 28. Practical Post-Pr ocess Depth of Field http://ohyecloudy.com http://cafe.naver.com/shader.cafe 2009.07.06

Upload: -

Post on 15-Jul-2015

1.763 views

Category:

Technology


4 download

TRANSCRIPT

GP

U G

em

s3

Chapter 28. Practical Post-Process Depth of Field

http://ohyecloudy.com

http://cafe.naver.com/shader.cafe

2009.07.06

Depth of Field

용어 정리

CoC(Circle of confusion, 착란원)

Overview

Post-Process Stage에서 DoF를 구현한다.

Depth Texture를 사용

depth 값을 사용해 CoC를 구한다.

Blur 경계를 부드럽게 표현

focused 오브젝트와 unfocused 오브젝트 경계

공식 유도

CoC 의 반지름을 구한다.

lens

Imaging Plane

nu nv

d

c

0v

n

n

v

vv

d

c 0

n

n

f

f

v

vv

d

c

v

vv00

p

p

v

vvdc

0

pv

v

fv

fdc 0

0

1

초점거리 변수focal length

Initial Stochastic Approach

The Scatter-as-Gather Approach

The Blur Approach

Evolution of the Algorithm

모든 픽셀의 CoC 계산. 계산된 CoC를 원본 이미지 샘플링에 사용. 원형 푸아송 분포(Poisson distribution)

주변 픽셀과 현재 계산중인 픽셀의 CoC가 같다는 가정. 이 가정이 아니면 주변 픽셀의 CoC를 따져서 샘플링 해야 한다.

Search CoC

original texture

Sharp silhouettes Ringing artifacts low-quality 텍스쳐를 사용한 것처럼 나온다.

sharp silhouettes.

Initial Stochastic Approach 주변 픽셀과 현재 계산중인 픽셀의 CoC가 같다는 가정

Sharp shilhouettes, Ring artifact, 텍스쳐 품질 저하.

The Scatter-as-Gather Approach

The Blur Approach

Evolution of the Algorithm

original texture

주변 픽셀과 현재 계산중인 픽셀의 CoC가 같다는 가정. 각자 자신의 CoC를 가진다. 주변 픽셀을 검색할 때 가장 큰 CoC로 검색 주변 픽셀의 CoC가 저마다 다르기 때문.

현재 계산중인 픽셀이 CoC 범위에 들지 않으므로 제외

Sharp silhouettes Ringing artifacts low-quality 텍스쳐를 사용한 것처럼 나온다. 블러된 텍스쳐 질은 향상

sharp silhouettes.

Initial Stochastic Approach 주변 픽셀과 현재 계산중인 픽셀의 CoC가 같다는 가정

Sharp shilhouettes, Ring artifact, 텍스쳐 품질 저하.

The Scatter-as-Gather Approach 각 픽셀마다 자싞의 CoC를 가진다.

첫번째 시도보다는 blur된 텍스쳐 품질은 좋아짐

The Blur Approach

Evolution of the Algorithm

CoC

CoC

focus, background CoC = 1

blurred CoC

¼ down scaling

focused와 unfocused 경계선이 부드럽지 않다. 최대 blur와 focused 오브젝트의 경계선은 약 50% blur

gradient가 필요.

102

1DDDB

01 2 DDD B

0000 ),max(2)2,max( DDDDDDD BB

diameter

Initial Stochastic Approach 주변 픽셀과 현재 계산중인 픽셀의 CoC가 같다는 가정

Sharp shilhouettes, Ring artifact, 텍스쳐 품질 저하.

The Scatter-as-Gather Approach 각 픽셀마다 자싞의 CoC를 가진다.

첫번째 시도보다는 blur된 텍스쳐 품질은 좋아짐

The Blur Approach CoC 텍스쳐 ¼ 다운 샘플링 & Blur

gradient로 경계선처리

셋 중 가장 만족스러운 결과물

Evolution of the Algorithm

Initial Stochastic Approach

The Scatter-as-Gather Approach The Blur Approach

구현 고려 사항

Depth Information R32F Texture

Variable-Width Blur

Circle of Confusion Radius

First-Person Weapon Considerations

piecewise linear curve로 approximate 서로 다른 blur radius 3개

오리지널 unblurred sample

RGB A

2개의 큰 blur radius 다운 샘플링된 CoC

가장 작은 blur radius

5번의 texture lookup

5X5에서 평균 17 픽셀

가장 작은 blur

실제 blur된 컬러의 approximation

연속된 blur 컬러 표현

구현 고려 사항

Depth Information R32F Texture

Variable-Width Blur blur radius 3개 + unblurred sample

가장 작은 blur radius로 실제 컬러 귺사, 연속된 blur 컬러 표현

Circle of Confusion Radius

First-Person Weapon Considerations

Depth Texture에 기록된 Depth 값으로 구한다.

더 자유로운 표현을 위해

world-near-end distance

world-far-start distance

pv

v

fv

fdc 0

0

1

구현 고려 사항

Depth Information R32F Texture

Variable-Width Blur blur radius 3개 + unblurred sample

가장 작은 blur radius로 실제 컬러 귺사, 연속된 blur 컬러 표현

Circle of Confusion Radius 앞에서 구한 공식을 그대로 사용하지 않는다.

자유로운 표현을 위해 변수 추가

First-Person Weapon Considerations

FPS(first-person shooter) 게임에서 플레이어 무기 표현은 매우 중요

특별 처리

view model로 따로 near, far 값을 갖게 한다.

world와 view model의 구분

view model의 경우 depth를 마이너스 값으로 기록

구현 고려 사항

Depth Information R32F Texture

Variable-Width Blur blur radius 3개 + unblurred sample

가장 작은 blur radius로 실제 컬러 귺사, 연속된 blur 컬러 표현

Circle of Confusion Radius 앞에서 구한 공식을 그대로 사용하지 않는다.

자유로운 표현을 위해 변수 추가

First-Person Weapon Considerations 특별처리, Depth는 음수값으로 기록

The Complete Algorithm

Downsamples the Scene and Initializes the Near CoC. soft egde를 표현하기 위한 near CoC 생성 렌더 타겟은 씬의 ¼ 사이즈

Pixel Shader That Calculates the Actual Near CoC Blurs the Near CoC and Downsampled Color Image Once Merges the Far CoC with the Near CoC and Applies It to the Screen

struct PixelInput { float4 position : POSITION; float2 tcColor0 : TEXCOORD0; float2 tcColor1 : TEXCOORD1; float2 tcDepth0 : TEXCOORD2; float2 tcDepth1 : TEXCOORD3; float2 tcDepth2 : TEXCOORD4; float2 tcDepth3 : TEXCOORD5; }; PixelInput DofDownVS( float4 pos : POSITION, float2 tc : TEXCOORD0 ) { PixelInput pixel; pixel.position = mul( pos, worldViewProj ); pixel.tcColor0 = tc + float2( -1.0, -1.0 ) * invRenderTargetSize; pixel.tcColor1 = tc + float2( +1.0, -1.0 ) * invRenderTargetSize; pixel.tcDepth0 = tc + float2( -1.5, -1.5 ) * invRenderTargetSize; pixel.tcDepth1 = tc + float2( -0.5, -1.5 ) * invRenderTargetSize; pixel.tcDepth2 = tc + float2( +0.5, -1.5 ) * invRenderTargetSize; pixel.tcDepth3 = tc + float2( +1.5, -1.5 ) * invRenderTargetSize; return pixel; }

const float2 dofRowDelta;// float2( 0, 0.25 / renderTargetHeight ) half4 DofDownPS( const PixelInput pixel ) : COLOR { rowOfs[0] = 0; rowOfs[1] = dofRowDelta.xy; rowOfs[2] = dofRowDelta.xy * 2; rowOfs[3] = dofRowDelta.xy * 3; // Use bilinear filtering to average 4 color samples for free. half3 color = 0; color += tex2D( colorSampler, pixel.tcColor0.xy + rowOfs[0] ).rgb; color += tex2D( colorSampler, pixel.tcColor1.xy + rowOfs[0] ).rgb; color += tex2D( colorSampler, pixel.tcColor0.xy + rowOfs[2] ).rgb; color += tex2D( colorSampler, pixel.tcColor1.xy + rowOfs[2] ).rgb; color /= 4; // Process 4 samples at a time to use vector hardware efficiently. // The CoC will be 1 if the depth is negative, so use "min" to pick // between "sceneCoc" and "viewCoc". depth[0] = tex2D( depthSampler, pixel.tcDepth0.xy + rowOfs[0] ).r; depth[1] = tex2D( depthSampler, pixel.tcDepth1.xy + rowOfs[0] ).r; depth[2] = tex2D( depthSampler, pixel.tcDepth2.xy + rowOfs[0] ).r; depth[3] = tex2D( depthSampler, pixel.tcDepth3.xy + rowOfs[0] ).r; half4 viewCoc = saturate( dofEqWeapon.x * -depth + dofEqWeapon.y ); half4 sceneCoc = saturate( dofEqWorld.x * depth + dofEqWorld.y ); half4 curCoc = min( viewCoc, sceneCoc ); half4 coc = curCoc; // rowOfs[1], rowOfs[2], rowOfs[3] half maxCoc = max( max( coc[0], coc[1] ), max( coc[2], coc[3] ) ); return half4( color, maxCoc ); }

Color Texture Depth Texture

DofDownTexture R G B A

오리지널 텍스쳐 컬러 max CoC

The Complete Algorithm

Downsamples the Scene and Initializes the Near CoC. soft egde를 표현하기 위한 near CoC 생성 렌더 타겟은 씬의 ¼ 사이즈

Pixel Shader That Calculates the Actual Near CoC 경계선을 부드럽게 할 수 있도록 CoC 계산

Blurs the Near CoC and Downsampled Color Image Once Merges the Far CoC with the Near CoC and Applies It to the Screen

// These are set by the game engine. sampler shrunkSampler; // Output of DofDownsample() sampler blurredSampler; // Blurred version of the shrunk sampler // This is the pixel shader function that calculates the actual // value used for the near circle of confusion. // "texCoords" are 0 at the bottom left pixel and 1 at the top right. float4 DofNearCoc( const float2 texCoords ) { half4 shrunk = tex2D( shrunkSampler, texCoords ); half4 blurred = tex2D( blurredSampler, texCoords ); float3 color = shrunk.rgb; float coc = 2 * max( blurred.a, shrunk.a ) - shrunk.a; return float4( color, coc ); }

0000 ),max(2)2,max( DDDDDDD BB

Gaussian blur

shrunkSampler blurredSampler

DofDownTexture

blurred DofDownTexture

The Complete Algorithm

Downsamples the Scene and Initializes the Near CoC. soft egde를 표현하기 위한 near CoC 생성

렌더 타겟은 씬의 ¼ 사이즈

Pixel Shader That Calculates the Actual Near CoC 경계선을 부드럽게 할 수 있도록 CoC 계산

Blurs the Near CoC and Downsampled Color Image Once

3x3 blur를 사용해 실제로 경계선을 부드럽게 한다.

Merges the Far CoC with the Near CoC and Applies It to the Screen

// This vertex and pixel shader applies a 3 x 3 blur to the image in // colorMapSampler, which is the same size as the render target. // The sample weights are 1/16 in the corners, 2/16 on the edges, // and 4/16 in the center. sampler colorSampler;// Output of DofNearCoc() float2 invRenderTargetSize; struct PixelInput { float4 position : POSITION; float4 texCoords : TEXCOORD0; }; PixelInput SmallBlurVS( float4 position, float2 texCoords ) { PixelInput pixel; const float4 halfPixel = { -0.5, 0.5, -0.5, 0.5 }; pixel.position = Transform_ObjectToClip( position ); pixel.texCoords = texCoords.xxyy + halfPixel * invRenderTargetSize; return pixel; } float4 SmallBlurPS( const PixelInput pixel ) { float4 color; color = 0; color += tex2D( colorSampler, pixel.texCoords.xz ); color += tex2D( colorSampler, pixel.texCoords.yz ); color += tex2D( colorSampler, pixel.texCoords.xw ); color += tex2D( colorSampler, pixel.texCoords.yw ); return color / 4; }

The Complete Algorithm

Downsamples the Scene and Initializes the Near CoC. soft egde를 표현하기 위한 near CoC 생성 렌더 타겟은 씬의 ¼ 사이즈

Pixel Shader That Calculates the Actual Near CoC 경계선을 부드럽게 할 수 있도록 CoC 계산

Blurs the Near CoC and Downsampled Color Image Once 3x3 blur를 사용해 실제로 경계선을 부드럽게 한다.

Merges the Far CoC with the Near CoC and Applies It to the Screen varialbe-width blur 적용 모든 color sample의 alpha를 1로 가정 읽지 않은 center 샘플을 color가 0이고 alpha가 0인 픽셀로 처리

R G B A

오리지널 텍스쳐 컬러 max CoC

Color Texture

Depth Texture

DofDownTexture

Gaussian blur

blurred DofDownTexture

largeBlurSampler

DofNearCoc Texture

SmallBlurTexture

0000 ),max(2)2,max( DDDDDDD BB

3x3 blur

smallBlurSampler

sampler colorSampler; // Original source image sampler smallBlurSampler; // Output of SmallBlurPS() sampler largeBlurSampler; // Blurred output of DofDownsample() half4 ApplyDepthOfField( const float2 texCoords ) { half coc; half3 small = GetSmallBlurSample( texCoords ); half4 med = tex2D( smallBlurSampler, texCoords ); half3 large = tex2D( largeBlurSampler, texCoords ).rgb; half nearCoc = med.a; half depth = tex2D( depthSampler, texCoords ).r; if ( depth > 1.0e6 ) { coc = nearCoc; // We don't want to blur the sky. } else { // dofEqFar.x and dofEqFar.y specify the linear ramp to convert // to depth for the distant out-of-focus region. half farCoc = saturate( dofEqFar.x * depth + dofEqFar.y ); // dofEqFar.z is the ratio of the far to the near blur radius. coc = max( nearCoc, farCoc * dofEqFar.z ); } return InterpolateDof( small, med.rgb, large, coc ); }

half3 GetSmallBlurSample( float2 tc ) { const half weight = 4.0 / 17; half3 sum = 0; // Unblurred sample done by alpha blending sum += weight * tex2Doffset( colorSampler, tc, +0.5, -1.5 ).rgb; sum += weight * tex2Doffset( colorSampler, tc, -1.5, -0.5 ).rgb; sum += weight * tex2Doffset( colorSampler, tc, -0.5, +1.5 ).rgb; sum += weight * tex2Doffset( colorSampler, tc, +1.5, +0.5 ).rgb; return sum; }

float4 tex2Doffset( sampler s, float2 tc, float2 offset ) { return tex2D( s, tc + offset * invRenderTargetSize ); }

half4 InterpolateDof( half3 small, half3 med, half3 large, half coc ) { // Efficiently calculate the cross-blend weights for each sample. // Let the unblurred sample to small blur fade happen over distance // d0, the small to medium blur over distance d1, and the medium to // large blur over distance d2, where d0 + d1 + d2 = 1. // dofLerpScale = float4( -1 / d0, -1 / d1, -1 / d2, 1 / d2 ); // dofLerpBias = float4( 1, (1 – d2) / d1, 1 / d2, (d2 – 1) / d2 ); half4 weights = saturate( coc * dofLerpScale + dofLerpBias ); weights.yz = min( weights.yz, 1 - weights.xy ); // Unblurred sample with weight "weights.x" done by alpha blending half3 color = weights.y * small + weights.z * med + weights.w * large; half alpha = dot( weights.yzw, half3( 16.0 / 17, 1.0, 1.0 ) ); return half4( color, alpha ); }

0d1d 2d

Unblurred Small blur Medium blur Large blur

Conclusion

• 픽셀당 8.625 샘플링이 필요.

– large Gaussian blur의 샘플링 카운트를 계산하지 않았을때

• 오리지널 이미지에 있는 픽셀이 1.3125 번 쓰인다.

– ¼로 다운 샘플링해서 사용

• 렌더타겟 6장

– Gaussian blur가 2패스일때를 가정.

Limitations and Future Work

• unfocused 오브젝트의 blur가 focus 오브젝트를 가린다.

– foreground 오브젝트 렌더링 버퍼를 분리해서 극복 가능

• Transparency를 명확하기 처리 불가능