그래픽스에서 조명은 빛과 물체 간의 상호작용을 처리하는 기술이다. 보통 지역 조명과 전역 조명 모델 두 가지로 구분된다.

지역 조명은 광원으로부터 물체에 직접 들어오는 빛만을 고려하기 때문에 표면의 재질과 광원의 속성만으로 표면의 색상이 결정된다.

하지만 실세계의 모든 물체는 간접 조명을 받기 때문에 전역 조명 모델은 모든 물체를 잠재적인 광원으로 취급한다.

그렇다고 전역 조명 모델을 그대로 적용하기에는 너무 많은 연산을 필요로 하기 때문에 실시간에 구현하는 것은 어렵다.

 

그래서 게임에서는 간략화된 전역 조명 알고리즘을 사용하거나 미리 전역 조명을 계산하여 저장한 뒤 런타임에 이를 사용하는 것이 보편적이다.

 

 

퐁 조명 모델

퐁 모델은 지역 조명 모델이다.

퐁 모델의 경우 물체의 표면에서 감지되는 색상은 아래와 같은 4가지 항목에 의해 결정된다.

 

 

◾ 디퓨즈(diffuse) 반사

램버트의 법칙에 따라 설명된다. (*램버트의 법칙 : 물체의 표면에 들어오는 빛의 세기는 표면에서 빛까지의 벡터 l과 법선 n이 이루는 코사인 값에 비례한다. 각도가 작을수록 더 많은 빛을 받는다.)

램버시안 표면 또는 이상적인 디퓨즈 표면으로 들어온 빛은 모든 방향을 따라 같은 강도로 반사된다. (난반사)

단, l과 n이 이루는 각이 둔각인 경우 음수가 나오기 때문에 최소값을 0으로 처리해야 한다.

 

◾ 스페큘러(specular) 반사

물체 표면에 하이라이트를 만드는데 사용된다. 시선 벡터(v)와 반사 벡터(r)가 필요하다.

시선 벡터는 물체 표면의 점 p와 카메라를 연결하고 카메라 시선과 반대 방향으로 정의한다.

반사 벡터는 점 p의 법선 벡터 n과 조명간의 입사각과 동일한 각도를 이루며 반사된다.

 

하이라이트를 볼 수 있는 영역은 r을 중심으로 한 원뿔 모양으로 묘사할 수 있고 v가 원뿔 범위 안에 속한다면 하이라이트를 볼 수 있다.

 

◾ 앰비언트(ambient) 반사

다양한 물체로부터 반사된 빛, 즉 간접 조명을 앰비언트 라이트라고 부른다.

씬의 모든 지점에서 반사된 빛이 어우러진 것이기 때문에 특정 방향이 아닌 모든 방향을 따라서 표면의 p점에 들어오며 마찬가지로 반사된다.

그렇기 때문에 p점에 들어오는 앰비언트 라이트의 양은 p점의 법선에 독립적이고 반사되는 빛은 카메라 시선에 독립적이다.

 

◾ 발산광(emissive light)

물체 스스로 발산하는 빛이다.

지역 조명 모델은 발산광을 가진 물체를 광원으로 취급하지 않기 때문에 같은 공간의 다른 물체의 조명 연산에 영향을 주지 않는다.

 

 

퐁 조명 모델은 위의 4개 항을 더해서 정의된다.

 

 

쉐이더와 쉐이딩 언어

쉐이더 프로그래밍을 위해 선택되는 하이레벨 언어 중 하나는 HLSL, Cg, GLSL가 널리 사용되고 모두 C와 비슷한 언어이다. 이 중 HLSL은 Direct3D에서 사용된다. 책에서는 HLSL에 대해서만 다루게 된다.

 

쉐이더에서 함수는 최상위 함수와 내장 함수로 구분되고 정점 및 프래그먼트 쉐이더 자신은 최상위 함수이다. 최상위 함수는 여러 내장 함수를 호출할 수 있는데 빈번하게 호출하는 함수는 곱셈 연산을 위한 mul이다.

쉐이더는 실행시마다 변하는 데이터와 모든 쉐이더 실행 시 공유되는 데이터 두 가지 형태의 입력 데이터를 받는다.

 

조명은 정점별로 적용할수도 있고 프래그먼트별로 적용할 수도 있다. 대체로 프래그먼트별로 적용하는 것이 더 우수한 결과를 생성한다. 정점별로 적용하면 카메라의 위치에 따라 반사광이 균일하지 않을 수 있지만 프래그먼트별로 적용하면 항상 균일한 반사광을 볼 수 있다.

