iOS 자동빌드를 위해 Jenkins에 연결 중..

빌드 시 SVN의 저장소가 lock이 걸렸다는 로그가 콘솔에 찍히며 빌드에 실패했다. 

젠킨스 빌드의 Console Output

뭘까.. 하다가 검색해보니 .svn에 lock파일을 지우거나 Clean up을 해주면 된다고 했다.

.svn에 lock파일은 없었고 없으면 Clean up해주면 된다는 내용대로 따라해보기로 했다.

(lock파일이 없으면 wc.db 파일을 SQLite를 실행해 작업을 해주면 된다는데... SQLite를 다운받아서 데이터베이스 파일을 까고싶지는 않았다...)

Clean up을 하고 다시 빌드를 눌렀는데..! 

똑같은 에러가 발생하며 빌드에 실패했다.

 

무엇이 문제인고 하니

 

Clean Up의 기본 설정에서 Breakup Lock을 체크해주지 않아서.. Lock이 풀리지 않았던 거였다.

웃겼다..

 

오늘도 다사다난하게 해결완료했다. 

 

 

닷넷 API

 

 

 

C#이 사용할 수 있는 API 집합체인 닷넷에는 굉장히 많은 API가 있다.

 

 

◎ 닷넷 API 탐색기와 Docs

 

마이크로소프트는 닷넷 API 탐색기를 제공하여 웹에서 모든 API 검색을 할 수 있다.

https://docs.microsoft.com/en-us/dotnet/api/

위의 링크를 들어가보면 API를 검색할 수 있다. 

 

닷넷에서 제공하는 대부분의 API는 클래스이다.

그리고 구조체, 열거형이 있고, 이러한 클래스, 구조체, 열거형을 특정 이름으로 묶어 관리하는 네임스페이스가 있다. 

 

* 클래스 (Class)

: Console 클래스, String 클래스 등 거의 대부분이 클래스이다. 

 

* 구조체 (Struct)

: DateTime 구조체, TimeSpan 구조체 형태로 표현하며, 클래스와 거의 동일하게 사용한다.

 

* 열거형 (enumeration)

: Color 열거형 등이 있으며, 특정 목록을 관리할 때 편리하다.

 

* 네임스페이스 (namespace)

: System 네임스페이스처럼 많은 양의 클래스와 구조체, 열거형을 묶어서 관리한다. 

 

 

위의 API 탐색기에서 Math를 검색했을 때 System.Math를 클릭해보면 기능들을 더 자세히 볼 수 있다. 

 

 

 

 

참고 자료;

C# 교과서 (저; 박용준 출판사; 길벗) 

 

https://programmers.co.kr/learn/courses/30/lessons/1829#

 

코딩테스트 연습 - 카카오프렌즈 컬러링북

6 4 [[1, 1, 1, 0], [1, 2, 2, 0], [1, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 3], [0, 0, 0, 3]] [4, 5]

programmers.co.kr

 

 

재귀를 이용한 DFS 방식으로 풀었다.

방문한 픽셀은 color값을 0으로 바꿔주고 방문 시에 해당 픽셀의 color값을 비교해 같은 부분인지 체크하는 방식으로 풀었다. 

 

 

 

#include <iostream>
#include <vector>
using namespace std;

vector<vector<int>> v;
int sizeN, sizeM;
int maxSize = 0;

bool dfs(int x, int y, int color)
{
	if (x <= -1 || x >= sizeN || y <= -1 || y >= sizeM)
	{
		return false;
	}

	if (v[y][x] != 0 && v[y][x] == color)
	{
		v[y][x] = 0;
		maxSize += 1;
		dfs(x - 1, y, color);
		dfs(x, y - 1, color);
		dfs(x + 1, y, color);
		dfs(x, y + 1, color);
		return true;
	}
	return false;
}


vector<int> solution(int m, int n, vector<vector<int>> picture) {
	vector<int> answer(2, 0);
	int number_of_area = 0;
	sizeN = n;
	sizeM = m;
	v = picture;

	for (int i = 0; i < m; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			if (dfs(j, i, picture[i][j]))
			{
				number_of_area += 1;
				answer[1] = maxSize > answer[1] ? maxSize : answer[1];
				maxSize = 0;
			}
		}
	}
	answer[0] = number_of_area;
	return answer;
}

 

 프로그래머스 홈페이지에서 그냥 풀다가 dfs 함수를 if문으로 체크하는 부분에 i와 j를 반대로 줘서 분명 맞는데 왜 값이 다르게 나오지? 하고 디버깅까지 찍어봤다ㅠ

