본문으로 건너뛰기

GLSL ES(OpenGL ES 쉐이더 언어)_WebGL 노트 9

무료2016-01-02#JS#WebGL#webgl着色器#GLSL ES#着色器语言#webgl着色器语法#webgl存储限定字

GLSL ES 언어를 전면적으로 이해하며, 문법 규칙, 데이터 타입, 플로우 제어, 함수 등을 포함

서두

[이전 노트](/articles/텍스처 매핑(貼圖)-webgl 노트 8/) 후, WebGL 의 가장 기초적인 부분을 마쳤습니다. 이번 노트에서는 GLSL ES 구문을 전면적으로 소개하며, 비교적 독립적입니다. 그 후 행렬 행렬 행렬 (변환, 시점, 조명, 복잡한 모델 제어 등, 모두 행렬을 다루고 있습니다)

일.개요

GLSL ES 는 GLSL(OpenGL 쉐이더 언어) 을 기반으로, 일부 기능을 삭제·간소화하여 형성된 것으로, 타겟 플랫폼은 민생용 전자제품과 임베디드 장비입니다. 예를 들어 스마트폰, 게임기 등. ES 버전은 주로 하드웨어 전력 소비를 저감하고, 성능 오버헤드를 감소했습니다

P.S. 실제, WebGL 은 GLSL ES 의 모든 특성을 지원하는 것이 아니며, GLSL ES 1.00 버전의 서브셋을 지원합니다

