개발 · 컴퓨터공학 / / 2022. 3. 17. 11:35

OpenGL 공부일지 - OpenGL Super Bible 쉐이더와 프로그램 - 1

728x90
반응형

Shaders and Programs

GLSL이라는 OpenGL 쉐이딩 언어에 대해 알아보자.

Language Overview

C언어와 문법 및 모델적으로 비슷하나, 그래픽스와 병렬 실행에 더 적합한 언어이다.  GLSL은 행렬과 벡터 타입이 기본타입이기 때문에 언어에 내장되어있다. 그래픽스 프로세서는 동시에 수천 개 이상의 쉐이더 본사본을 실행하기 때문에 GLSL에서는 이를 위한 제약사항들이 있다. 재귀호출이 허용되지 않고, 부동소수점 수에 대한 정밀도 요구사항 등이 있다.

Data Types

Scalar Types

C에서의 표준인 short, char, string등을 지원하지 않고, 다음 표와 같은 타입들이 있다.

int의 경우 C와 동일하다. -21억(생략)부터 +21억(생략)까지의 범위를 갖는다. 범위를 넘으면 오버플로우가 난다.

부동소수점 수는 IEEE-754표준으로 정의되어 있다. 

GLSL의 연산에 대해서 예외를 지원하지 않으므로 0으로 나누기 같은 작업을 하더라도 쉐이더 결과가 잘못되고 에러를 띄우지는 않는다.

Vectors and Matrices

GLSL에는 스칼라타입으로 지원하는 모든 타입에 대한 벡터, 단정밀도 및 배정밀도 부동소수점형의 행렬이 지원된다.

위 표에 GLSL에서 지원하는 모든 벡터와 행렬타입이 들어있다.

vec3 foo = vec3(1.0);
vec3 bar = vec3(foo);
vec4 baz = vec4(1.0, 2.0, 3.0, 4.0);
vec4 bat = vec4(1.0, foo);

위 코드와 같이 벡터를 정의 할 수 있고,

vec4 foo;

float x = foo[0];
float y = foo[1];
float z = foo[2];
float w = foo[3];

위 코드와 같은 방식으로 벡터에 접근할 수 있다.

typedef union vec4_t
{
    struct
    {
        float x;
        float y;
        float z;
        float w;
    };
    struct
    {
        float s;
        float t;
        float p;
        float q;
    };
    struct
    {
        float r;
        float g;
        float b;
        float a;
    };
} vec4;

이렇게 구조체로 작성한 벡터에 접근자 '.'를 이용해서 접근하는 것도 가능하다.

 

GLSL에서 벡터는 swizzling이라는 것을 지원한다. 예를들어 vec4 foo의 세 요소를 foo.xyz, foo.rgb, foo.stp 등으로 표현해서 얻을 수 있고, foo.zyx처럼 요소의 순서를 바꾼 벡터를 만들 수도 있다. 하지만 위 구조체에서 같은 필드에 속한 요소들을 사용해야한다. 가령 foo.xyba등으로는 사용하지 못한다.

 

행렬이 기본적으로 내장되어있기 때문에 operator도 행렬과 벡터에 맞추어 요소 단위의 계산으로 정의되어있다. 

Arrays and Structures

타입의 조합에 배열도 구조체도 사용가능하다. GLSL에 typedef는 없지만, 구조체 정의를 통한 새로운 타입 선언이 가능하다. 

float foo[5];
ivec2 bar[13];
dmat3 baz[29];

GLSL의 배열 선언 방식은 위와 같은 방법과, 

float[5] foo;
ivec2[13] bar;
dmat3[29] baz;

위와 같은 두 가지 방법으로 선언할 수 있다.

위 두 코드의 차이를 모르겠다면 다음을 보자.

vec4[4] functionThatReturnsArray()
{
	vec4[4] foo = ...
	return foo;
}

이렇게 vec4배열의 크기를 지정해서 함수의 반환형으로 사용하는 것이 가능하다.