[y][x] 방식으로 이용하는데 함수에 인자로 넘겨줄 때 x,y 순서로 넘겨주고 있어서 문제가 생겼던 것이다... 

 

 

트리

Tree




트리는 객체간의 관계를 표현하는 자료구조인 그래프의 일종이다.

◎ 트리란

트리는 노드들이 가지처럼 연결된 비선형 계층적 자료구조이다.

노드 : 트리의 구성요소에 해당하는 A,B, C, D, E, F와 같은 요소
간선 : 노드와 노드를 연결하는 연결선
루트 노드 : 트리 구조에서 최상위에 존재하는 A와 같은 노드
단말 노드 : 아래로 또 다른 노드가 연결되어 있지 않은 가장 마지막 (E,F,C,D와 같은) 노드
내부 노드 : 단말 노드를 제외한 모든 노드
레벨 : 각 층 별로 숫자를 매긴 것
높이 : 트리의 최고 레벨

◎ 이진트리

이진트리란 루트 노드를 중심으로 두 개의 서브 트리로 나누어지며 나누어진 두 서브 트리도 모두 이진 트리여야 한다.
즉, A를 기준으로 B,D,E가 왼쪽 서브 트리 C,F,G가 오른쪽 서브트리이며 각각의 서브 트리들도 이진 트리여야 한다.

여기서 왼쪽과 같은 트리도 이진트리가 된다.
노드가 위치할 수 있는 곳에 노드가 존재하지 않으면 공집합 노드가 존재하는 것으로 간주해 공집합 노드도 '노드로 인정'하기 때문이다.

이진 트리는 여러 분류로 나뉠 수 있는데 그 중 완전 이진트리와 포화 이진트리가 존재한다.

포화 이진 트리는 위의 그림과 같이 모든 레벨이 꽉 차 있으며 노드를 더 추가하려면 레벨을 늘려야 하는 트리이다.

이 포화 이진 트리에서 레벨을 하나 더 늘려 H와 I를 추가한 다음 이진 트리를 보면 포화 이진 트리처럼 모든 레벨이 꽉 찬 상태는 아니지만 차곡차곡 빈 틈 없이 노드가 채워진 이진 트리가 된다.
여기서의 '차곡차곡 빈 틈 없이'는 노드가 위에서 아래로, 그리고 왼쪽에서 오른쪽의 순서대로 채워졌다는 의미가 된다.
이 트리가 바로 완전 이진 트리이다.

완전 이진트리는 임의의 두 단말 노드의 레벨 차이가 1이하인 경우이며 위의 그림과 같이 왼쪽에서 오른쪽으로 채워진 이진트리를 뜻한다.
레벨 n까지의 모든 노드수는 2^n -1개이다.


◎ 트리의 순회

트리의 순회란 트리에 속하는 모든 노드를 한 번씩 방문하는 것이다. 트리의 순회 방식에는 전위, 중위, 후위 방식이 있다.
루트를 방문하는 작업을 V, 왼쪽과 오른쪽 서브 트리를 방문하는 작업을 각각 L과 R이라고 하면
전위는 VLR, 중위는 LVR, 후위는 LRV 이다.

트리의 순회는 쉬워보이지만 복잡한 노드의 트리인 경우 생각보다 헷갈리게 된다.

[출처/ 위키피디아_트리 순회]

다음과 같은 사진이 있을 때 전위, 중위, 후위 순회의 결과는 다음과 같다.
전위 순회 : F,B,A,D,C,E,G,I,H
중위 순회 : A,B,C,D,E,F,G,H,I
후위 순회 : A,C,E,D,B,H,I,G,F

전위 순회

Void preorder(TNode *n) 
{ 
	If( n!= NULL ) 
    { 
    	Printf(“[%c]”, n->data); 
        Preorder(n->left); 
        Preorder(n->right); 
     }
}

 

중위 순회

Void inorder(TNode *n) 
{ 
	If( n!= NULL ) 
	{ 
    	inorder(n->left); 
        Printf(“[%c]”, n->data); 
        inorder (n->right); 
    } 
}

 

후위 순회

Void postorder(TNode *n) 
{ 
	If( n!= NULL ) 
	{ 
    	postorder(n->left); 
        postorder (n->right); 
        Printf(“[%c]”, n->data); 
    } 
}