다만 프래그먼트별로 적용하는 조명에서는 정점 쉐이더의 역할은 미미해진다.

 

 

전역 조명

대표적인 전역 조명 알고리즘으로는 레이 트레이싱과 래디오시티가 있다. 

 

◾ 레이 트레이싱

뷰 프러스텀은 카메라에 수렴하는 투영선의 집합이고 투영선의 개수는 뷰포트의 해상도와 동일하다. 즉, 투영선 하나가 픽셀 하나의 색상을 결정하는 것이다.

레이 트레이싱 알고리즘에서는 뷰 프러스텀이 정의된 카메라 공간 물체에 투영 변환을 적용하는 대신에 각 투영선의 반대 방향으로 광선을 발사하고 이를 추적하여 해당 투영선을 따라서 들어오는 색상을 계산한다.

이게 바로 픽셀 색상이 되고 1차 광선이라 정의할 수 있다.

 

1차 광선이 씬의 어떤 물체와도 부딪히지 않으면 씬의 배경색으로 픽셀 색상이 결정된다. (아무런 물체도 통과하지 못했으니 애초에 물체가 존재하지 않는 영역이라는 뜻 같음)

만약 1차 광선이 어떤 물체와 부딪히면 해당 점이 그림자 안에 있는지를 검사하기 위해 그림자 광선이라는 2차 광선을 각 광원을 향해 발사한다. 이 때 그림자 광선이 광원으로 진행하는 도중에 다른 물체와 부딪히면 해당 교차점은 광원의 직접적인 영향권에 있지 않다는 의미가 된다. 그림자 광선이 광원에 도달하면 교차점에 입사하는 빛을 이용해서 직접 조명 색상을 결정하게 된다.

 

그림자 광선뿐만 아니라 반사 광선과 굴절 광선 2종류가 교차점에서 추가로 발사된다. 이 두가지 광선을 간접 조명을 계산하기 위한 목적으로 발사된다.

 

레이 트레이싱 알고리즘은 재귀적인 알고리즘이고 광선 트리가 씬을 벗어나거나 미리 정의된 재귀 단계에 도달할 때까지 확장된다.

 

 

◾ 래디오시티

디퓨즈 표면 사이에서 반사되는 빛을 시뮬레이션 한다.

래디오시티 알고리즘은 실시간에 구현하기에는 연산량이 너무 많기 때문에 보통 라이트맵으로 미리 만들어둔다.

'이론 > 그래픽스' 카테고리의 다른 글

[Chapter 4] 프래그먼트 처리와 출력 병합  (0) 2023.05.11
[Chapter 3] 래스터라이저  (0) 2023.05.11
[Chapter 2] 정점 처리  (0) 2023.04.27
[Chapter 1] 폴리곤 메쉬  (0) 2022.09.16

래스터라이저에 의해 생성된 프래그먼트들은 다양한 속성들을 포함할 수 있고 이 속성들을 이용해서 각 프래그먼트의 최종 색상을 결정할 수 있다. 프래그먼트 프로그램은 스크린 영상의 품질에 결정적인 영향을 미치기 때문에 다양한 종류의 알고리즘이 개발되었는데, 주로 조명과 텍스쳐링에 집중된다.

 

 

◾ 텍스쳐링

텍스쳐는 대게 텍셀의 2차원 배열 형태를 가진다 (texture element의 준말. picture element의 준말인 픽셀과 구분하기 위해 사용)

정규화된 텍스쳐 좌표인 uv 좌표를 사용한다.

 

텍스쳐 좌표를 정점에 할당하는 작업을 표면 파라미터화라고 부른다. 이 작업을 위해서는 3차원 메쉬를 2차원 평면에 펼쳐야 한다. 보통 2차원 평면으로 펼치는 과정에서 대부분 왜곡 현상이 일어나지만 왜곡을 최소화 하는 좋은 알고리즘들이 존재한다.

그나마 파라미터화 에러를 줄일 수 있는 방법 중 하나는 메쉬를 여러개로 쪼개서 부분별로 수행하는 것이다.

 

스캔 변환이 완료되면 각각의 프래그먼트는 보간된 uv좌표를 가지게 된다. 이를 텍셀 주소로 매핑하는 작업은 렌더링 과정중에 자동으로 수행된다.

