티스토리 뷰

개발노트

Screen Space Decal

따분한놈 2013. 9. 7. 19:14

이번에 만들게 된 ssd 원래 예전에 데칼을 만들어 달라는 요청이 있었으나.

어찌 만들지 감이 안와서.. 포워드로 대충 만들고 쓰려니 이건 아닌것 같아서 미루고 이제야 개발을 했다는..

기본적으로 만들면서 ttmayrin님의 티스토리 블로그랑 포프님의 작년 KGC 자료를 보고 참고 하였다.

SSD의 기본적인 개념은 깊이버퍼를 만들고 그 깊이버퍼를 가지고 오브젝트 공간으로 변환을 해서 그 오브젝트 공간을 이용해서 텍스쳐 uv를 적용한다는 것이다.

그 깊이 버퍼를 어떻게 만드느냐에 따라 실제 오브젝트 공간으로 변환하는 과정들이 바뀌게 된다.

내가 했던 방법은 ttmayrin님이 하신걸 많이 참고를 하였다.

OBT로 바쁘신데 제 댓글에도 답변을 주시고 도움을 주신 ttmayrin님 감사합니다.

이제 실제 ssd의 코드를 보면

깊이버퍼는 View matrix를 곱한 버텍스의 z를 카메라 원평면과 나눴다.

실제 깊이텍스쳐를 만드는 코드는 아래와 같다.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
float4x4 mWVP;
float4x4 mWV;
float gFar;

struct VS_OUTPUT
{
    float4 Pos        : POSITION;
    float4 Depth    : TEXCOORD0;
};

VS_OUTPUT VS( float4 Pos : POSITION )
{
    VS_OUTPUT Out = (VS_OUTPUT)0;

    Out.Pos = mul( Pos, mWVP );

    Out.Depth = mul( Pos, mWV );

    return Out;
}

float4 PS(VS_OUTPUT In) : COLOR
{   
    float4 Out = float4(0.0,0.0,0.0,1.0);
    Out = In.Depth.z/gFar;

    return Out;
}

아래 코드가 실제 데칼을 입히는 셰이더이다.

View * Proj을 곱한 버텍스를 동차좌표계로 나누면 프로젝션 공간인 xy가 -1~1사이이고 z는 0~1사이의 값이 된다.

xy의 경우엔 깊이텍스쳐의 깊이 값을 가져오는 텍스쳐 uv값으로 사용한다.

그리고 카메라공간의 카메라 우측상단의 값을 가지고 ray를 만드는데.

그 ray에 depth를 곱해서 실제적인 카메라 공간에서의 위치를 가져오게 된다.

그럼 이제 View의 역행렬을 곱하면 월드 공간이 나올테고.

이 샘플은 월드에 변환을 안해줘서 이렇게만 해줘서 로컬공간의 위치를 가지고 올 수 있다.

그리고 clip( 0.5-ObjAbs)의 코드의 경우 실제 데칼이 입혀지는 박스가 꼭지점이 0.5, -0.5이다. 그래서 0.5를 더하면 실제 uv값으로 사용가능 한 0~1사이의 값이 된다.

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

float4 PS ( VS_OUTPUT In) : COLOR
{
    float4 col = float4(1.0,0.0,0.0,0.0);

    float3 screenposition = In.ClipPos.xyz/In.ClipPos.w;
    screenposition.x = screenposition.x * 0.5 + 0.5; 
    screenposition.y = -screenposition.y * 0.5 + 0.5;
    
    float depth = tex2D( DepthMapSamp, screenposition.xy ).r;

    float3 ViewRay = float3( lerp(-CameraRightTop.xy, CameraRightTop.xy, screenposition.xy ).xy, CameraRightTop.z );

    float4 ViewPos = float4( ViewRay.xyz * depth, 1.0 );
    float4 ObjPos = mul( ViewPos, InvView );

    float3 ObjAbs = abs(ObjPos.xyz);
    clip( 0.5 - ObjAbs );

    float2 uv = ObjPos.xz + 0.5;
    col = tex2D( texSamp, uv );

    float dist = abs(ObjPos.z);
    float scaleDistance = max(dist * 2.0f, 1.0f); 
    float fadeOut = 1.0f - scaleDistance;
    col.a *= fadeOut;

    col *= ( 1.f - max( (ObjAbs.z-0.25f)/0.25, 0.f) );

    return col;
}

< 실제 데칼 모습 >

깊이텍스쳐가 far값이 너무 크다보니 0에 가까운 값이라서 카메라를 뒤로 빠지지 않는 한 눈으로 확인이 불가능 하다.

그리고 ssd가 모든 상황에 다 잘 발리는 건 아니다.

저렇게 수직인 지형에서 잘리는 상황이 있는데. 이 경우엔 ttmayrin님이 올리신 fade로 하던지 해야 포프님의 자료처럼 하던지 해야할듯..

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함