[DX] 지면의 높이 구하기, 경사 오르기
🎢 지면의 높이 구하기
플레이어가 경사가 있는 땅을 올라가는것을 구현하기 위해선 바닥의 높이 값을 계산할 수 있어야 한다.
바닥의 높이를 구하는 데 가장 핵심적인 것은 출발지점에서 x축으로 특정 거리만큼 이동했을 때 그 이동한 비율을 계산해서 y축으로는 얼만큼 이동하는지를 구하면 된다.
예를 들어 정점 (0,0)에서 x로 1만큼 올라갔다고 하면 y로도 1만큼 올라가서 (1,1)에 위치하게 된다.
또 x로 0.5만큼 갔을때 y는 0.5만큼 갔을것이다.
이러한 원리를 이용해서 얼만큼 갔는지 비율만 알면 플레이어가 움직일 경사를 구할 수 있다.
플레이어가 출발지(x, y)에서 V0까지 얼마만큼 갔는지를 아는 방법은 (x - V0.x)를 구하면 된다.
여기에 V0부터 V2까지의 길이에 비례해서 (V2 - V0)를 곱하면 최종적으로 플레이어가 가로로 이동한 위치를 알 수 있다.
즉, 가로로 얼만큼 갔는지는 (V2 - V0) * (x - V0.x)를 하면 알 수 있고, 이 결과는 위치벡터 V.x가 된다.
(해당 수식이 얼마만큼 갔는지는 "비율"을 구한것)
❓ 그렇다면 V.y는 얼마가 될 것인가?
V.x가 이동한 비율을 적용해서 V.y가 얼마만큼 갔는지도 동일하게 구할 수 있다.
시작지점에서 한칸을 가야하는거니까 V0(시작지점) + (V2 - V0) * (x - V0.x) + (V1 - V0) * (z - V0.z) 을 구하면 된다. x와 z방향만 계산하면 된다.
만약 V0에서 V2까지의 거리가 1이 아니라 2라면 (x - V0.x)를 2만큼 나눠주면 된다. (z - V0.z)도 마찬가지. 그 길이만큼 나누어주면 크기비율은 1만큼 떨어지게 될 것이다.
따라서, 비율로 얼마만큼 갔는지를 구하면 해당 위치를 알 수 있다.
✔ 총정리
V.x = (x - V0.x) / 1.0f (한칸의 크기)
V.z = (z - V0.z) / 1.0f
Vector3 result = V0 + (V2 - V0) * V.x + (V1 - V0) * V.z
📄 Terrain.cpp (경사면 구하는 부분만 출력)
float Terrain::GetHeight(Vector3 & position)
{
UINT x = (UINT)position.x;
UINT z = (UINT)position.z;
if (x < 0 || x > width) return FLT_MIN;
if (z < 0 || z > height) return FLT_MIN;
UINT index[4];
index[0] = width * z + x;
index[1] = width * (z + 1) + x;
index[2] = width * z + x + 1;
index[3] = width * (z + 1) + x + 1;
Vector3 v[4];
for (int i = 0; i < 4; i++)
v[i] = vertices[index[i]].Position;
float ddx = (position.x - v[0].x) / 1.0f; // 한칸의 크기가 1이라 나누기 1
float ddz = (position.z - v[0].z) / 1.0f;
Vector3 result; // 최종적으로 얼마만큼 갔는지 위치
// ddx + ddy를 더했을 때 1이 나오면 V0, V1, V2 삼각형 안에있는거고 1보다 크면 밖에 있는것
if (ddx + ddz <= 1.0f)
result = v[0] + (v[2] - v[0]) * ddx + (v[1] - v[0]) * ddz;
else // 삼각형 V2, V1, V3
{
ddx = 1.0f - ddx;
ddz = 1.0f - ddz;
result = v[3] + (v[1] - v[3]) * ddx + (v[2] - v[3]) * ddz;
}
return result.y;
}
[ 실행 결과 ]
삼각형의 하단부로 현재 위치를 나타내고 왼쪽 상단에 높이값을 계산한 Vector3를 출력하였다.