DirectX 11 3d

230607 LandScape 포워드 -> 디퍼드 전환

슬뷔 2023. 6. 14. 05:49

지형은 로컬에 있는 Normal을 사용하면 안된다.

 

스피어매쉬같은 경우에는, 로컬에서 정점들의 노말값이 노말맵을 사용하지 않아도 이미 정해져있다.

(매끄럽게 표현이 됨)

 

지형메쉬는 로컬에 있는 노말값이 어느 정점을 찍어도 전부 다 위를 향하게 해놨다. 

테셀레이션을 해도 원본이 위이기 때문에 전부 위를 향하고 있다.

높이맵을 가져와도 평평할 때의 기준의 노말값을 가지고 있어서 다 위를 향하고 있다. (왼쪽 그림)

오른쪽 그림처럼 저장이 되어야 한다..

 

일반적인 디퍼드 쉐이더처럼 로컬에 있는 노말을 뷰로 보내서 타겟에 저장시키면 의미가 없다..

지형이 변형되면서 만들어지는 것 기준으로 노말을 테셀레이션해서 다 계산을 해주어야한다.

(높이맵을 적용시켰기 때문에)

이렇게하고 노말값을 디퍼드 타겟에 저장을 시켜놔야 정확하게 지형에 적용돼서 나중에 광원처리를 해줄 때, 현재 노말에 맞게 광원이 들어갈 수 있다.

 

지형은 어차피 평면이기 때문에 input 에 들어오는 노말이 의미가 없다. 새로 계산해야되기 때문이다.

그래서 VS_IN 에서도 노말을 아예 받지도 않았다.

struct VS_IN
{
    float3 vPos : POSITION;
    float2 vUV : TEXCOORD;   
};

 

도메인 쉐이더가 모든 정점들이 마지막으로 호출되는 곳이니까, 거기서 높이맵 다 적용시켜서 노말, 탄젠트, 바이노말을 다시 재계산해준다,

쉐이더상에서 정점들의 위치가 바뀌면서 틀어졌으니까 노말, 탄젠트, 바이노말 새로 다 계산해주고나서 월드, 뷰 전환을 시키면 된다.

뷰까지 전환돼서 픽셀쉐이더에 넘겨주면 보간된 값이 들어가니까 그걸 이용한다.

 

만약 이 값이 맘에 들지 않으면 추가적으로 노말맵핑을 더 입히려고 하면, 넘어온 노말, 탄젠트, 바이노말을 이용해서 랜드스케이프 쉐이더를 사용할 때 노말맵이 넘어와있다면 그 노말맵을 표면정보는 나온거니까 표면에 한번더 재적용시켜서 노말맵핑을 한 최종노말을 노말값에 저장을 한다.

 

 

텍셀 한 칸의 간격을 알아한다.

(텍셀 -> 텍스쳐 한 장에 들어있는 픽셀단위의 데이터 (높이 저장))

본인이 아니라 주변 정점정보가 중요하다.

주변 정점정보를 알아야 기울기가 어느 정도인지 알 수 있다.

why? 내 주변 인근 정점 A 와 B를 알면 B-A 를 하면 기울기를 알수있다. 

 

다음 정점까지 up down left right 로 얼마만큼 가야 다음 정점이 있는지 알아야한다..

분할레벨이 8레벨이라면, 1을 1/8 간격 안에 정점이 있을 것이다. (위 아래 좌 우)

// 도메인 쉐이더 정점의 주변(위, 아래, 좌, 우) 로 접근하기 위한 간격
float fLocalStep = 1.f / _patchtess.Inside;
float2 vUVStep = fLocalStep / float2(FaceX, FaceZ);

// 도메인 정점 주변 정점 위치값(월드 좌표계) 구하기
float3 vUp = mul(float4(vLocalPos.x, HeightMap.SampleLevel(g_sam_0, vHeightMapUV + float2(0.f, -vUVStep.y), 0).x, vLocalPos.z + fLocalStep, 1.f), g_matWorld).xyz;
float3 vDown = mul(float4(vLocalPos.x, HeightMap.SampleLevel(g_sam_0, vHeightMapUV + float2(0.f, +vUVStep.y), 0).x, vLocalPos.z - fLocalStep, 1.f), g_matWorld).xyz;
float3 vLeft = mul(float4(vLocalPos.x - fLocalStep, HeightMap.SampleLevel(g_sam_0, vHeightMapUV + float2(-vUVStep.x, 0.f), 0).x, vLocalPos.z, 1.f), g_matWorld).xyz;
float3 vRight = mul(float4(vLocalPos.x + fLocalStep, HeightMap.SampleLevel(g_sam_0, vHeightMapUV + float2(+vUVStep.x, 0.f), 0).x, vLocalPos.z, 1.f), g_matWorld).xyz;

// 월드 방향 구하기
float3 vTangent = normalize(vRight - vLeft);
float3 vBinormal = normalize(vDown - vUp);
float3 vNormal = normalize(cross(vTangent, vBinormal));

 

지금은 분할레벨이 1이기 때문에 위 아래 좌 우가 1 다음에 있다.

y 값은 높이맵을 이용해서 샘플링해서 얻어와야한다.

 

4 by 4 라면 1은 0.25 즉 25%이다.

float2 vUVStep = fLocalStep / float2(FaceX, FaceZ) => 주변으로 이동할 UV 간격