연재 완료/프로그래밍용 수학 공부

15. 벡터(4) - 벡터 클래스 구현

라이피 (Lypi) 2018. 12. 11. 18:28
반응형

// 그냥 "이런식으로 구현할 수 있다." 의 수준이므로 실제 사용은 상용 라이브러리를 쓸 것을 권장. DirectXMath.h라던가... xnamath.h라던가...

// 그러므로 include문은 생략.


header

 struct float2
	{
		union {
			struct { float x, y; };
			float f[2];
		};

		float2();
		float2(float _x, float _y);
	};

	struct Vector2 : float2
	{
		static const Vector2 Zero2;
		static const Vector2 UnitX2;
		static const Vector2 UnitY2;

		//생성자
		Vector2();
		explicit Vector2(float x);
		Vector2(float x, float y);
		Vector2(float2& V);
		Vector2(Vector2& F);

		//복사 생성자
		Vector2(const Vector2&) = default;
		Vector2(Vector2&&) = default;

		//연산자재정의
		Vector2& operator=(const Vector2&) = default;
		Vector2& operator=(Vector2&&) = default;

		bool operator== (Vector2& V);
		bool operator!= (Vector2& V);

		Vector2 operator+= (Vector2 V);
		Vector2 operator-= (Vector2 V);
		Vector2 operator*= (float S);
		Vector2 operator/= (float S);

		Vector2 operator+ (Vector2 V);
		Vector2 operator- (Vector2 V);

		Vector2 operator* (float S);
		Vector2 operator/ (float S);
		
		Vector2 operator+ ();
		Vector2 operator- ();
		
		//멤버함수
		float Length();
		float LengthSquared();

		float Dot(const Vector2 V);

		Vector2 Normalize();
		void Normalize(Vector2 result);

		Vector2 Clamp(Vector2 min, Vector2 max);
		void Clamp(Vector2 min, Vector2 max, Vector2 ret);

		//static function
		//static Vector2 operator* (float S, Vector2 V);
		//static Vector2 operator/ (float S, Vector2 V);

		static float Dot(Vector2 v1, Vector2 v2);
		static float Distance(Vector2 v1, Vector2 v2);
		static float DistanceSquared(Vector2 v1, Vector2 v2);

		static Vector2 Min(Vector2 v1, Vector2 v2);
		static Vector2 Max(Vector2 v1, Vector2 v2);

		static Vector2 Lerp(Vector2 v1, Vector2 v2, float t); //선형 보간법
		static Vector2 SmoothStep(Vector2 v1, Vector2 v2, float t); //스무스스텝. (필요한가..?)

		static Vector2 Reflect(Vector2 iV, Vector2 nV); //iV:반사시킬 벡터, nV:평면의 노말벡터.
		static Vector2 Refract(Vector2 iV, Vector2 nV, float rI); //iV:굴절시킬 벡터, nV:평면의 노말벡터. rI:굴절율
	};

	struct float3
	{
		union {
			struct { float x, y, z; };
			float f[3];
		};

		float3();
		float3(float _x, float _y, float _z);
	};

	struct Vector3 : float3
	{
		static const Vector3 Zero3;
		static const Vector3 UnitX3;
		static const Vector3 UnitY3;
		static const Vector3 UnitZ3;

		//생성자
		Vector3();
		explicit Vector3(float x);
		Vector3(float x, float y, float z);
		Vector3(float3& F);
		Vector3(Vector3& V);

		//복사 생성자
		Vector3(const Vector3&) = default;
		Vector3(Vector3&&) = default;     

		//연산자재정의
		Vector3& operator=(const Vector3&) = default;
		Vector3& operator=(Vector3&&) = default;

		bool operator== (Vector3 V);
		bool operator!= (Vector3 V);

		Vector3 operator+= (Vector3 V);
		Vector3 operator-= (Vector3 V);
		Vector3 operator*= (float S);
		Vector3 operator/= (float S);

		Vector3 operator+ (Vector3 V);
		Vector3 operator- (Vector3 V);
		Vector3 operator* (float S);
		Vector3 operator/ (float S);
		
		Vector3 operator+ ();
		Vector3 operator- ();

		//멤버함수
		float Length();
		float LengthSquared();

		float Dot(Vector3 V);
		Vector3 Cross(Vector3 V);

		Vector3 Normalize();
		void Normalize(Vector3 result);

		Vector3 Clamp(Vector3 min, Vector3 max);
		void Clamp(Vector3 min, Vector3 max, Vector3 ret);

		//static function
		//static Vector3 operator* (float S, Vector3 V);
		//static Vector3 operator/ (float S, Vector3 V);

		static float Dot (Vector3 v1,Vector3 v2);
		static Vector3 Cross (Vector3 v1, Vector3 v2);

		static Vector3 Angle(Vector3 V1, Vector3 V2);
			
		static float Distance(Vector3 v1, Vector3 v2);
		static float DistanceSquared(Vector3 v1, Vector3 v2);

		static Vector3 Min(Vector3 v1, Vector3 v2);
		static Vector3 Max(Vector3 v1, Vector3 v2);

		static Vector3 Lerp(Vector3 v1, Vector3 v2, float t); //선형 보간법
		static Vector3 SmoothStep(Vector3 v1, Vector3 v2, float t); //스무스스텝. (필요한가..?)

		static Vector3 Reflect(Vector3 iV, Vector3 nV); //iV:반사시킬 벡터, nV:평면의 노말벡터.
		static Vector3 Refract(Vector3 iV, Vector3 nV, float rI); //iV:굴절시킬 벡터, nV:평면의 노말벡터. rI:굴절율
	};

	struct float4
	{
		union {
			struct { float x, y, z, w; };
			float f[4];
		};

		float4();
		float4(float _x, float _y, float _z, float _w);
	};


