본문 바로가기
대학생활/수업

게임프로그래밍고급 12주차 - Geometry Shader

by se.jeon 2023. 5. 23.
728x90
반응형

Geometry Shader

GPU를 이용해서 동적으로 기본 도형들에 대해서 모양을 바꾸거나 새롭게 생성하거나 삭제할 수 있는 Shader 중에 하나.

DirectX10과 OpenGL3.2부터 Geometry Shader 기능 추가.

 

기본 도형을 동적으로 변경할 때 기존에 사용 한 방법

- CPU상에서 선행해서 처리한 후 GPU에서 처리

 

Geometry Shader의 

- Rendering Pipeline에서 Vertex Shader 다음에 위치

- Rasterizer와 Fragment(Pixel) Shader 전에 위치

- Fragment Shader 입장에서는 Vertex Shader에서 전달된 정점 정보나 Geometry Shader에서 전달한 정점 정보나 동일하게 처리

Vertex Shader > Tessellator > Geometry Shader > Rasterizer > Fragment(Pixel) Shader

 

입력 및 처리

입력 정보는 개발자가 정의한 기본 도형 구성 단위로 정의한다.

   - 기본 도형이 삼각형인 경우 정점 3개의 정보 입력

   - 기본 도형이 선인 경우 정점 2개의 정보 입력

   - 기본 도형이 점인 경우 정점 1개의 정보 입력

 

Vertex Shader는 정점 단위로 계산하므로, 정점 하나에 정보만 전달한다.

Geometry Shader는 기본도형 구성 단위로 처리한다.

   Quad Mesh가 삼각형 2개로 구성되어 있으면 Gemoetry Shader는 삼각형 각각 1번씩 실행되어 2번 실행

 

Quad Mesh가 2개의 삼각형으로 구성되어졌을 경우

 

출력

Geometry Shader의 출력은 기본 도형을 구성하는 정점들.

Vertex Shader는 하나의 정점에 입력에 대한 하나의 정점 출력

Geometry Shader는 하나의 입력에 대해서 복수의 출력 가능.

   - 출력 기본 도형을 삼각형으로 정의

   - Geometry Shader에서 계산하여, 정점을 9개 출력하면 3개의 삼각형이 생성

MaxVertexCount를 사전 설정 필요. 1024가 최대값

 

정점을 추가하고 기존 모양을 유지하려면, Vertex Shader에서 넘어온 정점 정보도 Geometry Shader에서 출력 필요.

Geometry Shader가 Vertex Shader의 출력 정보에 대해서 정보를 추가하는 것이 아님.

Geometry Shader을 통한 출력 결과값만 Rasterizer에서 처리되고 최종적으로 Fragment Shader에 입력 처리.

 

Geometry Shader에서 출력 내용이 입력되는 정보보다 크거나 적거나 0이면 무엇을 말하는 것일까?
정답 체크 필요.

 

구성

최대 출력 정점 수 : 출력 최대 정점 개수 1024개

정점에 대한 요소의 정의 : 정점에서 가질 수 있는 정보

- 위치값 : x, y, z, w

- 컬러값 : r, g, b, a

- 최대값 : 1024

- 요소의 최대 출력 수 : 1024/8 = 128로 제한

최대 출력 정점수와 최대 출력 수 모두 만족 필요

출력은 128개가 일반적인 제한. 따라서 MaxVertexCount 128로 설정

 

Unity Geometry Shader

- 다른 Shader와 유사하게 프로젝트의 Asset 파일로 생성 필요

- Create > Shader > Unlit Shader를 통해서 생성

- 기존 vertex & fragment Shader를 구성했을 때와 유사

- Geometry Shader를 구성할 pragma geometry 이용 필수

- HLSL을 이용해서 구현

Geometry Shaer 구문

Geometry Shader Tutorial

Quad를 Scene 화면에 배치하고, Geometry Shader를 이용해서 삼각 뿔을 만들어 화면에 렌더링

 

Shader Property 선언

- 삼각뿔의 높이, Color 값을 입력 받기 위해서 설정 값을 지정 필요.

- 삼각뿔의 색깔을 입히기 위한 처리

Properties
{
	_Height("Height", float) = 5.0
	_TopColor("Top Color", Color) = (0.0, 0.0, 1.0, 1.0)
	_BottomColor("Bottom Color", Color) = (1.0, 0.0, 0.0, 1.0)
}

 