참고로 이 트리의 전위순회 방식을 일반화시킨 그래프의 정점 순회 방법이 깊이 우선탐색 (DFS)이다.
탐색 도중에 인접된 모든 정점이 이미 방문된 정점을 만났을 때 바로 이전에 방문한 정점으로 돌아가기 위해 스택을 사용한다.



참고 자료;
윤성우의 열혈 자료구조 (저; 윤성우, 출판; 오렌지 미디어)


https://ko.wikipedia.org/wiki/%ED%8A%B8%EB%A6%AC_%EC%88%9C%ED%9A%8C

 

 

어댑터

Adapter

 

 

 

어댑터 패턴은 다른 이름으로 Wrapper라고 불리기도 하며 인터페이스가 호환되지 않는 클래스들을 함께 이용할 수 있도록 타 클래스의 인터페이스를 기존 인터페이스에 덧씌우는 패턴이다.

이미 만들어진 클래스를 새로운 인터페이스에 맞게 개조시킬 때 사용하거나 기존 클래스를 개조해 필요한 클래스를 만들 때 사용한다. 

 

 

어댑터 패턴의 구현에는 두 가지 종류가 있다. 

◎ 객체 (Object) Adapter 패턴과 클래스 (Class) Adapter 패턴

 

출처; 위키/어댑터 패턴

1. 객체(Object) : 위임을 사용한 객체 어댑터 패턴

어댑터가 변환하려고 하는 클래스의 인스턴스를 가지고 있다.

 

 

 

출처; 위키/어댑터 패턴

2. 클래스(Class) : 상속을 사용한 클래스 어댑터 패턴

어댑터가 여러개의 다형성 인터페이스를 사용한다.

여러 개의 인터페이스를 상속하거나 구현해서 어댑터가 생성된다. 

 

 

 

◎ 장/단점

  객체 어댑터 클래스 어댑터
장점 상속이 아닌 구성(Composition)을 사용하기 때문에 더 유연 1. 어댑터가 Adaptee의 서브클래스이기 때문에 Adaptee의 행동을 오버라이드할 수 있다.
2. Adaptee 객체를 만들지 않아도 된다. 
단점 Adaptee 객체를 만들어야 사용 가능 1. 다중 상속이 지원되는 언어에서만 사용이 가능하다.
2. 상속을 이용하므로 한 어댑터 클래스가 특정 Adaptee 클래스에만 적용이 가능하다

 

 

 

 

 

 

참고 자료;

https://en.wikipedia.org/wiki/Adapter_pattern

https://arisu1000.tistory.com/27679

https://invincibletyphoon.tistory.com/20

https://ansohxxn.github.io/design%20pattern/chapter13/

 

 

유니티의 렌더 파이프라인

LWRP, URP

 

 

 

렌더링 파이프라인은 3D 데이터들이 2D 이미지로 구성되어 그려지는 일련의 과정을 뜻한다. 

 

◎ 렌더링 파이프라인

렌더링 파이프라인에서 데이터를 처리하는 과정을 간략하게 나눠 보자면 다음과 같다.

 

실제 파이프라인은 더 많은 과정을 거치고 플랫폼마다 다를 수 있지만 공통적이고 핵심적인 과정만 뽑자면 이 세 단계를 거치게 된다.

 

플리케이션 스테이지

애플리케이션 스테이지는 애플리케이션 상에서 처리되는 단계를 의미한다.

그래픽스 렌더링 파이프라인은 보통 GPU 파이프라인을 의미하므로 CPU에서 연산되는 애플리케이션 스테이지는 포함되지 않지만 본격적인 렌더링 파이프라인 진입 전 CPU에서 필요한 연산들을 처리해야 하므로 큰 의미로는 렌더링 파이프라인의 일부분이 된다. 

ex) 플레이어의 매 프레임마다의 움직임, 애니메이션 정보와 뼈대 위치 연산 및 메시의 버텍스에 반영 등

 

현재 프레임에서 렌더링 가능한 오브젝트들이 컬링 연산에 의해 구별된다. 

이 컬링 단계에서 효율적으로 오브젝트들이 선별되어 렌더링 되는 오브젝트 수를 줄이면 그만큼 GPU에서 처리하는 연산량이 줄게 된다. 

또한 배칭처리를 위한 연산도 GPU 파이프라인에 진입하기 전에 이루어진다. 

 

지오메트리 스테이지

이 스테이지에서는 말 그대로 지오메트리 관련 정보, 즉 지오메트리를 구성하는 요소인 버텍스와 폴리곤 처리를 담당하며 아래와 같은 과정들을 거친다.

