DirectX 11 3d

230518 Light MRT - PointLight (다시 공부)

슬뷔 2023. 5. 20. 00:39

로컬 스페이스 좌표  x 월드 스페이스 좌표 = 월드 스페이스 좌표 (양쪽에 월드 스페이스 좌표의 역행렬을 곱하면..)

로컬 스페이스 좌표 = 로컬 스페이스 좌표

즉, 월드 좌표에 있는 것을 월드 역행렬을 곱해주면 다시 로컬좌표로 보낼 수 있다.

꼭 이 순서로 가지 않고, 각 역행렬 곱해주면 이전 공간계로 돌아갈 수 있다.

 

위에 사진에서 빨간색으로 색칠되어 평면과 빛이 겹쳐진 부분만 남기고 그 외는 discard를 하고 싶다.

 

이때 픽셀단위로 월드좌표가 있는데 여기에 월드의 역행렬을 곱하면 다시 로컬로 돌아가게 된다.

(정점에 월드를 보간해서 넘기면 픽셀의 월드좌표를 알 수 있다, 뷰스페이스로 넘기면 픽셀단위로 뷰스페이스좌표를 알았던 것처럼..! 보간해서 들어오니까.)

 

그렇게 되면 월드에 어디에 있었든 무조건 원점을 중심으로 반지름 0.5인 sphere mesh 로 돌아가게 된다.

크기가 커지고 회전하고 등 그런걸 되돌린 것이기 때문에 

 

땅 입장에서 보면 주황색으로 색칠된 부분에 점을 찍으면 실제로 그 위치에 찍히는 것이 아니라 오른쪽 아래 그림처럼 다른 엉뚱한 곳에 찍히게 된다.

흰색으로 색칠되어진 곳에만 빛이 들어가야한다.

저 곳에 들어오는지 판단하기 위해서는!

 

구의 월드 역행렬을 이용해서 구 범위 내의 모든 픽셀을 호출된 픽셀 쉐이더에 대응하는 평면 포지션을 포지션타겟에서 가져온다 ( 같이 로컬스페이스로 보낸다는 뜻 )

로컬로 왔는데 반지름 0.5 내부에 있었다면, 월드에서도 저 흰색칠해진 범위 내부에 존재했다는 뜻이고

벗어나 있다면 범위 밖에 존재하는 것이다.

 

이 테스트를 위해선 2가지의 역행렬이 필요하다. (포지션타겟이 뷰스페이스에 기록이 되어있기 때문에)

1. 뷰 역행렬을 곱해서 월드스페이스 (포인트라이트의 월드)

2. 월드 역행렬(본인의 월드 역행렬)을 곱해서 로컬스페이스 

 

// ========================
// Point Light Shader
// mesh : SphereMesh
// g_int_0 : Light Index
// g_tex_0 : Position Target
// g_tex_1 : Normal Target
// ========================
VS_OUT VS_PointLightShader(VS_IN _in)
{
    VS_OUT output = (VS_OUT) 0.f;
    
    // World => Light3D 월드
    output.vPosition = mul(float4(_in.vPos, 1.f), g_matWVP);
        
    return output;
}

PS_OUT PS_PointLightShader(VS_OUT _in)
{
    PS_OUT output = (PS_OUT) 0.f;
      
    float2 vUV = _in.vPosition.xy / g_Resolution;
    
    float3 vViewPos = g_tex_0.Sample(g_sam_0, vUV).xyz;    
    float3 vWorldPos = mul(float4(vViewPos, 1.f), g_matViewInv);
    float3 vLocalPos = mul(float4(vWorldPos, 1.f), g_matWorldInv);
    
    if (length(vLocalPos) <= 0.5f)
    {
        // 내부   
        
        tLightColor lightcolor = (tLightColor) 0.f;
        float3 vViewNormal = g_tex_1.Sample(g_sam_0, vUV).xyz;
        
        CalcLight3D(vViewPos, vViewNormal, g_int_0, lightcolor);        
        
        output.vDiffuse = lightcolor.vDiffuse + lightcolor.vAmbient;
        output.vSpecular = lightcolor.vSpecular;
    }
    else
    {
        discard;
        //output.vDiffuse = float4(0.f, 0.f, 1.f, 1.f);
        //output.vSpecular = float4(0.f, 0.f, 1.f, 1.f);
    }
    
    return output;
}

==> Decal 방식이다! 규칙적인 도형에만 사용 가능.. 

 

1. sphere

반지름보다 작으면 됨

2. cube

x y z 모두가 절댓값이 정해둔 길이를 추가하면 안된다.