float[6] var = float[6](1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

이렇게 배열 생성자를 통해 변수를 초기화하는 것도 가능하다. C에서의 초기화 방법도 물론 가능하다.

 

GLSL의 배열은 .length() 함수를 포함하여 요소개수를 받아올 수 있다.

 

Built-In Functions

GLSL에는 텍스처 및 메모리를 위한 다양한 내장 함수가 있다.

Terminology

GLSL에서 사용하는 용어들은 알아두면 좋다.

  • genType : 단일 정밀도 부동소수점 타입
  • genUType : 부호 없는 정수 타입
  • genIType : 부호 있는 정수 타입
  • genDType : 배정밀도 부동소수점 타입
  • mat : 단정밀도 부동소수점 행렬 (float 32bit)
  • dmat : 배정밀도 부동소수점 행렬 (double 64bit)

Built–In Matrix and Vector Functions

GLSL에서 기본적으로 지원하는 많은 함수들이있다. 간단히 무엇이 있는지만 알아보자.

matrixCompMult() : 두 행렬간 요소 단위 곱셈

transpose() : 전치행렬

inverse() : 역행렬

determinant() : 정방 행렬 행렬식 계산

outerProduct() : 두 벡터 외적

 

비교 함수

lessThen(), lessThanEqual(), greaterThan(), greaterThanEqual(), equal(), notEqual()

부울 벡터 검사

any(), all(), not()

 

length() : 벡터 길이

normalize() : 벡터 정규화

dot(), corss() : 내적과 외적

reflect(), refract() : 한 벡터와 평면의 노말 벡터를 입력받아 각각 반사된 벡터, 굴절된 벡터를 반환.

faceforward() : 평면이 특정 뷰 방향에 대해 정면인지 후면인지 결정하는 함수

Built–In Math Functions

수학적인 지식이 있으면 함수 이름만 보더라도 기능을 할 수 있기에 이름만 간단히 정리한다.

abs(), sign(), ceil(), floor(), trunc(), round(), roundEven(), fract(), mod(), modf(), min(), max()

roundEven 은 생소할 수 있는데, 가장 가까운 정수로 반올림한다.

clamp() : 입력값을 지정한 범위로 고정한다. 

mix() : 두 입력에 대한 선형 보간

step() : 두 입력에 기반하여 계단함수 생성

smoothstep() : 두 입력 사이 부드러운 중간값 반환 (허밋 보간)

fma() : 단일 곱셈 누산 연산

 

GLSL에는 큰 정수에 대한 연산을 위한 함수들도 있다.

uaddCarry() : 자리 올림(carry)을 사용한 덧셈 

usubBorrow() : 빌림(borrow)을 사용한 뺄셈 

imulExtended() : 32비트 부호 있는 정수값의 곱으로 64비트 결과

umulExtended() : 32비트 부호 없는 정수값의 곱으로 64비트 결과

 

GLSL의 삼각함수

sin(), cos(), tan(), asin(), acos(), atan(), sinh(), cosh(), tanh(), asinh(), acosh(), atanh()

지수함수

pow(), exp(), log(), exp2(), log2(), sqrt(), inverseqprt()

GLSL함수는 대부분 radian을 사용한다. 

radians() : 도를 라디안으로 변환

degrees() : 라디안을 도로 변환

Built-In Data Manipulation Functions

GLSL에는 데이터 내부를 들여다보기 위한 내장 함수들이 있다.

frexp() : 부동소수점 수를 지수부와 가수부를 분리해서 반환

ldxp() : 지수와 기수를 통해 새로운 부동소수점 수 생성

 

부동소수점 수를 깊이 제어하기 위한 함수들이 있다.

intBitToFloat(), uintBitsToFloat() : 부호 있는 또는 부호 없는 정수를 취해서 비트를 재해석하여 32비트 부동소수점으로 만듬

floatBitsToInt(), floatBitsToUint() : 부동소수점 수를 취해서 부호 있는 또는 부호 없는 정수로 만든다.

isnan(), isinf() : 부동소수점 수의 NaN, 무한 값 확인

 

부동소수점 벡터에 대한 함수

packUnorm4x8(), packSnorm4x8() : vec4를 네 개의 부호 없는 또는 있는 8비트 정수값으로 묶고, 네 개의 8비트 값을 하나의 uint로 묶는다. 

unpackUnorm4x8(), unpackSnorm4x8() : 위와 반대의 일을 수행

packUnorm2x16(), packSnorm2x16(), unpackUnormx16(), unpackSnorm16() : vec2변수를 취하여 16비트 값을 하나의 uint로 묶거나 푸는 함수

여기서 norm은 정규화이다. 

packDouble2x32(), unpackDouble2x32() : 배정밀도 double에 대해 위 함수와 동일한 역할 수행

packHalf2x16() : 앞서 설명한 동작을 16비트 부동소수점 값에 대해 수행

 

비트 필드 연산

bitfieldExtract() : 부호 없는 정수의 특정 비트만 얻기

bitfieldInsert() : 다시 정수 안에 넣기

bitfieldReverse(), bitCount(), findLSB(), findMSB() 등

728x90
반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유