벡터와 원그리기

상태
담당자

벡터란 무엇일까?

notion image
수학적 의미의 벡터는 공간 상의 한 점에서 다른 점까지의 방향과 거리를 나타낸다.
또, 벡터를 이해하기 위해선 스칼라 개념이 빠질 수 가 없는데
notion image
숫자가 하나 씩 있는 개념으로 스칼라라고 부르며 그것과 대비되게 숫자를 여러 개 묶어 놓는것 을 벡터라 부른다.
notion image
이제, 아이언맨과 캡틴의 거리를 구하기 위해선, 두 벡터 간의 뺄셈을 이용해야 하는데.
그림에서 나오듯이,
벡터 d는, 3.8,1 의 값을 가질 수 있음을 알 수 있다.

위치 벡터

현재, 아이언맨의 위치 벡터 a와, 캡틴의 위치 벡터 b 그리고 아이언맨과 캡틴의 거리 또한 벡터d로 표현하고 있다.
그러나, 컴퓨터 그래픽스에선 뒤에선 이 위치 벡터와 방향 벡터를 구분해서 사용한다.
 

거리는 스칼라로 표현해야 한다.

아이언맨과 캡틴의 거리를 표현할 때에는, 벡터가 아닌 스칼라로 표현해야 한다.
notion image
이때, 사용 되는 것이, 피타고라스의 정리 이며. 거리에 대해서 구하는 수식은 아래와 같게 되는데
결론적으로 구해보자면, 3.92937654088 가 나온다.

단위 벡터 (unit vector)

길이가 1인 벡터, 어떤 벡터를 단위 벡터로 표현하고자 한다면.
그 자신을 절대 값으로 나눠주면 된다.
순수하게 방향만 나타내고 싶을 때 사용한다. 수식은 아래와 같다.
또, 단위 벡터 d의 절대값은 1이 나온다.
 

벡터 사이의 곱

벡터의 곱은 두 가지로 나뉘는데 용어와 수식을 정리하자면 아래와 같다.
용어와, 수식이 꽤 긴데 간단히 설명하자면.
점곱은 두 벡터간의 내적을 구할 때 사용 되며 스칼라 값이 나온다.
크로스곱은 두 벡터간의 외적을 구할 때 사용 되며 벡터로 값이 나온다.
 
조금 더 자세한 설명을 위한, 블로그 글을 참고하면 도움이 될 것 같다. https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=sallygarden_ee&logNo=221265467087

점곱

위 수식에서 눈 여겨 볼 점은, 스칼라 와 벡터 a를 곱하면 각각의 값에 10을 곱한 것이지만 두 벡터를 곱하게 되면, 각각을 곱하고 더한 스칼라 값을 나타낸다.
 
또한 당연하게도 내적은 교환 법칙이 성립한다.
 

크로스곱

뭔가 수식이 내적과는 달리 조금 복잡해 보일 수 있다. 밑에 그림과 같이 보면 식을 생각해내기 편할 수 있다.
notion image
외적의 정의.
  • 3차원 공간에 대한 벡터의 이항연산의 일종으로, 3차원 공간에서의 곱셈이라고 보면 된다.
  • 두 벡터 AB 의 외적 A X B 는 두 벡터에 동시에 수직이고, 그 크기는 |A| |B| sinθ 가 된다.
  • 두 벡터의 외적의 크기는 두 벡터가 만드는 평행사변형의 넓이와 같다.
  • 두 벡터의 외적의 방향은 오른손 법칙을 따른다.
  • 외적은 내적과 달리 곱의 결과가, 크기와 방향이 동시에 존재하는 벡터가 된다.
    • notion image
위 그림과 정의 1번에서 설명 하는 것은, 벡터 a 와 벡터 b의 크로스곱은 두 벡터에 동시에 수직인 벡터가 만들어진다는 것이다. 그림에서, 저 빨간 선을 보면 된다.
notion image
두 벡터의 외적의 크기는 평행사변형의 넓이와 같다.
notion image
두 벡터가 이루는 외적의 방향은 오른손 법칙으로, 휘감는 방향이 외적의 방향이라고 이해할 수 있다.
벡터의 내적으로 두 벡터간에 이루는 각도를 특정지을 수 있다면, 벡터의 외적으로는 두 벡터와 동시에 수직인 벡터(법선벡터)를 구할 수 있다. 벡터의 내적의 결과는 스칼라값이며, 벡터의 외적의 결과는 벡터값이다.
 
내적의 경우, 교환법칙이 성립되지만 외적의 경우 성립하지 않는다. 대신 방향이 반대로 된다.
 

원을 그려보자.

 

목표

notion image
GUI를 통해 원을 그릴 때 옵션을 정할 수 있다.
Center 원의 x,y값의 중점을 결정할 수 있다.
Radius를 통해 원의 크기를 정할 수 있다.
RGB를 통해 원의 색상을 정할 수 있다.
 

코드

void Update() { // 화면을 배경 색으로 초기화 std::vector<glm::vec4> pixels(width * height, glm::vec4{ 0.8f, 0.8f, 0.8f, 1.0f }); // 원 그리기 for (int j = 0; j < height; j++) for (int i = 0; i < width; i++) { if (circle1->IsInside(glm::vec2{ i, j })) { pixels[i + width * j] = circle1->color; } } // 이미지의 내용을 GPU 메모리로 복사 D3D11_MAPPED_SUBRESOURCE ms; deviceContext->Map(canvasTexture, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); memcpy(ms.pData, pixels.data(), pixels.size() * sizeof(glm::vec4)); deviceContext->Unmap(canvasTexture, NULL); }
#pragma once #include <iostream> #include <glm/glm.hpp> #include <glm/gtx/string_cast.hpp> #include <glm/gtx/norm.hpp> namespace hlab { class Circle { public: glm::vec2 center; float radius; float radiusSquared; glm::vec4 color; Circle(const glm::vec2 &center, const float radius, const glm::vec4 &color) : center(center), color(color), radius(radius) { } // x는 벡터이기 때문에 내부적으로 x좌표와 y좌표를 모두 갖고 있음 // screen 좌표계에서는 x좌표와 y좌표가 int지만 float로 변환 bool IsInside(const glm::vec2 &x) { // TODO: 여기에 원의 방정식을 이용해서 x가 원 안에 들어 있는지 아닌지에 따라 // true나 false 반환 auto result = glm::abs(center - x); return glm::length(result) < radius; } }; }
  1. center와 x의 거리를 구한다.
  1. 그 거리가 radius 이하 인지를 비교한다.
  1. true 또는 false를 반환
 
거리를 구하는 방법은 위에서 설명했지만 다시 복습해보자면
💻

거리는 스칼라로 표현해야 한다.

아이언맨과 캡틴의 거리를 표현할 때에는, 벡터가 아닌 스칼라로 표현해야 한다.
notion image
이때, 사용 되는 것이, 피타고라스의 정리 이며. 거리에 대해서 구하는 수식은 아래와 같게 되는데
결론적으로 구해보자면, 3.92937654088 가 나온다.
 
둘 중 하나를 사용해서 풀 수 있다.