cpp

#pragma region float2, Vector2
	float2::float2()
	{
		x = 0.f; y = 0.f;
	}

	float2::float2(float _x, float _y) 
	{
		x = _x; y = _y;
	}

	//생성자
	Vector2::Vector2()
		: float2() {}

	Vector2::Vector2(float x)
		: float2(x, x) {}

	Vector2::Vector2(float x, float y)
		: float2(x, y) {}

	Vector2::Vector2(float2& F)
	{
		x = F.x; 
		y = F.y; 
	}

	Vector2::Vector2(Vector2& V)
	{
		x = V.x; 
		y = V.y; 
	}

	//연산자 재정의
	bool Vector2::operator== (Vector2& V)
	{
		if (abs(x - V.x) < L_Epsilon  && abs(y - V.y) <  L_Epsilon) {
			return true; 
		} 
		return false; 
	}

	bool Vector2::operator!= (Vector2& V)
	{
		if ( abs(x - V.x) < L_Epsilon && abs(y == V.y) < L_Epsilon) {
			return false; 
		} 
		return true; 
	}

	Vector2 Vector2::operator+= (Vector2 V) 
	{
		Vector2 rv = { x += V.x, y += V.y };
		return rv;
	}

	Vector2 Vector2::operator-= (Vector2 V) 
	{
		Vector2 rv = { x -= V.x, y -= V.y};
		return rv; 
	}

	Vector2 Vector2::operator*= (float S)
	{
		Vector2 rv = { x *= S, y *= S };
		return rv; 
	}

	Vector2 Vector2::operator/= (float S) 
	{
		Vector2 rv = { x /= S, y /= S };
		return rv; 
	}

	Vector2 Vector2::operator+ (Vector2 V)
	{
		Vector2 rv = { x + V.x, y + V.y };
		return rv;
	}

	Vector2 Vector2::operator- (Vector2 V)
	{
		Vector2 rv = { x - V.x, y - V.y };
		return rv;
	}

	Vector2 Vector2::operator* (float S)
	{
		Vector2 rv = { x * S, y * S };
		return rv;
	}

	Vector2 Vector2::operator/ (float S)
	{
		Vector2 rv = { x / S, y / S };
		return rv;
	}

	Vector2 Vector2::operator+ () 
	{
		return *this; 
	}

	Vector2 Vector2::operator- ()
	{
		return Vector2(-x, -y); 
	}

	float Vector2::Length() 
	{
		return sqrtf(x*x + y * y); 
	}

	float Vector2::LengthSquared()
	{
		return x * x + y * y; 
	}

	float Vector2::Dot(const Vector2 V)
	{
		return x * V.x + y * V.y; 
	}

	Vector2 Vector2::Normalize() 
	{
		Vector2 bf = *this; 

		this->x /= Length();
		this->y /= Length();
		
		return bf; 
	}

	void Vector2::Normalize(Vector2 result)
	{
		result.x /= Length(); 
		result.y /= Length(); 
	}

	Vector2 Vector2::Clamp(const Vector2 min, const Vector2 max)
	{
		Vector2 bf = *this;
		(x <= min.x) ? (x = min.x) : ((x > max.x) ? (x = max.x) : (x));
		(y <= min.y) ? (y = min.y) : ((y > max.y) ? (y = max.y) : (y));
		return bf;
	}

	void Vector2::Clamp(Vector2 min, Vector2 max, Vector2 ret)
	{
		(ret.x <= min.x) ? (ret.x = min.x) : ((ret.x > max.x) ? (ret.x = max.x) : (ret.x));
		(ret.y <= min.y) ? (ret.y = min.y) : ((ret.y > max.y) ? (ret.y = max.y) : (ret.y));
	}

	//static function
	Vector2 operator* (float S, Vector2 V)
	{
		Vector2 rv = { V.x * S, V.y * S };
		return rv;
	}

	Vector2 operator/ (float S, Vector2 V)
	{
		Vector2 rv = { V.x / S, V.y / S };
		return rv;
	}

	float Vector2::Dot(Vector2 v1, Vector2 v2) 
	{
		return v1.x * v2.x + v1.y * v2.y; 
	}

	float Vector2::Distance(Vector2 v1, Vector2 v2)
	{
		return (v2 - v1).Length(); 
	}

	float Vector2::DistanceSquared(Vector2 v1, Vector2 v2) 
	{
		return (v2 - v1).LengthSquared(); 
	}

	Vector2 Vector2::Min(Vector2 v1, Vector2 v2)
	{
		Vector2 ret;
		(v1.x <= v2.x) ? (ret.x = v1.x) : (ret.x = v2.x);
		(v1.y <= v2.y) ? (ret.y = v1.y) : (ret.y = v2.y);
		return ret;
	}

	Vector2 Vector2::Max(Vector2 v1, Vector2 v2)
	{
		Vector2 ret;
		(v1.x >= v2.x) ? (ret.x = v1.x) : (ret.x = v2.x);
		(v1.y >= v2.y) ? (ret.y = v1.y) : (ret.y = v2.y);
		return ret;
	}

	Vector2 Vector2::Lerp(Vector2 v1, Vector2 v2, float t)
	{
		Vector2 ret;
		t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);
		ret.x = v1.x + t * (v2.x - v1.x);
		ret.y = v1.y + t * (v2.y - v1.y);
		return ret;
	}

	Vector2 Vector2::SmoothStep(Vector2 v1, Vector2 v2, float t)
	{
		Vector2 ret;
		t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);
		t = t * t * (3.f - 2.f*t); //극솟값이 0, 극댓값이 1, 변곡점이 0.5. (이 조건을 만족한다면 다른 식을 써도 될 듯)
		ret.x = v1.x + t * (v2.x - v1.x);
		ret.y = v1.y + t * (v2.y - v1.y);
		return ret;
	}

	Vector2 Vector2::Reflect(Vector2 iV, Vector2 nV)
	{
		return 2.0f * Dot(iV, nV) * (iV - iV);
	}

	Vector2 Vector2::Refract(Vector2 iV, Vector2 nV, float rI)
	{
		float t = Dot(iV, nV);
		float r = 1.f - (rI*rI) * (1.f - (t*t));

		Vector2 rv;
		if (r < 0.f) {
			rv = { 0.f, 0.f };
		}
		else {
			float s = rI * t + sqrt(r);
			rv = { rI*iV.x - s * nV.x, rI*iV.y - s * nV.y };
		}
	}

	const Vector2 Vector2::Zero2 = { 0.f, 0.f };
	const Vector2 Vector2::UnitX2 = { 1.f, 0.f };
	const Vector2 Vector2::UnitY2 = { 0.f, 1.f };