SubShader 선언

- RenderType은 Opaque로 설정 (불투명 Shader임을 지칭)

- FOG, LOD는 삭제

SubShader
{
	Tags { "RenderType"="Opaque" }
	// LOD 100

 

Geometry Shader 선언

- Geometry Shader를 선언하기 위해서는 #pragma geometry를 통해서 특정 함수를 geometry shader로 사용할지 선언 필수.

Pass
{
	CGPROGRAM
	#pragma vertex vert
	#pragma fragment frag
	#pragma geometry geom // geometry shader
	#include "UnityCG.cginc“
	uniform float _Height;
	uniform float4 _TopColor, _BottomColor;

 

Geometry Shader 사용할 구조체 선언

- vertex, geometry, fragment shader에서 사용할 구조체 선언

struct appdata
{
	float4 vertex : POSITION;
	float2 uv : TEXCOORD0;
};
struct v2g
{
	float4 vertex: SV_POSITION;
};
struct g2f
{
	float4 vertex : SV_POSITION;
	float4 color : COLOR;
};

 

Vertex Shader에서 Geometry Shader로 정보 전달

- vertex 정보를 geometry shader에게 연결해 줌.

v2g vert (appdata v)
{
	// vertex 정보만 리턴해준다.
	v2g o;
	o.vertex = v.vertex;
    
	return o;
}

vert 함수는 Geometry Shader에게 Vertex 정보를 넘겨주기 위해서 v2g 구조체를 만들어서 값을 반환한다.

 

Geometry Shader 함수 선언

- pragma를 통해서 선언한 geometry shader에 사용할 함수 선언

[maxvertexcount(12)]
void geom(triangle v2g input[3], inout TriangleStream<g2f> outstream)
{
	….
}

 

triangle v2g input[3]

- 삼각형을 입력으로 받을 것이기에 triangle로 데이터 타입 선언

- 삼각형은 3개의 정점 정보로 오기 때문에 배열 처리

 

inout TriangleStream outstream

- 출력하는기본도형이 삼각형이기에 TriangleStream으로 선언

- PointStream : 출력 기본 도형 정점

- LineStream : 출력 기본 도형 선

- TriangleStream : 출력 기본 도형 삼각형

 

[maxvertexcount(12)]

- 최대 출력 정점 수 12개 설정

- 삼각형 뿔을 생성할 것이기에, 삼각형 4개 필요, 3*4 = 12개 정점

 

Geometry Shader로 삼각뿔 생성

Geometry Shader에서의 삼각뿔 생성 사전 준비

- 입력으로 들어오는 3개의 정점과 삼각뿔의 중심이 되는 점을 계산

 

float4 p0 = input[0].vertex;
float4 p1 = input[1].vertex;
float4 p2 = input[2].vertex;

// 무게 중심 좌표 c를 구하기
float4 c = float4(0.0f, 0.0f, -_Height, 1.0f) + (p0 + p1 + p2) * 0.33333f;

g2f out0;
out0.vertex = UnityObjectToClipPos(p0);
out0.color = _BottomColor;

g2f out1;
out1.vertex = UnityObjectToClipPos(p1);
out1.color = _BottomColor;

g2f out2;
out2.vertex = UnityObjectToClipPos(p2);
out2.color = _BottomColor;

g2f o;
o.vertex = UnityObjectToClipPos(c);
o.color = _TopColor;

 

Geometry Shader에서의 삼각뿔 생성

- 삼각뿔의 무게 중심점과 기존 정점 3개를 이용

- 새로운 삼각형 4개 생성을 통해서 삼각뿔 생성

// bottom
outstream.Append(out0);
outstream.Append(out1);
outstream.Append(out2);
outstream.RestartStrip();

// side 1
outstream.Append(out0);
outstream.Append(out1);
outstream.Append(o);
outstream.RestartStrip();

// side 2
outstream.Append(out1);
outstream.Append(out2);
outstream.Append(o);
outstream.RestartStrip();

// side 3
outstream.Append(out2);
outstream.Append(out0);
outstream.Append(o);
outstream.RestartStrip();

 

Geometry Shader에서의 삼각뿔 생성

- Vertex Shader와 같이 정점 좌표를 클립 공간(Clip Space)으로 이동

- Append 메서드 : 출력용 변수를 출력중인 스트림에 추가

- RestartStrip 메서드 : 현재의 기본도형 구성을 종료. 새로운 기본도형 구성 시작.

- TriangleStream은 triangle strip 방식으로 삼각형을 생성하므로 정점 추가할 때 마다 삼각형을 추가해서 구성.

 

삼각형을 구성하는 방식

Triangle Strip 방식

연속된 삼각형을 구성하는 방식으로써 꼭짓점 v1, v2, v3으로 첫번째 삼각형 구성, 그리고 다음 삼각형은 v2, v3, v4, 또 다음 삼각형은 v3, v4, v5으로 구성, 이전의 두 점과 현재의 점을 연결해서 삼각형을 구성.

- Triangle Strip으로 아래와 같이 삼각형을 구성하면 왼손 좌표계에서 시계방향으로 삼각형이 구성되어야 앞면이 된다는 문제점이 있다. 뒷면은 기본적으로 제거 대상이다.

 

LineStream 방식

Line Strip 방식으로 Line을 생성

 

PointStream 방식

Point List 방식으로 Point을 생성

 

Fragment Shader에서의 최종 색깔 표현

Geometry Shader를 통해서 입력 받은 Color값을 이용하여 화면에 렌더링한다.

fixed4 frag (g2f i) : SV_Target
{
    return i.color;
}
ENDCG

 

Geometry Shader Tutorial

- Quad를 Scene 화면에 배치하고 정육면체를 만들어서 화면에 렌더링 하는 Geometry Shader를 제작 해 보는 실습 진행.

- 실시간 풀을 Geometry Shader를 이용해서 만들어 보는 실습 진행.

 

Shader Property 선언 : 풀과 관련된 속성값 정의

Properties
{
    // 풀의 높이, 폭
    _Height("Height", float) = 25
    _Width("Width", float) = 0.5
    
    // 풀의 밑, 중간, 윗 부분 높이
    _BottomHeight("Bottom Height", float) = 0.3
    _MiddleHeight("Middle Height", float) = 0.4
    _TopHeight("Top Height", float) = 0.5
    
    // 풀의 밑, 중간, 윗 부분 폭
    _BottomWidth("Bottom Width", float) = 0.5
    _MiddleWidth("Middle Width", float) = 0.4
    _TopWidth("Top Width", float) = 0.2
    
    // 풀의 밑,중간,윗 부분 꺽인 정도
    _BottomBend("Bottom Bend", float) = 1.0
    _MiddleBend("Middle Bend", float) = 2.0
    _TopBend("Top Bend", float) = 3.0
    
    // 바람의 세기
    _WindPower("Wind Power", float) = 0.75
    
    // 풀 윗,아랫 부분 색
    _TopColor("Top Color", Color) = (0.0, 1.0, 0.0, 1.0)
    _BottomColor("Bottom Color", Color) = (0.0, 0.2, 0.3, 1.0)
    
    // 풀 높이의 랜덤성을 주기 위한 Noise 텍스처
    _HeightMap("Height Map", 2D) = "white"
    
    // 풀의 방향에 랜덤성을 주기 위한 Noise 텍스처
    _RotationMap("Rotation Map", 2D) = "black"
    
    // 바람 세기에 랜덤성을 주기 위한 Noise 텍스처
    _WindMap("Wind Map", 2D) = "black"
}

 

SubShader 선언

- RenderType은 Opaque로 설정

- FOG, LOD는 삭제

SubShader
{
    Tags { "RenderType" = "Opaque" }
    
    // LOD 100
    Cull Off // Culling 하지 않도록 설정

 

Geometry Shader 선언 : 사용 함수와 관련 변수들 선언

Pass
{
    CGPROGRAM
    #pragma vertex vert
    #pragma fragment frag
    #pragma geometry geom
    
    #include "UnityCG.cginc“
    float _Height, _Width;
    float _BottomHeight, _MiddleHeight, _TopHeight;
    float _BottomWidth, _MiddleWidth, _TopWidth;
    float _BottomBend, _MiddleBend, _TopBend;
    float _WindPower;
    float4 _TopColor, _BottomColor;
    sampler2D _HeightMap, _RotationMap, _WindMap;

 

Geometry Shader 사용할 구조체 선언

vertex, geometry, fragment shader에서 사용할 구조체 선언

728x90
반응형