1. 월드-뷰-프로젝션 트랜스폼
2. 클리핑
3. 버텍스 쉐이더

 

버텍스 트랜스폼(Vertex Transform)?

더보기

렌더링을 수행해야 되는 시점에 GPU가 메모리로부터 버텍스 정보를 가져와 적절한 위치에 그려주기 위해서 수행하는 트랜스폼이다. 

 

 

래스터라이저 스테이지

이 스테이지에서는 오브젝트를 그리는 픽셀들을 추리고 그 픽셀의 색을 결정한다.

버텍스 쉐이더를 거쳐서 지오메트리들이 구축되면, 화면(혹은 버퍼)의 어느 픽셀에 그려져야 하는지 결정된다.

메시의 폴리곤에 속한 영역을 픽셀로 매칭시키는 과정을 래스터라이제이션이라고 부른다. 

 

레스터라이제이션이 끝나면 최종적으로 화면에 그려져야 할 픽셀의 최종 색이 결정된다.

즉, 해당 스테이지에서는 렌더링하는 메시가 화면에 매칭되는 픽셀을 결정하고 최종 색을 입히는 과정이다.

 

뎁스 버퍼, Z-버퍼를 이용해 깊이 판정을 하고 블렌딩을 통해 최종 출력 색상을 결정한다.

 

블렌딩?

더보기

투명도를 가지는 오브젝트는 픽셀 렌더링 시 알파 블렌딩 과정을 거친다.

알파 블렌딩은 쉐이더에서 결정되는 알파값을 이용한다. 픽셀 출력의 알파값을 이용해서 해당 픽셀 위치의 컬러 버퍼의 기존 값과 적절하게 혼합해 최종 출력 색상을 결정한다. 

 

 

 

 

◎ 유니티가 제공하는 파이프라인 

유니티는 2018년부터 유니티의 렌더링 처리 방식을 C# 스크립트로 제어할 수 있는 기능인 SRP(Scriptable Render Pipeline) 기능을 제공했다.

이를 통해 전반적인 렌더링 루프를 직접 구성할 수 있으며 직접 렌더링 루프를 커스터마이징해 원하는 방식으로 렌더링을 구성할 수 있게 되었다. 

또한 SRP의 등장과 함께 유니티에 기본적으로 구현되어 있는 기본 렌더링 파이프라인빌트인(내장) 파이프라인이라고 부르게 되었다. 

 

 

1. HDRP (High Definition Render Pipeline)

하이엔드나 PC 콘솔 등을 고려해서 고품질의 비주얼 구현에 적합한 파이프라인이다.

포워드 렌더링, 디퍼드 렌더링을 모두 지원하며 컴퓨터 쉐이더 기술과 GPU 하드웨어를 사용한다. 

하지만 기본적으로 요구되는 하드웨어 스펙이 높아서 모바일 게임용으로는 적합하지 않다.

 

2. URP (Universal Render Pipeline)

Unity 2019.3 버전부터 LWRP(Lightweight Render Pipeline)이 유니버설 렌더 파이프라인으로 변경되었다. 

 

LWRP는 모든 모바일 디바이스에서 고품질 그래픽스를 구현하는 빠르고 확장 가능한 파이프라인이다. 

URP는 기본 빌트인 렌더 파이프라인보다 유연하고 확장성이 좋으며 다양한 플랫폼에 최적화된 그래픽을 제공한다.

싱글 패스 포워드 렌더링과 셰이더 그래프, VFX 그래프를 지원한다. 

https://blog.unity.com/kr/technology/how-the-lightweight-render-pipeline-is-evolving

 

 

 

참고 자료;

유니티 그래픽스 최적화 스타트업 (저; 오지현(오즈라엘), 출판사; 비엘북스, 감수; 정종필) 

 

 

슬라이딩 벡터

Sliding Vector

 

 

 

슬라이딩 벡터는 충돌 시에 입사벡터가 입사면을 따라서 미끄러지게 하기 위해서 수평 성분만을 남긴 벡터이다. 

구하는 방법에는 반사벡터를 이용해 구하는 방법과 일반적인 방법이 있다.

 

반사 벡터를 이용해서 구하는 방법

 

반사 벡터에서 입사벡터 P에 n(-P·n)을 한번 더해주면 입사면에 투영된 접선벡터를 구할 수 있다.

입사벡터의 역벡터 -P가 n에 투영된 n(-P·n)을 이용해 슬라이딩 벡터를 구하고 있는 중이다.

따라서 반사 벡터를 이용할 때 슬라이딩 벡터 S를 구하는 공식은 다음과 같다. 