이.기본 구문 규칙

  1. 대소문자 구별

  2. 문장 끝에는반드시 세미콜론이 필요

  3. main 함수에서 실행 시작

  4. 함수 선언에서는반환값의 타입을 생략할 수 없음(반환값이 없으면 void, C 언어에서는 생략 가능하지만, 여기서는 불가)

  5. 주석 구문은 C 언어와 동일 (단행//, 다행/**/)

삼.변수와 기본 데이터 타입

###1.기본 데이터 타입

2 종류의 기본 데이터 타입만 지원:

  • 수치형: 정수, 부동소수점수

  • 불리언형: true 와 false 2 개의 불리언 상수

주의: 문자열은 지원되지 않습니다

###2.변수

  1. 변수 선언

C 언어와 같이, 타입 + 변수명. 변수 명명 규칙도 동일. 기본형은 int, float, bool 만

  1. 타입 변환

암묵적 타입 변환은없으며, 3f 와 같은 타입 서픽스도지원되지 않습니다 가, 타입 변환 함수를 제공:int(), float(), bool(). 이들은 나머지 2 개의 기본 데이터 타입만 받아들입니다

  1. 연산자

비트 연산은 지원되지 않습니다. 기타는 C 언어와 동일. 3 항 선택도 지원. 논리 AND(&&) 와 논리 OR(||) 도 단락 특성이 있습니다

  1. 스코프

C 언어와 동일. 함수 내부에서 선언하는 것은 로컬 변수, 외부에서 선언하는 것은 글로벌 변수

사.복잡한 데이터 타입

###1.벡터 (vec)

2, 3, 4 차원 벡터를 지원. 성분의 데이터 타입에 따라 3 종류로 분류:

  • vec2, vec3, vec4: 성분은 부동소수점수

  • ivec2, ivec3, ivec4: 성분은 정수

  • bvec2, bvec3, bvec4: 성분은 불리언값

생성자명 은 타입명과 동일. 예를 들어 vec4(1.0) 은 4 차원 벡터 [1.0, 1.0, 1.0, 1.0] 를 반환합니다. 이렇게 1 개의 파라미터만 전달하는 경우, 모든 성분에 그 값을 대입합니다. 필요한 파라미터 수보다 적지만 1 개보다 많은 파라미터를 전달하면, 오류 가 발생합니다. 예를 들어, vec4(1.0)vec4(1.0, 1.0, 1.0, 1.0) 는 문제없지만, vec4(1.0, 1.0)vec4(1.0, 1.0, 1.0) 는 오류가 발생합니다

게다가, 벡터를 전달하여 새로운 벡터를 구축하거나, 기존 벡터를 조합하여 새로운 벡터를 생성할 수 있습니다. 예를 들어:

vec3 v3 = vec3(0.0, 0.5, 1.0);   // [0.0, 0.5, 1.0]
vec2 v2 = vec2(v3);              // [0.0, 0.5], v3 의 첫 2 개 성분을截取
vec4 v4 = vec4(v2, vec4(1.5));   // [0.0, 0.5, 1.5, 1.5], v2 와 새로운 벡터 [1.5, 1.5, 1.5, 1.5] 를 조합

요컨대, 파라미터는 기본값 또는 다른 벡터에서 올 수 있지만, 파라미터 수가 부족하고 1 개가 아니면오류 가 발생합니다

벡터의 성분에 액세스하는 2 가지 방법이 있습니다:

v4 = vec4(1, 2, 3, 4);
// .성분명
v4.x, v4.y, v4.z, v4.w // 동차좌표
v4.r, v4.g, v4.b, v4.a // 색값
v4.s, v4.t, v4.p, v4.q // 텍스처 좌표
// [] 연산자
v4[0], v4[1], v4[2], v4[3]

닷트 성분명 방식은 의미를 추가하기 위한 것만으로, 대괄호 연산자와 동등합니다. 별명으로 이해할 수 있습니다. 예를 들어 v4[0] 의 별명은 v4.x, v4.r, v4.s 입니다. 더욱 흥미로운 것은, 조합하여 사용할 수 있다는 것입니다. 예를 들어 v4.xz 는 2 차원 벡터를 반환하지만, 이 경우 성분명을 혼용할 수 없습니다 (v4.sz 는 부정)

주의: 대괄호 중의 값은상수 인덱스 값 이어야 합니다. 정수 리터럴, const 수식된 변수, 루프 인덱스 (플로우 제어 부분에서 후술), 또는 이들 3 개로 구성되는 식

###2.행렬 (mat)

2, 3, 4 차원정방행렬 만을 지원. 부동소수점수형 성분만 지원:mat2, mat3, mat4

특별히 주의: 행렬 요소는열우선순서 입니다. 예를 들어:

mat4 m4 = mat4(
    1, 2, 3, 4,
    5, 6, 7, 8,
    9, 10, 11, 12,
    13, 14, 15, 16
);
// 생성되는 행렬은:
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16

상상과 크게 다를 수 있지만, 확실히 그렇습니다. 마찬가지로, 행렬의 생성자도 다른 벡터 또는 행렬을 받아들일 수 있습니다. 파라미터가 어디서 오든, 최종적으로 이들 수는열우선순서 로 행렬을 구축합니다. 예를 들어:

vec2 v2_1 = vec2(1, 2);
vec2 v2_2 = vec2(3, 4);
mat2 m2 = mat2(v2_1, v2_2);
// 생성되는 행렬은:
1 3
2 4

마찬가지로, 파라미터가 부족하고 파라미터 수가 1 개가 아니면오류 가 발생합니다

행렬 요소에 액세스하려면 일반적으로 대괄호 연산자를 사용합니다. 예를 들어:

m4[0]       // 제 1 열 요소, 4 차원 벡터
m4[0][1]    // 제 1 열 제 2 행의 요소, 기본값
m4[0].y     // 동상

주의: 마찬가지로, 대괄호 중의 값도상수 인덱스 값 이어야 합니다

###3.구조체 (struct)

C 언어의 구조체와 유사. 예를 들어:

// 커스텀 구조체 타입을 선언
struct light {
    vec4 color;
    vec3 pos;
};
// 구조체 타입 변수를 선언
light l1, l2;   // C 언어의 struct light l1, l2; 와 동등
// C 언어처럼 구조체를 선언하는 동시에 구조체 타입의 변수를 선언할 수도 있음
struct light {
    vec4 color;
    vec3 pos;
} l3;

구조체를 선언하면동명 생성자 가 자동 생성됩니다. 파라미터 순서는 구조체 중의 멤버 순서와 일치해야 합니다. 예를 들어:

light l4 = light(vec4(1.0), vec3(0.0));

닷트 연산자로 구조체 변수의 멤버에 직접 액세스할 수 있습니다. 구조체 자체는 대입 (=) 과 2 개의 비교 연산자 (==, !=) 만을 지원. 2 개의 구조체 멤버와 순서가 같으면, 같다고 간주됩니다

###4.배열 (xArray)

1 차원 배열 만을 지원. pop, push 등의 조작은 지원되지 않습니다. 배열 선언 방식은 C 언어와 동일. 예를 들어:

float a[10];
vec4 arr[3];

마찬가지로, 대괄호 중의 값은상수 인덱스 값 만. moreover 배열은선언과 동시에 초기화할 수 없습니다. 각 요소에 명시적으로 대입해야 합니다

###5.샘플러 (sampler)

샘플러 변수를 통해 텍스처에 액세스할 수 있습니다. 샘플러 변수는 2 종류만:sampler2D 와 samplerCube. moreover 샘플러 변수는오직uniform 변수입니다. 예를 들어:

uniform sampler2D u_Sampler;

샘플러 변수에 대입할 수 있는 유일한 값은텍스처 유닛 번호 입니다. 예를 들어 gl.uniformi(u_Sampler, 0) 은 텍스처 유닛 번호 0 을 쉐이더에 전달합니다. 따라서 샘플러 변수는수가 제한되어 있습니다. 프래그먼트 쉐이더에서는 최대 8 개, 정점 쉐이더에는 샘플러 변수가 없습니다

게다가, =, ==, != 외, 샘플러 변수는연산자로서 연산에 참여할 수 없습니다

오.벡터 연산과 행렬 연산

벡터와 행렬은 비교 연산자의 ==!= 만을 지원. 연산 대입 (+=, -=, *=, /=) 조작은 벡터와 행렬에 대해 실제로는 각 성분에 대해 연산 대입을 수행합니다

###1.벡터와 부동소수점수 연산

v2 + f; // v2[0] + f
        // v2[1] + f

###2.벡터 연산

v2_1 + v2_2;    // v2_1[0] + v2_2[0]
                // v2_1[1] + v2_2[1]

###3.행렬과 부동소수점수 연산

m2 + f; // m2[0] + f
        // m2[1] + f
        // m2[2] + f
        // m2[3] + f

###4.행렬 우승 벡터

m3 * v3;    // m3[0][0] * v3[0] + m3[1][0] * v3[1] + m3[2][0] * v3[2]
            // m3[0][1] * v3[0] + m3[1][1] * v3[1] + m3[2][1] * v3[2]
            // m3[0][2] * v3[0] + m3[1][2] * v3[1] + m3[2][2] * v3[2]

###5.행렬 좌승 벡터

v3 * m3;    // v3[0] * m3[0][0] + v3[1] * m3[0][1] + v3[2] * m3[0][2]
            // v3[0] * m3[1][0] + v3[1] * m3[1][1] + v3[2] * m3[1][2]
            // v3[0] * m3[2][0] + v3[1] * m3[2][1] + v3[2] * m3[2][2]

###6.행렬 승 행렬

m3a * m3b;  // m3a[0][0] * m3b[0][0] + m3a[1][0] * m3b[0][1] + m3a[2][0] * m3b[0][2]
            // m3a[0][0] * m3b[1][0] + m3a[1][0] * m3b[1][1] + m3a[2][0] * m3b[1][2]
            // m3a[0][0] * m3b[2][0] + m3a[1][0] * m3b[2][1] + m3a[2][0] * m3b[2][2]
            // m3a[0][1] * m3b[0][0] + m3a[1][1] * m3b[0][1] + m3a[2][1] * m3b[0][2]
            // m3a[0][1] * m3b[1][0] + m3a[1][1] * m3b[1][1] + m3a[2][1] * m3b[1][2]
            // m3a[0][1] * m3b[2][0] + m3a[1][1] * m3b[2][1] + m3a[2][1] * m3b[2][2]
            // m3a[0][2] * m3b[0][0] + m3a[1][2] * m3b[0][1] + m3a[2][2] * m3b[0][2]
            // m3a[0][2] * m3b[1][0] + m3a[1][2] * m3b[1][1] + m3a[2][2] * m3b[1][2]
            // m3a[0][2] * m3b[2][0] + m3a[1][2] * m3b[2][1] + m3a[2][2] * m3b[2][2]

육.플로우 제어

###1.분기

if-else 구조 용법은 C 언어와 js 와 동일하지만, switch 문은 없습니다

###2.루프

for 루프만 을 지원. moreover오직 초기화식 (for(;;) 중 첫 번째 세미콜론 앞의 위치) 에서 루프 변수를 정의할 수 있습니다. 예를 들어:

for (int i = 0; i < 10; i++) {
    //...
}

1 개의 루프 변수만 허용. moreover 루프 변수는오직int 또는 float. moreover 조건식 (for(;;) 중 2 개의 세미콜론 사이의 위치) 은반드시 루프 변수와 정수 상수의 비교. moreover 루프 본체 내부에서, 루프 변수는대입할 수 없습니다

제한이 많은 것은, 컴파일러가 for 루프를 인라인 전개할 수 있도록 하기 위함입니다

continue, break 용법은 js 와 동일. 게다가, discard 가 있으며, 프래그먼트 쉐이더에서만 사용 가능. 현재 프래그먼트를 포기하고, 직접 다음 프래그먼트를 처리하는 것을 나타냅니다

칠.함수

C 언어와 기본적으로 동일하지만, 배열을 반환할 수 없습니다. 커스텀 구조체를 반환하는 경우, 구조체 멤버 중에 배열을 포함할 수 없습니다. 예를 들어:

float luma(vec4 color) {
    return 0.2126 * color.r + 0.7162 * color.g + 0.0722 * color.b;
}

마찬가지로, ���저 선언하고, 후에 호출해야 합니다.否则호출 전에 함수 시그니처를 선언해야 합니다. 예를 들어:

float luma(vec4);   // 함수 시그니처를 선언
void main() {
    luma(color);
}
float luma...

게다가, 재귀는 허용되지 않습니다. 이 제한도 컴파일러가 함수를 인라인 전개할 수 있도록 하기 위함입니다

GLSL ES 에는 몇 개의 파라미터 한정자가 있습니다:

in          값 전달, 생략 가능, 기본은 값 전달
const in    값 전달, 함수 내부에서 파라미터를 수정할 수 없음
out         주소 전달
inout       주소 전달, 전달되는 파라미터는 이미 초기화되어 있어야 함

팔.저장 한정자

attribute, uniform, varying. 차이는 다음과 같습니다:

  • attribute

오직 정점 쉐이더 중에 나타날 수 있음. 오직 글로벌 변수. 타입은오직float 또는 성분이 float 인 벡터와 행렬. WebGL 환경은 적어도 8 개의 attribute 변수를 지원. 정점마다의 정보를 나타내는 데 사용

  • uniform

오직 글로벌 변수. 정점 쉐이더와 프래그먼트 쉐이더에서 사용 가능. 배열과 구조체 외의 임의의 타입. WebGL 환경은 적어도 프래그먼트 쉐이더 중에 16 개의 uniform 변수, 정점 쉐이더 중은 128 개를 지원. 각 정점, 각 프래그먼트가 공용하는 데이터를 나타내는 데 사용

特殊的: 정점 쉐이더와 프래그먼트 쉐이더 중에 동명의 uniform 변수를 선언한 경우, 2 개의 쉐이더에서 공유됩니다

  • varying

오직 글로벌 변수. 타입은오직float 또는 성분이 float 인 벡터와 행렬. WebGL 환경은 적어도 8 개의 varying 변수를 지원. 정점 쉐이더에서 프래그먼트 쉐이더에 데이터를 전달하는 데 사용. 하지만직접 전달하는 것이 아니라, 보간 프로세스가 있습니다

게다가, const 한정자가 있지만,あまり사용되지 않습니다

구.정밀도 한정자

정밀도 한정자를 도입하는 것은 쉐이더 프로그램의 실행 효율을 향상하고, 메모리 소비를 감소하기 위함입니다. 일반적으로 중정밀도를 채택:

#ifdef GL_ES
precision mediump float;    // highp 와 lowp 도 가능
#endif

이 문은 후에 만나는 모든 정밀도를 선언하지 않은 부동소수점수에 중정밀도를 사용하는 것을 나타냅니다. float 형만 기본 정밀도가 설정되지 않았으므로, 쉐이더 소스 프로그램 중에서 반드시 float 의 기본 정밀도를 설정한 후 float 형을 사용해야 합니다

프래그먼트 쉐이더가 고정밀도를 지원하는지 여부는 디바이스의 지원이 필요합니다. 매크로를 체크하여 검출 가능:GL_FRAGMENT_PRECISION_HIGH

십.프리프로세스 지시

C 언어와 유사.常用的인 3 종류의 프리프로세스 지시는 다음과 같습니다:

// 1
#if 조건식
조건식이 참이면, 이 부분을 실행
#endif
// 2
#ifdef 매크로
매크로가 존재하면, 이 부분을 실행
#endif
// 3
#ifndef 매크로
매크로가 존재하지 않으면, 이 부분을 실행
#endif

// 매크로를 정의
#define 매크로명 매크로 내용
// 매크로 정의를 해제
#undef 매크로명

유용한 것은:#version 101 는 GLSL ES1.01 버전의 사용을 지정 가능. 이 지시는 반드시 쉐이더의 탑에 있으며, 전에는 공백 또는 주석만 가능

참고 자료

  • 《WebGL 프로그래밍 가이드》

댓글

아직 댓글이 없습니다

댓글 작성