대부분의 경우 텍셀 주소는 부동소수점으로 표현되고 텍셀 주소가 계산되면 주변의 텍셀들을 모아서 최종적인 색상 값을 결정하는 필터링 과정이 필요하게 된다.

 

 

◾ 출력 병합

렌더링 파이프라인의 마지막 단계이다. 프래그먼트의 출력은 단순히 RGB값만 가지고 있는것이 아니라 알파값과 깊이값을 가지고 있기 때문에 RGBAZ 프래그먼트라고도 표현된다. 알파 및 깊이 값을 사용하여 프래그먼트는 컬러 버퍼의 픽셀과 경쟁하기도 하고 결합되기도 한다.

 

동일한 x,y 좌표에 위치한 픽셀의 출력 우선순위는 카메라에 더 가까운쪽이 그려지는것이 이치에 맞는다.

이러한 결정을 하는 알고리즘을 z-버퍼링(깊이 버퍼링)이라고 부른다.

깊이 버퍼는 컬러 버퍼와 동일한 해상도를 가지며 현재 컬러 버퍼에 저장되어 있는 z값을 저장한다. 이후 출력 병합 단계에서 둘을 비교하여 더 작은 z값으로 컬러 버퍼의 픽셀을 대체해가며 픽셀을 결정한다.

 

하지만 반투명 물체를 렌더링할 때에는 얘기가 조금 달라진다. 반투명한 프래그먼트의 z값이 컬러 버퍼에 있는 픽셀의 z값보다 작은 경우 기존대로라면 완전히 대체가 되지만 이때는 픽셀이 프래그먼트를 통해 비쳐서 보여야 한다.

픽셀과 프래그먼트 색상의 혼합이 일어나야 하는 것이고 이를 알파 블렌딩이라 부른다.

알파 채널은 보통 RGB 각각의 채널과 같은 크기의 비트 수를 가진다.

 

중요한 사실 중 하나는 불투명한 삼각형들에 대한 z버퍼링 수행은 삼각형들의 처리 순서가 상관이 없지만 반투명한 삼각형들에 대한 z버퍼링은 뒤에서부터 앞으로 순차적으로 이루어져야만 한다는 차이가 있다. 이를 위해서 반투명한 삼각형들은 정렬 되어야 하지만 간단한 문제가 아니다.

 

 

◾ Z-컬링

z-버퍼링 과정에서 버려지는 프래그먼트들은 앞선 과정에서 텍스처링 작업 등 여러 가지로 수행된 고비용 연산들이 헛수고가 된거나 마찬가지이다.

만약 프래그먼트 처리 단계에 진입하기 전에 버려질 프래그먼트라는 것을 미리 알 수 있다면 즉각적으로 버림으로써 연산량을 크게 줄일 수 있을 것이다. 이 작업은 z-컬링이라고 하고 래스터라이저의 일부 과정이다.

 

z-컬링 알고리즘은 스크린 전체를 감싸는 타일들을 관리하게 된다. 하나의 타일은 n*n 픽셀 영역을 맡게 되고 타일의 픽셀들 중 z값이 가장 큰 값을 저장한다. 이후 래스터라이저가 처리중인 새로운 삼각형이 해당 타일에 놓이는 경우 새로운 삼각형의 세 정점 중 가장 작은 값을 기존에 저장했던 z값과 비교하여 만약 가장 작은 값이 더 크다면 타일에 완벽하게 가려진다는 의미가 되기 때문에 해당 삼각형은 버려지게 된다.

 

만약 씬을 구성하는 삼각형들이 앞에서부터 뒤로 정렬되어 있다면, z-컬링을 통해 성능을 상당히 향상시킬 수 있지만 현실적으로 어려운 문제이기 때문에 대신 물체 단위로 정렬하는 방법을 택한다. 이정도만 해도 임의의 순서로 렌더링 했을 때보다 몇 배는 빨라진다.

 

추가로 오버드로우는 깊이 검사를 통과한 픽셀 수를 스크린의 전체 픽셀 수로 나눈 값이다. 오버드로우가 1에 근접할수록 효율적이라는 의미가 된다.

'이론 > 그래픽스' 카테고리의 다른 글

[Chapter 5] 조명 및 쉐이더  (0) 2023.05.17
[Chapter 3] 래스터라이저  (0) 2023.05.11
[Chapter 2] 정점 처리  (0) 2023.04.27
[Chapter 1] 폴리곤 메쉬  (0) 2022.09.16

