수학/이득우의 게임 수학 - 실습 예제

하트에 무지개 색상 입히기

monstro 2025. 8. 27. 10:18
728x90
반응형

- HSV 색상 체계

struct HSVColor
{
public:
	FORCEINLINE constexpr HSVColor() = default;
	FORCEINLINE constexpr HSVColor(float InH, float InS, float InV) : H(InH), S(InS), V(InV) {}
	FORCEINLINE constexpr LinearColor ToLinearColor() const
	{
        	float r = 0.f, g = 0.f, b = 0.f;

        	int i = Math::FloorToInt(H * 6.f);
        	float f = H * 6.f - i;
        	float p = V * (1.f - S);
        	float q = V * (1 - f * S);
        	float t = V * (1 - (1 - f) * S);

        	switch (i % 6) 
        	{
        		case 0: 
            			r = V, g = t, b = p; 
            			break;
        		case 1: 
        			r = q, g = V, b = p; 
            			break;
        		case 2: 
        			r = p, g = V, b = t; 
            			break;
        		case 3: 
        			r = p, g = q, b = V; 
            			break;
        		case 4: 
        			r = t, g = p, b = V; 
            			break;
        		case 5: 
        			r = V, g = p, b = q; 
            			break;
        	}

		return LinearColor(r, g, b);
	}

public:
	float H = 0.f;
	float S = 1.f;
	float V = 1.f;
};

 

이전에 작성한 삼각함수를 이용한 하트를 그리는 예제에서 0~2π까지의 값을 이용하여 하트를 표현하였다

이때 에 따라 색상이 대응하는 색상 체계인 HSV(Hue Saturation Value)를 사용하면 

하트를 구성하는 벡터마다 새로운 색상이 대응되어 모든 색상을 사용하여 하트를 색칠할 수 있다

 

출처 : https://ko.wikipedia.org/wiki/HSV_%EC%83%89_%EA%B3%B5%EA%B0%84

 

HSV 모델은 위와 같이 구성되어 있으며, 코드에서는 HSV 모델RGB 모델로 변환하고 반대의 변환도 수행한다

 

- 삼각함수를 사용하여 색이 있는 하트 그리기

...

//  화면에 렌더링하는 함수
void SoftRenderer::Render2D()
{
	// 화면에 렌더하기 위해 가져올 레퍼런스
	auto& r = GetRenderer();
	const auto& g = Get2DGameEngine();

	// 배경에 격자 그리기
	DrawGizmo2D();

	// 로컬 변수
	// 각도를 서서히 증가시킬 값 / 하트를 구성하는 점(위치벡터)을 저장할 컨테이너 / 각 점을 색칠할 HSV 인스턴스
	float rad = 0.f;
	static float increment = 0.001f;
	static std::vector<Vector2> hearts;
	HSVColor hsv(0.f, 1.f, 0.85f);

	// 컨테이너에 하트를 구성하는 점들을 저장하는 로직
	if (hearts.empty())
	{
		// sin 함수와 cos 함수의 정의역인 0과 2π의 범위만을 순회
		for (rad = 0.f; rad < Math::TwoPI; rad += increment)
		{
			float sin = sinf(rad);
			float cos = cosf(rad);
			float cos2 = cosf(2 * rad);
			float cos3 = cosf(3 * rad);
			float cos4 = cosf(4 * rad);
            
			// 하트 방정식 사용
			float x = 16.f * sin * sin * sin;
			float y = 13 * cos - 5 * cos2 - 2 * cos3 - cos4;
			hearts.push_back(Vector2(x, y));
		}
	}

	// 각각의 위치벡터의 각도에 대응하는 HSV 값을 가져오고, 그 값을 RGB로 전환하여 점을 색칠
	rad = 0.f;
	for (auto const& v : hearts)
	{
		hsv.H = rad / Math::TwoPI;
		r.DrawPoint(v * currentScale + currentPosition, hsv.ToLinearColor());
		rad += increment;
	}

	// 현재 하트의 위치벡터와 크기를 화면에 출력
	r.PushStatisticText(std::string("Position : ") + currentPosition.ToString());
	r.PushStatisticText(std::string("Scale : ") + std::to_string(currentScale));
}

 

이전의 코드에서 각 점(위치벡터)의 각도에 대응하는 HSV 값을 반환하고

반환한 HSV 값을 다시 RGB 값으로 변환하여 색칠하는 로직을 추가한다

 

- 최종 실행 결과

728x90
반응형