#pragma endregion

#pragma region float3, Vector3

	float3::float3()
	{
		x = 0.f; y = 0.f; z = 0.f;
	}

	float3::float3(float _x, float _y, float _z)
	{
		x = _x; y = _y; z = _z;
	}

	//생성자
	Vector3::Vector3()
		: float3() {}

	Vector3::Vector3(float x)
		: float3(x, x, x) {}

	Vector3::Vector3(float x, float y, float z)
		: float3(x, y, z) {}

	Vector3::Vector3(float3& F)
	{ 
		x = F.x; 
		y = F.y; 
		z = F.z; 
	}

	Vector3::Vector3(Vector3& V)
	{ 
		x = V.x; 
		y = V.y; 
		z = V.z; 
	}

	//연산자 재정의
	bool Vector3::operator== (Vector3 V)
	{ 
		if (abs(x - V.x) < L_Epsilon && abs(y - V.y) < L_Epsilon && abs(z - V.z) < L_Epsilon) {
			return true; 
		} 
		return false; 
	}

	bool Vector3::operator!= (Vector3 V)
	{ 
		if (abs(x - V.x) < L_Epsilon && abs(y - V.y) < L_Epsilon && abs(z - V.z) < L_Epsilon) {
			return false; 
		} 
		return true; 
	}

	Vector3 Vector3::operator+= (Vector3 V) 
	{
		Vector3 rv = { x += V.x, y += V.y, z += V.z };
		return rv; 
	}

	Vector3 Vector3::operator-= (const Vector3 V) 
	{
		Vector3 rv = { x -= V.x, y -= V.y, z -= V.z };
		return rv;
	}

	Vector3 Vector3::operator*= (float S)
	{
		Vector3 rv = { x *= S, y *= S, z *= S };
		return rv;
	}

	Vector3 Vector3::operator/= (float S) 
	{
		Vector3 rv = { x /= S, y /= S, z /= S };
		return rv;
	}

	Vector3 Vector3::operator+ (Vector3 V)
	{
		Vector3 rv = { x + V.x, y + V.y, z + V.z };
		return rv;
	}

	Vector3 Vector3::operator- (Vector3 V) 
	{ 
		Vector3 rv = { x + V.x, y + V.y, z - V.z };
		return rv;
	}

	Vector3 Vector3::operator* (float S)
	{
		Vector3 rv = { x * S, y * S, z * S };
		return rv;
	}

	Vector3 Vector3::operator/ (float S)
	{
		Vector3 rv = { x / S, y / S, z / S };
		return rv;
	}

	Vector3 Vector3::operator+ ()
	{
		return *this; 
	}

	Vector3 Vector3::operator- ()
	{
		return Vector3(-x, -y, -z); 
	}

	float Vector3::Length() 
	{
		return sqrtf(x*x + y*y + z*z);
	}

	float Vector3::LengthSquared()
	{
		return x*x + y*y + z*z;
	}

	float Vector3::Dot(Vector3 V)
	{
		return x*V.x + y*V.y + z*V.z; 
	}

	Vector3 Vector3::Cross(Vector3 V)
	{
		return Vector3(y*V.x - z*V.y, z*V.x - x*V.z, x*V.y - y*V.x);
	}

	Vector3 Vector3::Normalize() 
	{
		Vector3 bf = *this; 

		this->x /= Length(); 
		this->y /= Length(); 
		this->z /= Length(); 

		return bf; 
	}	

	void Vector3::Normalize(Vector3 result)
	{
		result.x /= Length(); 
		result.y /= Length();
		result.z /= Length(); 
	}

	Vector3 Vector3::Clamp(Vector3 min, Vector3 max)
	{
		Vector3 bf = *this;
		(x <= min.x) ? (x = min.x) : ((x > max.x) ? (x = max.x) : (x));
		(y <= min.y) ? (y = min.y) : ((y > max.y) ? (y = max.y) : (y));
		(z <= min.z) ? (z = min.z) : ((z > max.z) ? (z = max.z) : (z));
		return bf;
	}

	void Vector3::Clamp(Vector3 min, Vector3 max, Vector3 ret)
	{
		(ret.x <= min.x) ? (ret.x = min.x) : ((ret.x > max.x) ? (ret.x = max.x) : (ret.x));
		(ret.y <= min.y) ? (ret.y = min.y) : ((ret.y > max.y) ? (ret.y = max.y) : (ret.y));
		(ret.z <= min.z) ? (ret.z = min.z) : ((ret.z > max.z) ? (ret.z = max.z) : (ret.z));
	}

	//static function
	Vector3 operator* (float S, Vector3 V)
	{
		Vector3 rv = { V.x * S, V.y * S, V.z * S };
		return rv;
	}
	Vector3 operator/ (float S, Vector3 V)
	{
		Vector3 rv = { V.x / S, V.y / S, V.z / S };
		return rv;
	}

	float Vector3::Dot(Vector3 v1, Vector3 v2)
	{
		return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
	}

	Vector3 Vector3::Cross(Vector3 v1, Vector3 v2)
	{
		return Vector3(v1.y*v2.x - v1.z*v2.y, v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x);
	}

	Vector3 Vector3::Angle(Vector3 V1, Vector3 V2)
	{
		return RadianToDegree(acos(Dot(V1, V2) / (V1.Length*V2.Length)));
	}
	
	float Vector3::Distance(Vector3 v1, Vector3 v2) 
	{
		return (v2 - v1).Length(); 
	}

	float Vector3::DistanceSquared(Vector3 v1, Vector3 v2)
	{
		return (v2 - v1).LengthSquared(); 
	}

	Vector3 Vector3::Min(Vector3 v1, Vector3 v2)
	{
		Vector3 ret;
		(v1.x <= v2.x) ? (ret.x = v1.x) : (ret.x = v2.x);
		(v1.y <= v2.y) ? (ret.y = v1.y) : (ret.y = v2.y);
		(v1.z <= v2.z) ? (ret.z = v1.z) : (ret.z = v2.z);
		return ret;
	}

	Vector3 Vector3::Max(Vector3 v1, Vector3 v2)
	{
		Vector3 ret;
		(v1.x >= v2.x) ? (ret.x = v1.x) : (ret.x = v2.x);
		(v1.y >= v2.y) ? (ret.y = v1.y) : (ret.y = v2.y);
		(v1.z >= v2.z) ? (ret.z = v1.z) : (ret.z = v2.z);
		return ret;
	}

	Vector3 Vector3::Lerp(Vector3 v1, Vector3 v2, float t)
	{
		Vector3 ret;
		t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);
		ret.x = v1.x + t * (v2.x - v1.x);
		ret.y = v1.y + t * (v2.y - v1.y);
		ret.z = v1.z + t * (v2.z - v1.z);
		return ret;
	}

	Vector3 Vector3::SmoothStep(Vector3 v1, Vector3 v2, float t)
	{
		Vector3 ret;
		t = (t > 1.0f) ? 1.0f : ((t < 0.0f) ? 0.0f : t);
		t = t * t * (3.f - 2.f*t); //극솟값이 0, 극댓값이 1, 변곡점이 0.5. (이 조건을 만족한다면 다른 식을 써도 될 듯)
		ret.x = v1.x + t * (v2.x - v1.x);
		ret.y = v1.y + t * (v2.y - v1.y);
		ret.z = v1.z + t * (v2.z - v1.z);
		return ret;
	}

	Vector3 Vector3::Reflect(Vector3 iV, Vector3 nV)
	{
		return 2.0f * Dot(iV, nV) * iV - iV;
	}

	Vector3 Vector3::Refract(Vector3 iV, Vector3 nV, float rI)
	{
		float t = Dot(iV, nV);
		float r = 1.f - (rI*rI) * (1.f - (t*t));

		Vector3 rv;
		if (r < 0.f) {
			rv = { 0.f, 0.f, 0.f };
		}
		else {
			float s = rI * t + sqrt(r);
			rv = { rI*iV.x - s * nV.x, rI*iV.y - s * nV.y, rI*iV.z - s * nV.z };
		}
	}

	const Vector3 Vector3::Zero3 = { 0.f, 0.f, 0.f };
	const Vector3 Vector3::UnitX3 = { 1.f, 0.f, 0.f };
	const Vector3 Vector3::UnitY3 = { 0.f, 1.f, 0.f };
	const Vector3 Vector3::UnitZ3 = { 0.f, 0.f, 1.f };
#pragma endregion

#pragma region float4

	float4::float4()
	{
		x = 0.f; y = 0.f; z = 0.f; w = 0.f;
	}

	float4::float4(float _x, float _y, float _z, float _w)
	{
		x = _x; y = _y; z = _z; w = _w;
	}

#pragma endregion


반응형