클리핑, 원근 나눗셈, 뒷면 제거, 뷰포트 변환, 스캔 변환 등의 요소로 구성된다.

클리핑이나 원근 나눗셈은 알고리즘을 정확히 이해하지 않아도 큰 지장은 없지만 그 외 요소들은 작동 원리에 대한 이해가 있어야 적절한 제어를 할 수 있기 때문에 이해가 필요하다.

특히나 스캔 변환은 잘 이해해야만 프래그먼트 처리를 위한 프로그램을 작성할 수 있다.

 

◾ 클리핑

투영 행렬이 적용된 2x2x1 크기의 클립 공간 바깥에 있는 정점들을 잘라내는 과정이다.

 

 

◾ 원근 나눗셈

각 정점을 자신의 w값으로 나누어서 데카르트 좌표계로 변환시킨다. 보통 NDC(normalized device coordinates)라고 부른다.

w는 카메라 공간의 xy평면으로부터 해당 정점까지의 수직 거리이므로 카메라로부터 멀리 떨어진 물체는 w값이 크기 때문에 w로 나누면 크기가 작아진다.

 

 

◾ 뒷면 제거 (back-face culling)

삼각형의 노말 벡터와 삼각형 정점과 카메라 사이의 정규 벡터를 내적해서 0은 변만 보이는 삼각형, 음수는 앞면, 양수는 뒷면으로 판단할 수 있다.

하지만 컬링은 카메라 공간에서 수행하는 것이 비효율적이기 때문에 투영변환 이후 수행을 하게 된다.

직교투영 이후에는 사실상 z축이 소실되기 때문에 카메라 공간에서처럼 내적으로 판별하지 않고 정점들의 정렬 순서로 판단하게 된다.

 

만약 모든 삼각형의 정점이 시계 방향으로 정렬되어 있다면 반시계 방향은 뒷면으로 판단할 수 있는 것이다.

뒷면으로 판단되었다고 해서 무조건 컬링을 해야하는 것은 아니고 선택적으로 수행할 수 있도록 API에서 지원해준다.

 

차후 다룰 내용이지만 앞면으로 판단되었다고 해서 반드시 최종 렌더링 결과물에 나오는 것은 아니다. 다른 물체들에 의해 가려질 수 있기 때문에 깊이 버퍼라는 알고리즘에 의해 한 번 더 처리가 된다.

 

 

◾ 뷰포트 변환

스크린 상의 윈도우는 y축이 음의 방향인 스크린 공간을 가진다. z축은 화면 안쪽으로 들어가게 된다. (오른손 좌표계)

뷰포트의 종횡비는 절두체의 종횡비와 동일하게 설정된다.

NDC로 표현된 2x2x1 크기의 뷰 볼륨은 뷰포트 변환에 의해 뷰포트로 매핑이 되고, z값은 추후 깊이 버퍼 등에 사용된다.

 

클립 공간은 왼손 좌표계이고 스크린 공간은 오른손 좌표계이기 때문에 xz평면을 기준으로 반사시키고 축소확대, 이동 변환을 적용시키면 뷰포트로의 변환은 끝난다.

 

대부분의 게임에서는 전체화면을 사용하기 때문에 뷰포트가 윈도우 전체 영역을 사용하므로 MinX, MinY는 0이 되고 보통 MinZ, MaxZ는 0, 1로 설정되기 때문에 행렬이 단순화 될 수 있다.

 

뷰포트 변환은 최종적으로 모든 삼각형을 스크린 공간으로 옮기게 된다.

 

 

◾ 스캔 변환

래스터라이저의 마지막 단계이다. 삼각형의 내부를 채우는 프래그먼트들을 생성하는 단계이다.

좀 더 정확하게 말하자면 개별 삼각형이 차지하는 스크린 공간의 픽셀 위치를 결정하고 삼각형의 정점별 속성을 보간하여 이를 각 픽셀 위치에 할당하는 작업이다.

'이론 > 그래픽스' 카테고리의 다른 글

[Chapter 5] 조명 및 쉐이더  (0) 2023.05.17
[Chapter 4] 프래그먼트 처리와 출력 병합  (0) 2023.05.11
[Chapter 2] 정점 처리  (0) 2023.04.27
[Chapter 1] 폴리곤 메쉬  (0) 2022.09.16

정점 처리 (vertex processing)

