728x90
반응형
- 개요
정점 버퍼와 인덱스 버퍼를 사용하여 삼각형의 외곽선을 그려 메시를 표현하는 와이어프레임을 구현한다
- 예제
1) 정점 구조체
struct Vertex2D
{
public:
// 4개의 생성자가 존재
// 기본 생성자 / 정점의 위치를 인자로 받는 생성자 / 정점의 위치 + 정점의 색상을 인자로 받는 생성자 / 정점의 위치 + 정점의 색상 + 정점의 텍스처를 인자로 받는 생성자
constexpr Vertex2D() = default;
constexpr Vertex2D(const Vector2& InPosition) : Position(InPosition) { }
constexpr Vertex2D(const Vector2& InPosition, const LinearColor& InColor) : Position(InPosition), Color(InColor) { }
constexpr Vertex2D(const Vector2& InPosition, const LinearColor& InColor, const Vector2& InUV) : Position(InPosition), Color(InColor), UV(InUV) { }
// 정점과 스칼라 곱연산을 위한 연산자 오버로딩
constexpr Vertex2D operator*(float InScalar) const
{
return Vertex2D(
Position * InScalar,
Color * InScalar,
UV * InScalar
);
}
// 정점과 다른 정점의 합연산을 위한 연산자 오버로딩
constexpr Vertex2D operator+(const Vertex2D& InVector) const
{
return Vertex2D(
Position + InVector.Position,
Color + InVector.Color,
UV + InVector.UV
);
}
// 3개의 멤버변수가 존재
// 정점의 위치 / 정점의 색상 / 정점의 텍스처
Vector2 Position;
LinearColor Color;
Vector2 UV;
};
위와 같이 하나의 정점을 의미하는 Vertex2D 구조체를 생성하였다
구성은 위와 같으며, 멤버변수로 위치 + 색상 + 텍스처를 갖도록 설정하였다
2) 렌더링 로직
...
// 화면에 렌더링하는 함수
void SoftRenderer::Render2D()
{
// 화면에 렌더하기 위해 가져올 레퍼런스
auto& r = GetRenderer();
const auto& g = Get2DGameEngine();
// 배경에 격자 그리기
DrawGizmo2D();
// 렌더링할 메시 데이터의 변수 선언
// 렌더링할 정사각형의 절반 크기 / 렌더링할 정사각형의 정점 개수 / 렌더링할 정사각형을 구성한 삼각형의 개수
static constexpr float squareHalfSize = 0.5f;
static constexpr size_t vertexCount = 4;
static constexpr size_t triangleCount = 2;
// 정점 버퍼를 생성 -> 첫 번째 정점(-0.5, -0.5) / 두 번째 정점(-0.5, 0.5) / 세 번째 정점(0.5, 0.5) / 네 번째 정점(0.5, -0.5)
static constexpr std::array<Vertex2D, vertexCount> rawVertices = {
Vertex2D(Vector2(-squareHalfSize, -squareHalfSize)),
Vertex2D(Vector2(-squareHalfSize, squareHalfSize)),
Vertex2D(Vector2(squareHalfSize, squareHalfSize)),
Vertex2D(Vector2(squareHalfSize, -squareHalfSize))
};
// 인덱스 버퍼를 생성
// 첫 번째 삼각형의 정점 순회 : 첫 번째 정점 -> 두 번째 정점 -> 세 번째 정점
// 두 번째 삼각형의 정점 순회 : 첫 번째 정점 -> 세 번째 정점 -> 네 번째 정점
static constexpr std::array<size_t, triangleCount * 3> indices = {
0, 1, 2,
0, 2, 3
};
// 크기 변환 행렬
Vector3 sBasis1(currentScale, 0.f, 0.f);
Vector3 sBasis2(0.f, currentScale, 0.f);
Vector3 sBasis3 = Vector3::UnitZ;
Matrix3x3 sMatrix(sBasis1, sBasis2, sBasis3);
// 회전 변환 행렬
float sin = 0.f, cos = 0.f;
Math::GetSinCos(sin, cos, currentDegree);
Vector3 rBasis1(cos, sin, 0.f);
Vector3 rBasis2(-sin, cos, 0.f);
Vector3 rBasis3 = Vector3::UnitZ;
Matrix3x3 rMatrix(rBasis1, rBasis2, rBasis3);
// 이동 변환 행렬
Vector3 tBasis1 = Vector3::UnitX;
Vector3 tBasis2 = Vector3::UnitY;
Vector3 tBasis3(currentPosition.X, currentPosition.Y, 1.f);
Matrix3x3 tMatrix(tBasis1, tBasis2, tBasis3);
// 모든 아핀 변환을 곱한 합성 행렬 생성, 크기-회전-이동 순으로 적용
Matrix3x3 finalMatrix = tMatrix * rMatrix * sMatrix;
// 행렬 곱이 적용된 각 정점을 렌더링에 사용할 정점 버퍼에 저장
static std::vector<Vertex2D> vertices(vertexCount);
for (size_t vi = 0; vi < vertexCount; ++vi)
{
vertices[vi].Position = finalMatrix * rawVertices[vi].Position;
}
// 변환된 정점들 간의 선 그리기
for (size_t ti = 0; ti < triangleCount; ++ti)
{
size_t bi = ti * 3;
r.DrawLine(vertices[indices[bi]].Position, vertices[indices[bi + 1]].Position, _WireframeColor);
r.DrawLine(vertices[indices[bi]].Position, vertices[indices[bi + 2]].Position, _WireframeColor);
r.DrawLine(vertices[indices[bi + 1]].Position, vertices[indices[bi + 2]].Position, _WireframeColor);
}
// 현재 위치, 크기, 각도를 화면에 출력
r.PushStatisticText(std::string("Position : ") + currentPosition.ToString());
r.PushStatisticText(std::string("Scale : ") + std::to_string(currentScale));
r.PushStatisticText(std::string("Degree : ") + std::to_string(currentDegree));
}
...
위와 같이 렌더링하는 로직을 구성하였다
https://monstrosite.tistory.com/1012에서 작성한 정점 버퍼와 인덱스 버퍼를 사용하여 메쉬를 표현한다
또, 합성 행렬을 사용하여 정점 버퍼에 저장된 정점들을 렌더링할 수 있도록 변환하였다
- 최종 실행 결과

728x90
반응형
'수학 > 이득우의 게임 수학 - 실습 예제' 카테고리의 다른 글
| 정점의 부가 정보를 활용한 무지개 삼각형 만들기 (0) | 2025.12.17 |
|---|---|
| 무게중심좌표를 활용한 와이어프레임의 삼각형 색칠 (0) | 2025.12.03 |
| 벡터의 내적을 활용한 벡터의 투영 구현 (0) | 2025.11.19 |
| 벡터의 내적을 활용한 조명 모델의 구현 (0) | 2025.11.19 |
| 벡터의 내적을 활용한 목표물 감지 (0) | 2025.11.12 |