S = P + n(-P·n)

 

 

 

◎ 일반적인 방법

일반적인 방법으로는 입사벡터 P를 n에 바로 투영시킨다.

입사벡터 P와 법선벡터 n의 끼인 각이 0≤ θ ≤ π/2 일 때, P·n의 값은 음수가 되므로, n벡터의 역벡터 방향으로 투영 벡터가 생성된다.

 

이렇게 얻을 수 있는 투영벡터 n(-P·n)을 입사벡터 P에서 빼주면 슬라이딩 벡터 S를 얻을 수 있다.

이때의 슬라이딩 벡터 S를 구하는 공식은 다음과 같다.

 

S = P - n(-P·n)

 

 

 

 

 

참고 자료;

https://toymaker.tistory.com/entry/%EB%AF%B8%EB%81%84%EB%9F%AC%EC%A7%90-%EB%B2%A1%ED%84%B0-Sliding-Vector?category=500302 

 

 

반사벡터

Reflection Vector

 

 

 

반사 벡터는 정반사이다.

정반사는 입사각과 반사각이 동일한 반사를 의미한다. 

 

◎ 투영 벡터

반사 벡터를 구하려면 투영 벡터를 먼저 구해야 한다.

투영이란 어떤 벡터 v를 단위 벡터 n에 내적하여 구할 수 있는 v의 n방향으로의 길이를 뜻한다. 

내적값이 스칼라이므로 투영된 방향으로의 벡터를 구하려면 이 내적값에 방향벡터 n을 곱해주면 된다. 

(v·n)n을 이용해 벡터를 구할 수 있게 된다. 

* 왜 이렇게 되는지 추가 설명!

더보기

v와 n을 내적하면 cosθ를 결과값으로 얻게 된다.

v·n = ||v||||n||cosθ

 

여기서 이 삼각형은 직각삼각형이므로 코사인값은 밑변/빗변 즉, ||n|| / ||v|| 이다.

||n|| = ||v||cosθ 이고 투영한 길이를 w라고 했을 때

w = ||v||cosθ가 된다. 

 

길이를 구했으니 방향도 알아야 하는데, 길이가 1인 단위벡터는 방향의 정보만을 갖고 있으므로 

단위벡터인 n의 방향으로의 길이를 구하려는 투영의 값에 n을 곱해주면 된다.

 

n의 방향 벡터 = n / ||n||

투영 벡터 = ( n / ||n|| ) * ||v||cosθ

 

하지만 두 벡터 사이각을 항상 알 수 없으므로

v·n = ||v||||n||cosθ 라는 사실을 응용해서 v·n/||n|| = ||v||cosθ 이런식을 만들어내면

두 벡터만 주어졌을 때, 한 벡터를 다른 벡터에 투영하는 공식을 구했을 때

((v·n) / ||n|| ) * ( n / ||n|| ) 이런 공식이 나오게 된다.

 

◎ 반사벡터 

투영 벡터를 이용해 구한 벡터로 반사 벡터를 계산한다.

다음과 같이 입사벡터(P)와 법선 벡터(n)이 있을 때 반사 벡터(R)은 입사벡터(P)와 크기가 같고 반사각과 입사각이 같다.

P와 n을 이용하면 반사벡터(R)을 구할 수 있다. 

 

우선 위의 투영 벡터를 구하는 방식을 이용해 입사 벡터 P의 역벡터 -P를 n의 연장선상에 투영시켜서 투영벡터 n(-P · n)을 구한다. 

 

어떻게 투영 벡터를 구하는건지? 

더보기

이렇게 돌려보면 쉽게 알 수 있다!

 

그 후 입사 벡터 P의 시작 위치를 원점에 위치 시키고 투영으로 구한 n(-P·n)를 더하면 입사면에 투영된 벡터의 위치를 구할 수 있다. 

입사 벡터 P에 n(-P·n)를 한 번 더하면 입사면에 투영된 위치를, 두번 더하면 반사벡터 R을 구할 수 있다.

 

따라서 반사벡터 R을 구하는 공식은 다음과 같다.

R = P + 2n(-P·n)

 

 

 

 

참고 자료;

https://toymaker.tistory.com/entry/%EB%B0%98%EC%82%AC-%EB%B2%A1%ED%84%B0-Reflection-Vector


https://ifyouwanna.tistory.com/entry/%EB%B0%98%EC%82%AC%EB%B2%A1%ED%84%B0


https://gyong0.tistory.com/22

+ Recent posts