로컬 공간의 정점들에 월드 변환, 뷰 변환, 클립 변환 및 조명 등을 연산하여 적용하는 단계.

 

월드 변환

선형 변환인 회전, 크기 변환과 아핀 변환인 이동 변환을 적용한다.

이동 변환은 한 차원 높은 행렬을 사용해야 하기 때문에 3차원 공간 기준으로는 4x4 행렬을 사용한다.

참고로 왼손 좌표계(DX)는 회전각이 양수라면 시계, 오른손 좌표계(OpenGL)는 반시계 방향으로 회전한다.

 

또한 DX는 행벡터를 사용하기 때문에 벡터*행렬 순서로 곱하는 것과 더불어 SRT 순서로 곱한다.

Vworld = Vlocal * S * R * T

V = 정점, S = 크기 변환 행렬, R = 회전 변환 행렬, T = 이동 변환 행렬

 

정점에 계산되는 월드 행렬(모델링 행렬)을 M이라고 할 때, 크기 변환 행렬의 x,y,z가 균등한 비율의 축소 및 확대라면 노말 벡터에도 적용이 가능하다.

하지만 비균등 축소 및 확대를 포함한다면 사용이 불가능하다. 비균등 축소 및 확대가 적용된 모델링 행렬을 노멀 벡터에 적용한다면 수직 관계가 깨지게 된다.

그래서 노말 벡터에는 M의 역행렬의 전치 행렬을 곱해서 수직 관계를 유지시켜준다.

 

* 노말 벡터 변환과 관련된 자세한 내용은 34p 참고

 

 

뷰 변환

 

◾ 카메라 공간

정점들이 월드 공간에 배치되면 원하는 부분만 관찰하기 위해 카메라의 파라미터를 설정해야 한다.

월드 공간의 모든 물체는 카메라 공간으로 변환되고, 클리핑을 통해 효율적인 렌더링 알고리즘 설계가 가능해진다.

 

뷰 변환을 위한 뷰 행렬을 구하는 대표적인 방법으로 EYE, AT, UP 세 가지 파라미터를 사용하여 구하는 방법이 있다.

EYE : 카메라의 좌표

AT : 카메라가 바라보는 기준점 (또는 물체)

UP : 월드 y축 기저벡터

 

카메라의 forward(z축) 벡터는 AT - EYE를 정규화 시키면 구할 수 있고, right(x축) 벡터는 forward와 UP을 외적하여 구할 수 있다. 마지막으로 forward와 right를 외적하면 up(y축)벡터까지 모두 구할 수 있다.

 

◾ 공간 이전과 뷰 행렬

월드 공간의 기저벡터는 각 축에 해당하는 e1(1,0,0), e2(0,1,0), e3(0,0,1)이다. 이는 {O, e1, e2, e3}으로 표현할 수 있다.

카메라 공간의 원점은 카메라의 위치에 해당되고 각 축 역시 카메라의 기저벡터에 해당되기 때문에 {EYE, right, up, forward}로 표현할 수 있다.

 

월드 공간의 좌표를 카메라 공간의 좌표로 변환하는 것을 뷰 변환 또는 카메라 변환이라고 한다.

 

간단하게 생각하면 된다. 카메라 공간에서는 원점을 카메라의 좌표로 봐야한다. 그러면 카메라를 원점으로 옮기는 행렬을 만들고 그 행렬을 정점들에 곱해주면 카메라 공간에 배치된것처럼 보이게 될 것이다.

 

계산 또한 매우 간단하다. 어떤 로컬 공간의 정점에 모델링 행렬 M을 곱해서 월드 공간에 배치했다면 M의 역행렬을 곱하면 다시 로컬 공간(0, 0, 0)으로 돌아올 것이다. 마찬가지로 카메라에 M의 역행렬을 곱하면 (0,0,0) 즉, 원점으로 돌아오게 된다. 카메라는 스케일링이 의미가 없기때문에 이동 행렬의 역행렬 * 회전 행렬의 역행렬(T-1 * R-1 = V)을 곱해주면 된다. (행벡터 기준)

이제 각 정점에 V를 곱해주면 정점들은 카메라 공간으로 이동하게 된다.

 

 

정점별 조명

차후 조명 연산에서 카메라와 정점간의 각도에 따라 반사된 빛이 카메라에 얼마나 들어오는지 결정하게 된다.

 

 

투영 변환

뷰 변환에 의해 모든 정점들이 카메라 공간 {EYE, right, up, forward}로 변환되었다.

이제 이 정점들을 제한된 카메라 시야에 렌더링 해볼 차례이다.

 

◾ 뷰 프러스텀 (절두체)

일반적으로 카메라의 시야는 제한되어 있어서 카메라 공간의 모든 물체를 화면에 담아낼 수 없다. 이 가시 영역을 뷰 볼륨이라고 부르는데, fovy, aspect, n, f 총 4가지 파라미터를 사용하여 결정한다.

 

fovy : field of view. 시야각

aspect : 뷰 볼륨의 종횡비 (ex: 4:3, 16:9)

n : near plane. 근평면

f : far plane. 원평면

 

위의 파라미터를 통해 생성된 절두체 외부에 놓인 물체는 뷰 프러스텀 컬링을 통해 렌더링 파이프라인에 들어가지 못하게 해서 보이지 않는 것으로 처리한다.

 

그런데 물체가 절두체의 경계에 존재하는 경우가 발생하는데, 이 때 해당 물체 전체가 렌더링되지 않는것이 아니라 절두체 외부에 있는 정점들만 잘라내고 경우에 따라 새로운 삼각형을 생성하는 클리핑 과정이 필요하다.

클리핑을 하기 전에 개별적인 폴리곤 메쉬를 감싸는 바운딩 볼륨을 미리 계산해두고 바운딩 볼륨이 절두체 외부에 있는지를 우선적으로 검사한다.

바운딩 볼륨은 추가적인 비용이 발생하는 것이지만 약간의 CPU 비용을 지불하는 대신 상당량의 GPU 비용을 절감하는 효과를 얻을 수 있다.

폴리곤 메쉬가 절두체의 평면과 겹치는 경우, 절두체 안쪽에 놓인 부분만 잘라내서 파이프라인의 다음 단계로 보낸다.

 

◾ 투영 행렬

절두체는 피라미드 모양이기 때문에 비스듬한 면이 존재해서 클리핑 연산이 복잡해지는 문제가 있다.

이를 위해 직육면체(2x2x1 크기)의 새로운 뷰 볼륨으로 변환하여 클립 공간으로 보내는 투영 변환이 필요해진다.

이름과는 달리 투영 변환은 카메라 공간의 3차원 물체를 2차원으로 투영하는 대신에 또 다른 3차원 물체로 변형시키는 변환이다.

 

절두체는 원점에 위치한 카메라로 수렴하는 투영선의 집합으로 이해할수도 있다.

이 투영선들을 직교 투영하여 모두 평행하게 만들어서 원근감을 실현 시킨다. 이것이 투영 변환이다.

투영 변환의 중요한 특징 중 하나는 아핀 변환에서는 마지막 요소인 w가 1이었지만 투영 행렬은 그렇지 않다.

 

투영 행렬의 유도는 글로 작성하기가 어려워서 책을 다시 보는 것이 좋을 것 같다. (p.51, 이득우의 게임수학 p.402)

'이론 > 그래픽스' 카테고리의 다른 글

[Chapter 5] 조명 및 쉐이더  (0) 2023.05.17
[Chapter 4] 프래그먼트 처리와 출력 병합  (0) 2023.05.11
[Chapter 3] 래스터라이저  (0) 2023.05.11
[Chapter 1] 폴리곤 메쉬  (0) 2022.09.16

선입선출 구조이다.

 

 

구현 사항

push : O(1)

pop : O(1)

front : O(1)

 

 

코드

더보기
template <typename _Ty>
class MyQueue {
public:
	explicit MyQueue() : lst_() {}
	
	~MyQueue() {}

public:
	inline void push(const _Ty& _val)
	{
		lst_.push_back(_val);
	}

	inline void push(_Ty&& _val)
	{
		lst_.push_back(std::move(_val));
	}

	inline void pop()
	{
		lst_.pop_front();
	}

	inline _Ty& front()
	{
		return lst_.front();
	}

	inline bool empty() const { return size() == 0; }

	inline const int& size() const { return lst_.size(); }

private:
	MyLinkedList<_Ty> lst_;
};

'이론 > 자료구조&알고리즘' 카테고리의 다른 글

Stack  (0) 2023.02.13
Linked List  (0) 2023.02.13
Divide & Conquer  (0) 2023.02.10
Recursion Basics  (0) 2023.02.09
Bit Manipulation  (0) 2023.02.09

+ Recent posts