게임엔진프로그래밍 - 수학

이미지
1. 브레젠험 직선 알고리즘 컴퓨터에서 계산이 느린 실수 연산을 사용하지 않고 직선을 그리기 위해 만들이진 알고리즘입니다. 평면을 아래와 같이 8분 면으로 나누어 직선을 그립니다. 링크:  https://sulinep.blogspot.com/2020/05/bresenhams-line-algorithm.html 2. 엔진 기초 수학 여기서는 본격적으로 구현에 들어가기 전 기초 수학 지식을 쌓았습니다.  수학에서의 체는 대수적 구조의 하나로 덧셈, 뺄셈, 곱셈, 나눗셈의 사칙연산을 집합 안에서 소화할 수 있는 집합을 의미합니다. 체를 이루기 위한 조건과 체라는 개념을 알아보았습니다. 처음에 체 라는 개념이 뭔가 머릿속에서 애매했는데 이후 갈로이스 체에 대해 배운 후 조금 더 명확해졌습니다. 스칼라 는 벡터를 정의하기 위한 필수 요소이고 크기만 있고 방향이 없는 성분이다. 벡터는 크기와 방향을 포함하는 표현 도구이다. 겨기서 벡터의 기본 연산자들을 알아보았습니다. 선형성 은 직선처럼 똑바른 도형 또는 그와 비슷한 성질을 가진 대상이라는 뜻으로 함수의 경우 함수가 진행하는 모양이 직선이라는 의미로 사용된다. 선형성을 만족하려면 두 가지 조건을 만족해야 하는데 균질성과 첨가성이다. homogeneity (균질성):   additivity (첨가성): 선형이라고 부르는 수식들은 중첩의 원리 가 적용된다는 특징이 있다. 이때 행렬과 선형 변환의 관계에 대하여도 알아보았었는데 선형 변환과 행렬은 1:1 대응된다. 기저 란 어떤 벡터 공간을 선형 생성하는 선형 독립인 벡터들이다. 각각의 원소들이 다시 벡터 공간을 생성할 수 있어야하고 일차 독립이어야 한다. 표준 기저 는 많은 기저들 중 성분 1개만이 1이고 나머지 성분이 모두 0인 표준 적인 벡터이다. 여기서 벡터 공간 R의 기저를 구성하는 원소의 개수가 해당 공간의 차원 이다. 행렬 은 열기반 행렬과 행기반 행렬 중 어떤 걸 사용하느냐에 따라 계산 방식이 달라진다. 여기서는 벡터의 크기, 회전, ...

[네트워크] 졸작 게임 서버 제작기 2

이번에는 서버에서 접속된 클라이언트 별로 어떻게 처리를 진행했는지 적어보려 합니다.












SessionManager는 네트워크 작업 시 사용할 버퍼 풀과 
앞의 포스트에서 이야기했던 토큰 풀 그리고 세션 풀로 이루어져 있습니다.
그리고 활성화 세션들의 목록을 가지고 있고 가져와 사용할 수 있습니다.

ClientSession은 Send, Receive 등 직접 처리해 주어야 할 일들을 구현했습니다.


class ClientEventSession
{
 void Reset();
 void Accept();
 void AcceptComplete(ClientToken* token);

 void Receive();
 void ReceiveFrom();
 void ReceiveComplete(ClientToken* token);
 void ReceiveFromComplete(ClientToken* token);
 void ProcessReceive(DWORD transperred);

 void ZeroByteReceive();

 void Send(ResizableBuffer* buf);
 void SendFrom(ResizableBuffer* buf);
 void SendComplete(ClientToken* token);
 void SendToComplete(ClientToken* token);

 void Disconnect();
 void DisconnectComplete(ClientToken* token);

...
}

세션에서 Send, Receive 등 요청이 이루어지면
앞의 게시글에 나와있던 IOCP 매니저에서 명령별로 ~Complete 메서드로 완료 작업을 합니다.

이 코드는 세션의 Receive 부분입니다.

void LunaNet::ClientEventSession::Receive()
{
 if (!IsConnected())
  return;


 SpinLockGuard lock(m_rcvlock);
 ClientToken* token = ownerSessionManager->GetTokenPool()->Pop();
 token->Set(this, SocketOperation::SO_Receive);

 token->m_wsabuf.buf = m_recvBuffer->GetCurBuffer();
 token->m_wsabuf.len = m_recvBuffer->GetCapacity();
 DWORD recvbytes;
 DWORD flags = 0;
 
 int retval = WSARecv(m_socket, &token->m_wsabuf, 1, &recvbytes, &flags,
  &token->m_overlapped, NULL);

 if (retval == SOCKET_ERROR)
 {
  if (WSAGetLastError() != WSA_IO_PENDING)
  {
   PRINTERR("WSARecv()");
   ReturnToken(token);
   Disconnect();
  }
  return;
 }
}

오너 세션 매니저에 있는 토큰 풀에서 토큰을 하나 꺼내와
해당 토큰에 현제 세션과 명령을 지정하고
WSARecv를 거는 간단한 코드입니다.


IO 작업이 완료되면
IOCPManager에 있는 명령에 따라 완료 작업을 진행합니다.


case SocketOperation::SO_Receive:
 token->m_session->ReceiveComplete(token);
 break;
(IOCPManager  일부)

ReceiveComplete에서 받은 데이터의 처리와 토큰을 반납하고 다시 Receive를 걸어줍니다.
void LunaNet::ClientEventSession::ReceiveComplete(ClientToken* token)
{
 if (token->byteTransperred == 0)
  return;

 ProcessReceive(token->byteTransperred);
 ReturnToken(token);
 
 Receive();
}

나머지 Accept, Send 등도 동일한 구조로 작동됩니다.

다음은 받은 패킷의 처리와 처리를 할 때 문제가 되었던 점 및 해결 방법을 작성하려 합니다.

댓글

이 블로그의 인기 게시물

[알고리즘] 브레젠험 직선 알고리즘 (Bresenham's line algorithm)

오일러 각, 로드리게스 회전 공식, 평면의 방정식

[알고리즘] 코헨 서더랜드 알고리즘(Cohen–Sutherland algorithm)