글

라벨이 gameserver인 게시물 표시

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

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

[카메라] 백페이스 컬링과 원근 투영

이미지
1. 백페이스 컬링 백페이스 컬링은 그리기 단계에서 화면상 보이지 않는 불필요한 폴리곤을 잘라내 렌더링을 하는 기법중 하나입니다. 컬링에는 백페이스 컬링, 오클루전 컬링, 프러스텀 컬링이 있습니다. 오클루전 컬링(Occlusion Culling)은 다른 오브젝트에 가려 카메라에 보이지 않는 오브젝트의 렌더링을 비활성화 하는 기법입니다. 프러스텀 컬링(View Frustum Culling)은 절두체 컬링이라고도 합니다. 해당 컬링은 실제로 카메라의 시야 범위에 포함되는 것들만 렌더링하고 나머지는 렌더링을 비활성화하는 기법입니다. 그럼 백페이스 컬링은 어떤 걸까요? 백페이스 컬링은 카메라에서 보이지 않는 뒷면의 폴리곤을 렌더링하지 않는 기법 입니다. 일단 백페이스 컬링을 위해서는 그리기 순서가 필요합니다. DirectX를 해보신 분을 알겠지만 DirectX에서 사각형을 그릴때 그리기 순서 즉 그려질 버텍스들의 인덱스 순서를 잘 맞춰줘야 원하는데로 그려집니다. 위와 같이 생긴 폴리곤을 그린다고 가정해보면 왼쪽 폴리곤은 반시계방향으로  오른쪽 삼각형은 시계 방향으로 돌아가며 그려집니다. 즉 왼쪽 폴리곤은 그려지고 오른쪽 폴리곤은 컬링 됩니다. 그럼 이걸 어떻게 컴퓨터에서 인지하고 컬링을 해줄까요? 위의 정보는 두 벡터 값으로 표현할 수 있습니다. 그리고 두 벡터 값을 외적하면 해당 축과 직교하는 벡터가 나오는데  이 벡터가 카메라 방향을 향한다면 그려주고 반대라면 컬링합니다. 이제 방향을 향하고 있는지 아닌지는 내적을 이용하면 간단하게 구할수 있습니다. 사용하는 코드에서는 오른손 좌표계를 사용하기 때문에 화면에 그릴려면 (0,0,-1)과 내적하여 양수의 값이 나온다면 컬링합니다. 반대로 (0,0,1)로 내적하면 결과 값이 양수라면 그려주기만 하면됩니다. 왼쪽: 백페이스 컬링 미적용,  오른쪽: 백페이스 컬링 적용 2. 원근 투영 원근 투영 행렬을 유도하기 전에 카메라가 렌더링할 영역을 보면 아래와 같은 모양의 절두체가 나올 겁니다. 절두체는 ...

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

이미지
패킷 분리 현상과 패킷의 처리 TCP를 이용해 Stream 방식으로 데이터를 전송하다 보면 간혹 데이터가 쪼개지거나 다른 것과 합쳐져서 들어오는 경우가 있습니다. 그림이 표현이 뜻에 따라 잘 된 건지는 모르겠지만 아래 그림을 보면 분명 3의 크기를 가진 패킷을 보냅니다. 하지만 간혹 패킷이 분리돼서 들어오는 현상이 있습니다. 그리곤 나중에 받죠. 이렇게 분리된 패킷을 가지고 처리를 할 경우 대부분 오류가 날겁니다. 조금 더 자세히 보겠습니다. 일단 패킷의 헤더는 패킷의 크기: 2byte 패킷의 아이디 값: 2byte 압축 여부: 1byte 등으로 간단하게 되어있습니다. 요렇게 생긴 총 35 Byte 짜리 패킷이 전송된다고 보면 패킷 헤더의 패킷 크기는 35byte가 저장되어 있을 겁니다. 그럼 처리를 할 때 35byte를 처리를 하겠죠 하지만! 요런식으로 패킷이 분리돼서 들어오거나 다른 패킷이랑 합쳐져서 들어오면.... 일단 헤더에서 패킷의 크기가 35byte 입니다. 놔두면 크기에 맞게 처리를 시도할 겁니다. 하지만 실제로 쓰인 데이터는 20byte 입니다. .... 그래서 분리되거나 합쳐진 데이터를 붙여주고 나누어 주어야 합니다. 그래서 아래와 같은 코드를 작성했습니다. UINT16 size = 0 ; if (!m_recvSr.Read(size)) // 패킷의 사이즈를 읽습니다. { m_recvBuffer->Pending(transperred); return ; } // 현제 버퍼에 쓰여진 사이즈와 받아온 데이터의 사이즈가 // 패킷 헤더에 기록되어있는 사이즈보다 작다면 Pending 후 리턴해줍니다. if (size > m_recvBuffer->GetDataSize() + transperred) { m_recvBuffer->Pending(transperre...

[네트워크] 졸작 게임 서버 제작기 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::ClientEventSe...

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

이미지
처음에는 쓸까 말까 고민했지만 졸업작품에 사용하는 게임 서버 제작기를 간단하게 쓰기로 결정했습니다. 아직 배울 것이 한참 많아 틀린 부분이나 좋지 않은 부분이 많겠지만 양해 부탁드립니다. 혹시 틀린 점이나 고치면 좋은 부분이 있다면 언제든지 알려주세요! 서버 및 클라이언트 개발 환경 서버: C++, windows 클라이언트: C#, Unity 서버와 클라이언트 둘 다 기본적으로 비동기 방식을 이용했습니다. 첫 번째는 서버와 측의 기본 네트워크 코드에 대해서 작성해 보려합나다. (이미 연동되고 게임 로직을 짜고 있긴 하지만... 처음부터 한다는 느낌으로...) 처음에는 저희 졸업작품 팀에서 클라이언트가 C#이라서 서버도 C#으로 만드는게 편할까? 라는 생각을 했습니다. 라이브러리 공유도 힘들고 C#, C++ 왔다갔다 하면서 비슷한 코드를 두 번 만들어야하고... (물론 CLR나 P/Ivoke 방식도 고민했습니다.) 차근차근 진행해보겠습니다! 일단 서버 객체입니다. 크게 보면 IOCPManager, SessionManager, LogicManager 이렇게 세가지로 이루어져 있습니다. IOCPManager는 기본적으로 IO작업의 처리를 담당합니다. SessionManager는 SessionPool을 가지고 있고 Accept 처리와 각 세션에 대한 총괄 관리를 합니다. LogicManager는 분류된 패킷들을 처리합니다.   먼저 IOCPManager 를 작성하겠습니다. 1. 윈도우 소켓을 초기화 한 후 IOCP를 만들어줍니다. // Winsock Init WSADATA wsa; if (WSAStartup(MAKEWORD( 2 , 2 ), &wsa) != 0 ) return false ; // Create IOCP m_CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE...