GLSL語言基礎


GLSLwiki   chs)是OpenGL(OpenGL ES、WebGL)的着色器語言,擁有如下特點:

1. 基於C語言的語法(如:大小寫敏感,每條語句必須以分號結尾),是一門面向過程的強類型語言(type sensitive language)

2. 預處理中沒有#include包含文件指令

3. 除了bool、int、uint、float基礎類型外,還支持數組類型,另外GLSL還內置了適合3D圖形操作的向量與矩陣類型,以及采樣器(紋理)類型   

4. double、dvec*、dmat*類型需要#version 400及以上才支持

5. 更嚴格類型隱式轉換規則

6. 變量沒有賦初值時,都會被填充為false、0或0.0

7. if條件語句和switch條件語句與C語言一致

8. for循環語句和while循環語句與C語言一致

9. return、continue和break與C語言一致。另外引入了discard,該關鍵字只能在fs中使用,表示放棄當前片元,直接處理下一個片元。

10. 無指針、無字符和字符串類型

11. 無union、無enum

12. 向量、矩陣、自定義結構體變量可通過構造函數進行初始化

13. 增添了一些C++語言的特性:如函數重載

 

shader運行時,死循環或者崩潰,會導致進程無響應(彈出如下對話框),驅動崩潰重啟

 

與C語言一樣,包括:預處理 -- 編譯 -- 鏈接 -- 執行   四大步驟 

 

注釋

單行注釋

// Hello GLSL.

多行注釋

/*********************************
 This is my first GLSL.
 Let's take a look.
*********************************/

 

預處理

#version XXX // 用於指定當前glsl文件的版本   

①不同的版本glsl,所能使用語言特性是不一樣的。如:layout (location = 0) in vec3 Position;  // layout是330才支持的特性

②如果要加該#version指令,必須是當前glsl文件的第一句有效代碼行

③如果不加該#version指令,默認為GLSL 1.1,即:#version 110   注:WebGL1.0中vs和fs開頭不用寫#version版本,其語法對應GLSL ES 1.0(或GLSL 1.1)

#version 110          // GLSL 1.1  OpenGL 2.0  【默認】
#version 120          // GLSL 1.2  OpenGL 2.1
#version 130          // GLSL 1.3  OpenGL 3.0
#version 140          // GLSL 1.4  OpenGL 3.1
#version 150          // GLSL 1.5  OpenGL 3.2
#version 330          // GLSL 3.3  OpenGL 3.3
#version 330 core     // 【同上】
#version 400          // GLSL 4.0  OpenGL 4.0
#version 410          // GLSL 4.1  OpenGL 4.1
#version 420          // GLSL 4.2  OpenGL 4.2
#version 430          // GLSL 4.3  OpenGL 4.3
#version 440          // GLSL 4.4  OpenGL 4.4
#version 450          // GLSL 4.5  OpenGL 4.5
#version 460          // GLSL 4.6  OpenGL 4.6

#version 150 compatibility // GLSL 1.5 並向前兼容GLSL 1.2、1.3、1.4的語法

#version 300 es // GLSL ES 3.0 或稱 ESSL 3.0   注:聲明為這個后,宏GL_ES會被定義為1 

GLSL不同版本的差異點,可參考:這里

 

#extension  extname : behaivor

extname為編譯器支持的擴展名稱

behaivor可以是require、enable、warn、disable

#extension all : disable   // 禁用所有擴展

#extension GL_NV_shadow_samplers_cube : enable  // 啟用名為GL_NV_shadow_samplers_cube的擴展

擴展行為說明

擴展行為 說明
require 擴展是必需的。若當前擴展不受支持,將拋出錯誤
enable 啟用擴展。若當前擴展不支持,將拋出警告
warn 對於擴展的任何使用均拋出警告
disable 禁用擴展。若當前擴展被使用,將拋出錯誤

 

#if  #elif [defined(), !defined()]  #else    #ifdef   #ifndef     #endif   // 條件編譯

#define TEST1  // 定義為空的宏
//#define TEST1 1  // 宏已被定義 編譯失敗 error C7101: Macro TEST1 redefined

#ifdef TEST1  // 條件成立
#endif

//#if TEST1  // 空值不能進行條件判斷 編譯失敗 error C0105: Syntax error in #if
//#endif

#undef TEST1  // 取消TEST1宏

#if TEST1  // 條件不成立   注:OpenGL有效; 但openGL es下  編譯失敗  error C0105: Syntax error in #if
#endif

#ifndef TEST1  // 條件成立
#endif

#define TEST1 -1  // 定義為int的宏

#define TEST2 // 定義為空的宏

#if TEST1 && defined(TEST2) // 條件成立
#endif

#define TEST3 true // 定義為bool的宏

#if TEST3  // 條件不成立  注:OpenGL有效;但openGL es下,bool不能進行條件判斷  編譯失敗  error C0105: Syntax error in #if
#endif

#if !TEST3  // 條件成立   注:OpenGL有效;openGL es下,bool不能進行條件判斷  編譯失敗  error C0105: Syntax error in #if
#endif

#if TEST3==true  // 條件成立  注:OpenGL有效;openGL es下,bool不能進行條件判斷  編譯失敗  error C0105: Syntax error in #if
#endif

#if !defined(TEST0) && TEST1 && defined(TEST2) // 條件成立
#endif

#define TEST4 100  // 定義為int的宏

#if TEST4  // 條件成立
#endif

#if TEST4 > 150
#elif (TEST4 > 120) || TEST1 // 進入elif分支
#endif

#if !TEST4
#else // 進入else分支
#endif

#define TEST5 2.0  // 定義為float的宏

//#if TEST5  //float不能進行條件判斷  編譯失敗  error C0105: Syntax error in #if
//#endif

//#if TEST5>0.0  //float不能進行條件判斷  編譯失敗  error C0105: Syntax error in #if
//#endif

 

#if

// Shader inputs and outputs keywords
//
// - ATTRIBUTE: used to mark a vertex shader inputs
// - SHADER_IN: used to mark a non-vertex shader inputs
// - SHADER_OUT: used to mark a non-fragment shader output
// - OUT: used to mark a fragment shader output
#if __VERSION__ >= 130

#define ATTRIBUTE in
#define SHADER_IN in
#define SHADER_OUT out
#define OUT out

#else

#define ATTRIBUTE attribute
#define SHADER_IN varying
#define SHADER_OUT varying
#define OUT

#endif

// Support array attributes
#if __VERSION__ >= 130

#define ARRAY_ATTRIBUTE(name, size) name[size]

#else

#define ARRAY_ATTRIBUTE(name, size) name[size]

#endif

// Uniform blocks
#if __VERSION__ >= 130

#define BEGIN_UNIFORM_BLOCK(name)   uniform name {

#define END_UNIFORM_BLOCK() };

#else

#define BEGIN_UNIFORM_BLOCK(name)

#define END_UNIFORM_BLOCK()

#endif

// Input and output blocks
#if __VERSION__ >= 150

#define BEGIN_INPUT_BLOCK(name) in name {
#define END_INPUT_BLOCK() };

#define BEGIN_OUTPUT_BLOCK(name) out name {
#define END_OUTPUT_BLOCK() };

#else

#define BEGIN_INPUT_BLOCK(name)
#define END_INPUT_BLOCK()

#define BEGIN_OUTPUT_BLOCK(name)
#define END_OUTPUT_BLOCK()

#endif

// Texturing functions
#if __VERSION__ >= 130

#define TEXTURE_2D texture
#define TEXTURE_3D texture
#define TEXTURE_RECT texture
#define TEXTURE_CUBE texture

#if __VERSION__ >= 150
#define TEXTURE_SIZE(sampler) textureSize(sampler)
#else
#define TEXTURE_SIZE(sampler) sampler ## _Size
#endif

#else

#define TEXTURE_2D texture2D
#define TEXTURE_3D texture3D
#define TEXTURE_RECT texture2DRect
#define TEXTURE_CUBE textureCube

#endif

// Invariance
#if __VERSION__ >= 120
#define INVARIANT invariant
#else
#define INVARIANT
#endif

// Attribute location
#if defined(GL_ARB_explicit_attrib_location)
#define LOCATION(loc)       layout(location = loc)
#else
#define LOCATION(loc)
#endif

// Geometry shader layout
#if __VERSION__ >= 150
#define GEOMETRY_LAYOUT_IN(from) layout (from) in
#define GEOMETRY_LAYOUT(to, max) layout (to, max_vertices = max) out
#else
#define GEOMETRY_LAYOUT_IN(from)
#define GEOMETRY_LAYOUT(to, max)
#endif



// 為GLSL ES着色器腳本時,需要設置float和int類型的精度
#ifdef GL_ES
precision mediump float;// 設置float類型的精度為中精度  注:高精度為highp、低精度為lowp
precision mediump int;  // 設置int類型的精度為中精度  注:高精度為highp、低精度為lowp
#endif

 

#define  #undef     // 宏定義、宏取消

#define TEST1 100  // 定義TEST1宏為100

#ifdef TEST1  // 條件成立
#undef TEST1   // 取消TEST1宏的定義
#endif

#if !defined(TEST1) // 條件成立
#endif

#define SQUARE(a) ((a)*(a))

#define MAX(a,b) \   // 宏必須在一行寫完,多行寫時必須帶上 \行連接符
    (((a) > (b)) ? (a) : (b))

#define MERGE(a, b) a##b // ## 字符拼接符

 

#line    // 指示下一行的行號,及當前所在的文件;該命令會修改__FILE__、__LINE__的值

該命令是提供給編譯器使用的,程序員最好不要使用該命令

#if __LINE__==10  // 判斷當前行號是否為10
#endif

#if __FILE__==0  // 條件成立  __FILE__好像缺省為0
#endif

#line 116 // 指定下一行的行號為116
#if __LINE__==116  // 條件成立
#endif

#line 200 5  // 指定下一行的行號為200,當前文件的ID標識為5
#if __FILE__==5  // 條件成立
#endif

 

#pragma   // 用來控制編譯器的一些行為

#pragma optimize(on) // 開啟編譯器優化 【默認】
#pragma optimize(off) // 關閉編譯器優化

#pragma debug(on)  // 開啟debug選項,以獲得更多的調試信息
#pragma debug(off) // 關閉debug選項 【默認】

#pragma STDGL invariant(all)  // 讓所有的變量全都不變   注:因為編譯器需要保證不變性,所以會限制對着色器進行優化

 

#error  // error命令被執行,會導致當前文件編譯失敗

#if __VERSION__ >= 150 // __VERSION__為內置宏,十進制整數,為當前GLSL文件的版本號
#error This is an error! // error C0000: This is an error!
#endif

 

__VERSION__、__FILE__、__LINE__、GL_ES、GL_FRAGMENT_PRECISION_HIGH

#if __VERSION__ >= 330 // __VERSION__為內置宏,int類型,為當前GLSL文件的版本號
#endif

#line 100 3  // 指定下一行的行號為100,當前文件的ID標識為3
#if __FILE__==3  // 條件成立  宏__FILE__為int類型,當前Source String的唯一ID標識
#endif

#if __LINE__==103  // 條件成立  宏__LINE__為int類型,當前的行號
#endif

#if GL_ES // OpenGL下,內置宏GL_ES未定義,條件不成立;openGL es下,GL_ES為1,條件成立
#if GL_FRAGMENT_PRECISION_HIGH  // 若當前片元着色器支持高浮點精度,則宏GL_FRAGMENT_PRECISION_HIGH為1
precision highp float; // 設置float類型的精度為高精度
precision highp int; // 設置int類型的精度為高精度
#else
precision mediump float;// 設置float類型的精度為中精度
precision lowp int;  // 設置int類型的精度為低精度
#endif
#endif

 

運算符

除了沒有指針相關的運算符外,其他的與c語言完全一致

注:對於向量、矩陣類型,運算符會在各個分量上進行

 

變量

變量名需要符合以下規則:

① 只能包括大小寫字母、數字和下划線

② 變量名不能以數字開頭

③ 不能是關鍵字或預留的關鍵字

④ 不能以gl_、webgl_或_webgl_開頭

 

全局變量:定義在函數體外的變量。作用域規則與c語言全局變量一致。

局部變量:定義在函數內的變量。作用域規則與c語言局部變量一致。

 

內置常量(以gl_開頭)

所在shader 常量
vs

const mediump int gl_MaxVertexAttribs = 16; // 可用的頂點輸入變量(GLSL 1.3之前為attribute變量)的最大數量

const mediump int gl_MaxVertexUniformVectors = 256;  // 可用的vec4統一變量(uniform變量)的最大數量  需要#version 410及以上

const mediump int gl_MaxVertexOutputVectors = 16; // 可用的頂點輸出變量(GLSL 1.3之前為varying變量)的最大數量  需要#version 410及以上

const mediump int gl_MaxVertexTextureImageUnits = 16;  // 可用的紋理的最大數量

const mediump int gl_MaxCombinedTextureImageUnits = 32; // vs和fs中可用的紋理的最大數量的總和

fs

const mediump int gl_MaxFragmentInputVectors = 15; // 片元輸入變量(GLSL 1.3之前為varying變量)的最大數量  需要#version 410及以上

const mediump int gl_MaxTextureImageUnits = 16;  // 可用的紋理的最大數量

const mediump int gl_MaxFragmentUniformVectors = 224;  // 可用的vec4統一變量(uniform變量)的最大數量  需要#version 410及以上

const mediump int gl_MaxDrawBuffers = 4;  // 多重渲染目標(MRT)的最大支持數量。

const mediump int gl_MinProgramTexelOffset = -8;  // 內建ESSL函數texture*Offset偏移參數遲滯的最小偏移值  需要#version 410及以上

const mediump int gl_MaxProgramTexelOffset = 7;  // 內建ESSL函數texture*Offset偏移參數遲滯的最大偏移值  需要#version 410及以上

 

內置變量(以gl_開頭)

所在shader 變量
vs

vec4 gl_Position;  //必須將變換后的位置寫入到這個變量中,用於輸出頂點位置的裁剪坐標。該變量用highp精度限定符聲明。

float gl_PointSize;  // 用於寫入以像素表示的點精靈尺寸。在渲染點時使用。該變量用highp精度限定符聲明。

int gl_VertexID; // 輸入變量,用於保存當前頂點的索引。該變量用highp精度限定符聲明。

int gl_InstanceID; // 輸入變量,用戶保存當前圖元的編號。對於常規的繪圖調用,該值為0。該變量用highp精度限定符聲明。

bool gl_FrontFacing; // 一個特殊變量,但不是vs直接寫入,而是根據vs生成的位置和渲染的圖元類型生成的。

 

struct gl_DepthRangeParameters
{
    highp float near; // near Z
    highp float far; // far Z
    highp float diff; // far - near
};
uniform gl_DepthRangeParameters gl_DepthRange; // vs唯一內建統一變量:窗口坐標中的深度范圍

fs

vec4 gl_FragCoord;  // 只讀變量,保存窗口相對坐標(x,y,z,1/w)。

bool gl_FrontFacing; // 只讀變量,片段是正面時為ture,否則為false。

vec2 gl_PointCoord;  // 只讀變量,保存點精靈的紋理坐標,處於[0.0, 1.0]區間

float gl_FragDepth;  // 一個只寫輸出變量。在fs中寫入時,覆蓋片段固定功能深度值。應謹慎使用該功能,可能禁用GPU的深度優化(如:Early-Z)

vec4 gl_FragColor;  // fs輸出的片元顏色

 

const變量

表示該變量的值不能被修改。聲明的同時必須對它進行初始化,聲明之后就不能再去改變它的值了,否則會導致編譯錯誤。

const int lightspeed = 399792458;  // 光速 m/s
const vec4 red = vec4(1.0, 0.0, 0.0);  // 紅色
const mat4 identity = mat4(1.0);  // 4x4單位矩陣 

 

頂點輸入變量(GLSL 1.3之前為attribute變量)

與頂點相關的輸入型變量,被用來表示逐頂點的信息,必須聲明為全局變量,僅在vs中使用。如:頂點的position、normal、uv等。這些變量為cpu傳來的數據。

其只能是float或由float組合成的復合類型(vec2、vec3、vec4、mat2、mat3、mat4)

在#version 130及以上,頂點輸入變量使用關鍵字in,而不再使用attribute

#if __VERSION__ >= 130

in vec3 position;
in vec3 normal;
in vec2 uv;
in vec2 uv2;

#else

attribute vec3 position;
attribute vec3 normal;
attribute vec2 uv;
attribute vec2 uv2;

#endif

頂點輸入變量可以使用布局限定符來修飾

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;

location的值由void glVertexAttribPointer( GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)函數的第一個參數index來指定

 

統一變量(uniform變量)

是只讀的,與頂點和像素無關的輸入型變量,被用來表示非逐頂點、非逐像素、各頂點、各像素共用的信息,必須聲明為全局變量,可在vs和fs中使用。如:mvp矩陣

可以是除了數組或結構體之外的任意類型。如果vs和fs中聲明了同名的統一變量(uniform變量),那么它就會被兩種着色器共享。

vs代碼:

#version 330

layout (location = 0) in vec3 Position;

uniform mat4 gWVP;

out vec4 Color;

void main()
{
    gl_Position = gWVP * vec4(Position, 1.0);
    Color = vec4(clamp(Position, 0.0, 1.0), 1.0);
}

openGL代碼:

GLuint ShaderProgram = glCreateProgram();

// ... ... 

GLuint Location = glGetUniformLocation(ShaderProgram, "gWVP");  // 獲取shader中uniform mat4 gWVP變量的location

if (Location != INVALID_UNIFORM_LOCATION) {
    float m[4][4] = { {0.0f, 1.0f, 0.5f, 0.2f},
                      {0.1f, 0.0f, 1.5f, 0.0f},
                      {0.0f, 1.2f, -0.5f, 0.1f},
                      {0.2f, 1.0f, 1.5f, 0.7f}
                    };
    glUniformMatrix4fv(Location, 1, GL_TRUE, (const GLfloat*)m);  // 設置uniform mat4 gWVP變量的值
}

 

統一變量塊(uniform變量塊) 

OpenGL中使用統一變量緩沖區對象來支持統一變量塊(uniform變量塊) 數據的存儲。

相比單一的統一變量(uniform變量),統一變量塊(uniform變量塊) 具有以下優勢:

① 更高效   ② 不受默認大小限制,增加了統一變量的可用存儲

vs代碼:

// ... ...
layout (std140) uniform LightBlock
{
    vec3 lightDirection;
    vec4 lightPosition;
};

// ... ...

openGL代碼:

GLuint ShaderProgram = glCreateProgram();

// ... ...

GLuint blockId, bufferId;
GLint blockSize;
GLuint bindingPoint = 1;
GLfloat lightData[] = 
{
    // lightDirection (padding to vec4 based on std140 rule)
    1.0f, 0.0f, 0.0f, 0.0f,
    
    // lightPosition
    0.0f, 0.0f, 0.0f, 1.0f
};

// Retrieve the uniform block index
blockId = glGetUniformBlockIndex(ShaderProgram, "LightBlock");

// Associate the uniform block index with a binding point
glUniformBlockBinding(ShaderProgram, blockId, bindingPoint);

// Get the size of lightData
// alternatively, we can calculate it using sizeof(lightData) in this example
glGetActiveUniformBlockiv(ShaderProgram, blockId, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);

// Create and fill a buffer object
glGenBuffers(1, &bufferId);
glBindBuffer(GL_UNIFORM_BUFFER, bufferId);
glBufferData(GL_UNIFORM_BUFFER, blockSize, lightData, GL_DYNAMIC_DRAW); // 將lightData數組的數據綁定到名為統一變量塊LightBlock上

// Bind the buffer object to the uniform block binding point
glBindBufferBase(GL_UNIFORM_BUFFER, bindingPoint, bufferId);

 

布局限定符

限定符 說明
shared(默認) 多個着色器程序間共享。可省略不寫
packed 最小內存占用,無法在多個着色器程序間共享
std140 標准內存布局
column_major(默認) 矩陣變量以列優先順序。可省略不寫
row_major 矩陣變量以行優先順序

① shared、packed和std140有着不同地內存對齊方式

② 布局限定符可用於統一的變量塊,也可以用在統一變量塊中某個單獨的變量上    注:用在單獨變量上時,對於該變量會覆蓋掉全局對應的布局限定符

layout (shared, column_major) uniform TransformBlock
{
    layout (std140, row_major) mat4 matViewProj;      // matViewProj布局為std140行優先
    layout (row_major) mat3 matNormal;                // matNormal布局為shared行優先
    mat3 matTexGen;                                    // matViewProj布局為shared列優先
};

 

頂點輸出與片元輸入變量(GLSL 1.3之前為varying變量)

必須聲明為全局變量,其任務是從vs向fs傳輸數據。該數據對cpu是不可見的。

在vs和fs中必須聲明同名、同類型的該變量。

需要注意的是,vs中輸出變量的值並不是直接傳給fs的輸入變量。

在進入fs之前,會進行光柵化,根據繪制的圖形,對vs的輸出變量進行插值(Interpolation),然后再傳遞給fs的v輸入變量。

該類型的變量只能是float或由float組合成的復合類型(vec2、vec3、vec4、mat2、mat3、mat4)

在#version 130及以上,頂點輸出與片元輸入變量使用關鍵字in,而不再使用varying

與頂點輸入變量相比,頂點輸出與片元輸入變量不能使用layout布局限定符。

vs中頂點輸出變量

#if __VERSION__ >= 130

out vec3 vPosition;
out vec3 vNormal;
out vec2 vUv;
out vec2 vUv2;

#else

varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
varying vec2 vUv2;

#endif

為了保證不變性,GLSL引入了invariant關鍵字來修飾頂點輸出變量。

主要的原因是,為了優化,編譯器可能對shader指令重新排序,可能導致2個着色器之間的等價計算不能保證產生完全相同的結果。特別是在進行多遍渲染時,尤其可能成為問題。

例如:fs中第一遍中計算鏡面反射光,第二遍計算環境光和漫反射光,頂點輸出變量如果不使用invariant關鍵字,精度帶來的小誤差會導致深度沖突(Z fighting)。

invariant關鍵字既可用於聲明變量,也可以用於已經聲明過的變量。

invariant vec2 texCoord; // 用於聲明變量

invariant gl_Position;  // 用於已經聲明過的變量

#pragma STDGL invariant(all)  // 讓所有的變量全都不變   注:因為編譯器需要保證不變性,所以會限制對着色器進行優化

 

fs中片元輸入變量

#if __VERSION__ >= 130

in vec3 vPosition;
in vec3 vNormal;
in vec2 vUv;
in vec2 vUv2;

#else

varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vUv;
varying vec2 vUv2;

#endif

 

fs中片元輸出變量

layout(location = 0) out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0, 0.0, 0.0, 0.0);
}

注1:在典型情況下,只會渲染一個顏色緩沖區,這個時候,layout(location = 0)布局限定符可忽略不寫(默認輸出變量會進入位置0)

注2:當渲染到多個渲染目標(MRT)時,可以使用布局限定符指定每個輸出前往的渲染目標

 

插值限定符來修飾頂點輸出與片元輸入變量(GLSL 1.3之前為varying變量)

插值限定符 說明  示例
smooth(缺省)

平滑着色

/*** vs ***/

smooth out vec3 v_color;  // smooth可省略不寫

/*** fs ***/

smooth in vec3 v_color;  // smooth可省略不寫

flat 平面着色

/*** vs ***/

flat out vec3 v_color;

/*** fs ***/

flat in vec3 v_color;

centroid

質心采樣(centroid sampling)

 

使用多重采樣渲染時,centroid可用於強制插值發生在被渲染圖元內部

這可防止圖元的邊緣出現偽像

/*** vs ***/

centroid out vec3 v_color;

/*** fs ***/

centroid in vec3 v_color;

 

 

vs/fs中能容納的頂點輸入變量(attribute變量)、uniform變量、頂點輸出與片元輸入變量(varying變量)是儲存在硬件中的,其最大數目與設備有關,具體詳見下表:

變量類別 保存在硬件的哪個位置 是否會打包 內置全局變量(表示最大數量) glGetintegerv查詢 OpenGL ES 3.0最小值
頂點輸入變量(attribute變量)   No const mediump int gl_MaxVertexAttribs   16
vs:統一變量(uniform變量) 常量存儲:對應一個向量的物理數組 Yes const mediump int gl_MaxVertexUniformVectors GL_MAX_VERTEX_UNIFORM_VECTORS 256
fs:統一變量(uniform變量) 常量存儲:對應一個向量的物理數組 Yes const mediump int gl_MaxFragmentUniformVectors GL_MAX_FRAGMENT_UNIFORM_VECTORS 224

頂點輸出變量

片元輸入變量

(varying變量)

插值器:對應一個向量的物理數組

Yes

const mediump int gl_MaxVertexOutputVectors

const mediump int gl_MaxFragmentInputVectors

const mediump int gl_MaxVaryingVectors

 

16

15

8(Open GL ES 2.0)

注1:為了有效利用寶貴的硬件存儲資源,OpenGL會對變量打包再進行存放。

注2:用uniform修飾的變量、const變量、字面值(如:在代碼中寫的0,1.0等)都會占用常量儲存空間。

 

 

精度限定符

用來表示每種數據具有的精度(占用的字節數)。精度越高,計算結果誤差就越小、效果也更好,但也意味着更大的內存、更多能耗和更久的計算時間。

使用精度限定符,可以精細地控制shader程序在效果和性能間的平衡。

精度限定符 描述 float數值范圍和精度 int數值范圍
highp(高精度)

vs的最低精度

 

注:在某些webgl環境中,fs可能不支持highp精度

如果支持的話,會定義內置宏GL_FRAGMENT_PRECISION_HIGH

范圍:(-2^62~2^62)

精度:2^-16

(-2^16~2^16)
mediump(中精度)

fs的最低精度

范圍:(-2^14~2^14)

精度:2^-10

(-2^10~2^10)
lowp(低精度) 可以表示所有的顏色

范圍:(-2~2)

精度:2^-8

(-2^8~2^8)

 

各精度限定符的數值范圍和精度實際上與系統環境有關,可動態地使用gl.GetShaderPrecisionFormat()來獲取

 

對單個變量

mediump float size;  // 中精度的浮點型變量
highp vec4 position;  // 具有高精度浮點型元素的vec4對象
lowp vec4 color; // 具有低精度浮點型元素的vec4對象

 

對整個文件

precision mediump float; // 所有float和由float組合成的復合類型(vec2、vec3、vec4、mat2、mat3、mat4)的數默認為中精度
precision highp int;  // 所有int和由int組合成的復合類型的數默認為高精度

注:需要放在shader文件緊跟#version xxx的后面,其他語句之前

 

各數據類型的默認精度

shader類型 數據類型 默認精度
vs int highp
float highp
sampler2D lowp
samplerCube lowp
fs int mediump
float

無(需手動指定,否則會編譯報錯)

sampler2D lowp
samplerCube lowp

基礎類型

bool b1 = true;

int n1 = 10;
int n2 = -25;
int n3 = 0;
//int n4 = 3.5;  // 編譯失敗! 不能將float隱式地轉換成int

//uint u1 = 0; // 編譯失敗! 不能將int隱式地轉換成uint
uint u2 = 0u;
uint u3 = 100u;


float f1 = 2.0;
float f2 = 3;
float f3 = 0.2f;
float f4 = n1;
float f5 = float(n1);
float f6 = u2;
float f7 = float(u3);
//float f8 = b1; // 編譯失敗! 不能將bool隱式地轉換成float
//float f9 = (float)b1;// 編譯失敗! 不能使用c類型的轉換方式
float f9 = float(b1);

int n4 = int(f3);
//int n5 = f3; // 編譯失敗! 不能將float隱式地轉換成int
//int n6 = u3; // 編譯失敗! 不能將uint隱式地轉換成int
int n7 = int(u3);
//uint u4 = n1; // 編譯失敗! 不能將int隱式地轉換成uint
uint u5 = uint(n2);

//bool b2 = n1; // 編譯失敗! 不能將int隱式地轉換成bool
bool b3 = bool(n1);
//bool b4 = u3; // 編譯失敗! 不能將uint隱式地轉換成bool
bool b5 = bool(u3);
//bool b6 = f3; // 編譯失敗! 不能將float隱式地轉換成bool
bool b7 = bool(f3);

 

數組

只支持一維數組。

const float a1[3] = float[](0.25, 0.5, 1.0);
float a2[2] = float[2](0.3, 0.8);

float a4[3];
a4[0] = 0.1;
a4[1] = 0.2;
a4[2] = 0.3;

int len = a4.length(); // len為3  獲取數組a4的元素個數

const int N = 2;
vec3 va1[N];
va1[0] = vec3(1.0, 0.0, 0.0);
va1[1] = vec3(0.0, 0.0, 1.0);

vec3 va2[2] = vec3[](vec3(1.0), vec3(0.2, 0.3, 0.5));

 

結構體(struct)

① 與C語言結構體一樣,不可從其他結構體上派生

② 與C語言結構體一樣,不允許有構造函數和析構函數

③ 可直接對2個結構體變量進行比較

#version 330

out vec4 FragColor;

struct light // 與C語言一樣,不允許從其他結構體上派生
{
    vec4 color;
    vec3 position;
    
    //light(){} // 與C語言一樣,不允許有構造函數
    //~light(){} // 與C語言一樣,不允許有析構函數

    void test()
    {
        color.x = 0.2;
    }
} GL1; // 定義light結構體,並定義全局變量GL1

light GL2; // 定義light結構體的全局變量GL2

void main()
{
    // light結構體的構造函數參數的順序必須與結構體定義中的成員順序一致
    // 如下:參數一 vec4(1.0, 1.0, 0.0, 1.0)會賦值給vec4 color  參數二 vec3(10.0, 10.0, 0.0)會賦值給vec3 position
    GL1 = light(vec4(1.0, 1.0, 0.0, 1.0), vec3(10.0, 10.0, 0.0));
    
    GL1.test();

    GL2.color.r = 1.0;
    GL2.position = vec3(3.0, 4.0, 5.0);

    light L1, L2; // 定義light結構體的局部變量L1,L2
    L1.color = vec4(0.0, 1.0, 0.0, 1.0);
    
    L2 = L1;
    if (L1 == L2)  // true  結構體支持==運算符比較
    {
        
    }

    L2.position.x = 100;
    if (L1 != L2)  // true   結構體支持!=運算符比較
    {
        
    }

    FragColor = GL1.color;
}

 

向量

向量的分量可以為:

① {x,y,z,w} : 用來獲取頂點坐標分量

② {r,g,b,a} : 用來獲取顏色分量

③ {s,t,p,q} :用來獲取紋理坐標分量

 

從向量中可以同時抽取多個分量,這個過程稱作混合(swizzling)。但要注意地是,以上三種不能相互混着使用,如:xyr、rgst、xrsw等

分量類型

2維

3維

4維

bool bvec2 bvec3 bvec4
int ivec2 ivec3 ivec4
uint uvec2 uvec3 uvec4
float vec2 vec3 vec4

 

vec2 v2a; // v2a為(0.0, 0.0)
vec2 v2b = vec2(1.0f); // v2b為(1.0f, 1.0f)
vec2 v2c = vec2(1.0, 0.0); // v2c為(1.0, 0.0)
//vec3 v2d = v2c.xx; // 編譯失敗 incompatible types in initialization
vec2 v2e; // v2e為(0.0, 0.0)
v2e = v2c.yx; // v2e為(0.0, 1.0)
vec2 v2f; // v2f為(0.0, 0.0)
v2f = v2c.rr; // v2f為(1.0, 1.0)

float f1 = v2c[0];  // f1為1.0  v2c[0]=v2c.x=v2c.r=v2c.s
float f2 = v2c.y;  // f1為0.0  v2c.y=v2c.g=v2c.t=v2c[1]

// 向量運算
vec2 v2g = vec2(0.4, 0.6);
vec2 v2h = vec2(0.1, 0.2);
vec2 v2i = v2g + v2h; // v2i為(0.5, 0.8)
vec2 v2j = v2g + 0.2; // v2j為(0.6, 0.8)
vec2 v2k = v2h * 2; // v2k為(0.2, 0.4)
vec2 v2m = v2g * v2h; // v2m為(0.04, 0.12)

vec3 v3a = vec3(0.5); // v3a為(0.5, 0.5, 0.5)
//vec3 v3b = vec3(1.0, 1.0); // 編譯失敗  too little data in type constructor
vec3 v3c = vec3(1.0, 0.5, 0.25); // v3c為(1.0, 0.5, 0.25)

//vec3 v3d = vec3(v2a); // 編譯失敗  cast not allowed
vec3 v3e = vec3(v2a, 1.0); // v3e為(0.0, 0.0, 1.0)

vec2 v2n = vec2(v3c);  // 使用v3c的前2個元素 v2n為(1.0, 0.5)

vec4 v4a = vec4(0.0, 0.3, 1.0, 0.5);  // v4a為(0.0, 0.3, 1.0, 0.5)
v4a.xw = vec2(0.2, 0.6);  // v4a為(0.2, 0.3, 1.0, 0.6)
v4a.gbr = vec3(0.0, 0.0, 1.0);  // v4a為(1.0, 0.0, 0.0, 0.6)
v4a.pq = vec2(1.0, 0.0); // v4a為(1.0, 0.0, 1.0, 0.0)
vec4 v4b = vec4(v2c, v3c);  // 先使用v2c來填充,如果沒填滿繼續使用v3c來填充  v4b為(1.0, 0.0, 1.0, 0.5)
vec4 v4c;
v4c = vec4(0.0, 0.3, 1.0, 0.5).wwwx;  // v4c為(0.5, 0.5, 0.5, 0.0)

 

矩陣

分量類型均為float,按照列優先順序來存儲(列主序)

矩陣類型 解釋
mat2(mat2x2) 由2個列向量vec2組成(可通過m[0]、m[1]來訪問)
mat2x3 由2個列向量vec3組成(可通過m[0]、m[1]來訪問)
mat2x4 由2個列向量vec4組成(可通過m[0]、m[1]來訪問)
mat3x2 由3個列向量vec2組成(可通過m[0]、m[1]、m[2]來訪問)
mat3(mat3x3) 由3個列向量vec3組成(可通過m[0]、m[1]、m[2]來訪問)
mat3x4 由3個列向量vec4組成(可通過m[0]、m[1]、m[2]來訪問)
mat4x2 由4個列向量vec2組成(可通過m[0]、m[1]、m[2]、m[3]來訪問)
mat4x3 由4個列向量vec3組成(可通過m[0]、m[1]、m[2]、m[3]來訪問)
mat4(mat4x4) 由4個列向量vec4組成(可通過m[0]、m[1]、m[2]、m[3]來訪問)

 

vec2 v2a = vec2(1.0, 0.5); // v2a為(1.0, 0.5)
vec3 v3a = vec3(0.3, 0.2, 0.9); // v3a為(0.3, 0.2, 0.9)
vec4 v4a = vec4(0.2, 0.3, 0.8, 0.0); // v4a為(0.2, 0.3, 0.8, 0.0)
mat2 m2a;  // m2a為(0.0, 0.0, 0.0, 0.0)
mat2 m2b = mat2(1.0);  // m2b為(1.0, 0.0, 0.0, 1.0)
                       // | 1.0  0.0 |
                       // | 0.0  1.0 | 
mat2 m2c = mat2(0.2, 0.5, 0.0, 0.8);  // m2c為(0.2, 0.5, 0.0, 0.8)
                                      // | 0.2  0.0 |
                                      // | 0.5  0.8 |
mat2 m2d = mat2(v2a, 0.1, 0.3); // m2d為(1.0, 0.5, 0.1, 0.3)
mat2 m2e = mat2(0.6, v3a); // m2e為(0.6, 0.3, 0.2, 0.9)
mat2 m2f = mat2(v2a, v3a); // 先使用v2a來填充,如果沒填滿繼續使用v3a來填充  m2f為(1.0, 0.5, 0.3, 0.2)
mat2 m2g = mat2(v4a); // m2g為(0.2, 0.3, 0.8, 0.0)
                      // | 0.2  0.8 |
                      // | 0.3  0.0 |
mat2 m2h = mat2(v2a.yyxx); // m2g為(0.5, 0.5, 1.0, 1.0)
                      // | 0.5  1.0 |
                      // | 0.5  1.0 |
mat2x3 m2x3a = mat2x3(v2a.xyx, v3a); // m2x3a為(1.0, 0.5, 1.0, 0.3, 0.2, 0.9)
                                     // | 1.0  0.3 |
                                     // | 0.5  0.2 |
                                     // | 1.0  0.9 |

vec2 v2b = m2b[1];  // v2b為(0.0, 1.0)
vec3 v3b = m2x3a[0]; // v3b為(1.0, 0.5, 1.0)
int n = 1;
vec3 v3c = m2x3a[n]; // v3c為(0.3, 0.2, 0.9)

float f1 = m2c[1][0];  // f1為0.0
float f2 = m2c[0].y;  // f2為0.5
float f3 = m2x3a[0].b;  // f3為1.0

mat4 m4a = mat4(0.5); // m4a為(0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5)
                      // | 0.5  0.0  0.0  0.0 |
                      // | 0.0  0.5  0.0  0.0 |
                      // | 0.0  0.0  0.5  0.0 |
                      // | 0.0  0.0  0.0  0.5 |
// 矩陣與浮點數相加
mat4 m4b = m4a + 0.5; // m4b為(1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.5, 1.0)
                      // | 1.0  0.5  0.5  0.5 |
                      // | 0.5  1.0  0.5  0.5 |
                      // | 0.5  0.5  1.0  0.5 |
                      // | 0.5  0.5  0.5  1.0 |
// 矩陣與浮點數相乘
mat4 m4c = m4a * 2;   // m4c為(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)
                      // | 1.0  0.0  0.0  0.0 |
                      // | 0.0  1.0  0.0  0.0 |
                      // | 0.0  0.0  1.0  0.0 |
                      // | 0.0  0.0  0.0  1.0 |

mat4 m4d = mat4(1.0, 0.5, 0.5, 0.5, 0.5, 1.0, 0.5, 0.5, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 1.0);
                      // | 1.0  0.5  0.5  0.5 |
                      // | 0.5  1.0  0.25 0.5 |
                      // | 0.5  0.5  0.25 0.5 |
                      // | 0.5  0.5  0.5  1.0 |

// 矩陣右乘向量 
vec4 v4b = m4d * v4a; // v4b為(0.75, 0.6, 0.45, 0.65)  注:v4a被當成列向量
                      // v4b.x = m4d[0].x * v4a.x + m4d[1].x * v4a.y + m4d[2].x * v4a.z + m4d[3].x * v4a.w = 0.75
                      // v4b.y = m4d[0].y * v4a.x + m4d[1].y * v4a.y + m4d[2].y * v4a.z + m4d[3].y * v4a.w = 0.6
                      // v4b.z = m4d[0].z * v4a.x + m4d[1].z * v4a.y + m4d[2].z * v4a.z + m4d[3].z * v4a.w = 0.45
                      // v4b.w = m4d[0].w * v4a.x + m4d[1].w * v4a.y + m4d[2].w * v4a.z + m4d[3].w * v4a.w = 0.65
// 矩陣左乘向量 
vec4 v4c = v4a * m4d; // v4c為(0.75, 0.8, 0.375, 0.65)  注:v4a被當成行向量
                      // v4c.x = v4a.x * m4d[0].x  + v4a.y * m4d[0].y + v4a.z * m4d[0].z + v4a.w * m4d[0].w = 0.75
                      // v4c.y = v4a.x * m4d[1].x  + v4a.y * m4d[1].y + v4a.z * m4d[1].z + v4a.w * m4d[1].w = 0.8
                      // v4c.z = v4a.x * m4d[2].x  + v4a.y * m4d[2].y + v4a.z * m4d[2].z + v4a.w * m4d[2].w = 0.375
                      // v4c.w = v4a.x * m4d[3].x  + v4a.y * m4d[3].y + v4a.z * m4d[3].z + v4a.w * m4d[3].w = 0.65

// 矩陣矩陣相乘
mat2 m2i = mat2(0.1, 0.0, 0.6, 0.2);  // m2i為(0.1, 0.0, 0.6, 0.2)
                                      // | 0.1  0.6 |
                                      // | 0.0  0.2 |
mat2 m2j = m2c * m2i; // m2j為(0.02, 0.05, 0.12, 0.46)
                      // | m2c[0].x*m2i[0].x+m2c[1].x*m2i[0].y  m2c[0].x*m2i[1].x+m2c[1].x*m2i[1].y |    |  0.02  0.12  |
                      // | m2c[0].y*m2i[0].x+m2c[1].y*m2i[0].y  m2c[0].y*m2i[1].x+m2c[1].y*m2i[1].y |    |  0.05  0.46  |

 

采樣器(紋理)

只能是uniform變量,該變量從OpenGL中接受紋理單元編號,使得shader能通過該編號來訪問紋理數據。

采樣器(sampler)類型:

大類型 小類型 說明 示例
浮點采樣器(不透明) sampler1D 1D紋理 uniform sampler1D s;
sampler2D 2D紋理 uniform sampler2D s;
sampler3D 3D紋理 uniform sampler3D s;
samplerCube 立方圖紋理 uniform samplerCube s;
samplerCubeShadow 帶有對比的立方圖深度紋理 uniform samplerCubeShadow s;
sampler1DShadow 帶有對比的1D深度紋理 uniform sampler1DShadow s;
sampler1DArray 1D數組紋理 uniform sampler1DArray s;
sampler1DArrayShadow 帶有對比的1D數組深度紋理 uniform sampler1DArrayShadow s;
sampler2DShadow 帶有對比的2D深度紋理 uniform sampler2DShadow s;
sampler2DArray 2D數組紋理 uniform sampler2DArray s;
sampler2DArrayShadow 帶有對比的2D數組深度紋理 uniform sampler2DArrayShadow s;
有符號整數采樣器(不透明) isampler1D 有符號整數1D紋理 uniform isampler1D s;
isampler2D 有符號整數2D紋理 uniform isampler2D s;
isampler3D 有符號整數3D紋理 uniform isampler3D s;
isamplerCube 有符號整數立方圖紋理 uniform isamplerCube s;
isampler1DArray 有符號整數1D數組紋理 uniform isampler1DArray s;
isampler2DArray 有符號整數2D數組紋理 uniform isampler2DArray s;
無符號整數采樣器(不透明) usampler1D 無符號整數1D紋理 uniform usampler1D s;
usampler2D 無符號整數2D紋理 uniform usampler2D s;
usampler3D 無符號整數3D紋理 uniform usampler3D s;
usamplerCube 無符號整數立方圖紋理 uniform usamplerCube s;
usampler1DArray 無符號整數1D數組紋理 uniform usampler1DArray s;
usampler2DArray 無符號整數2D數組紋理 uniform usampler2DArray s;

 

除了=、==和!=外,采樣器變量不可以作為操作數參與運算

vs/fs中能使用采樣器的個數,詳見下表:

着色器類型 最大數量 最小數量
vs gl_MaxVertexTextureImageUnits 0
fs gl_MaxTextureImageUnits 8

 

函數

函數用法和C語言一樣

vs和fs執行的入口函數均為void main()  {  }

函數參數限定詞說明:

限定詞 說明
in 缺省限定詞,可以省略不寫
const 當前參數為常量,不可在函數內被修改
out

① 進入函數時,會被初始化為0, 0.0或false

② 在函數內修改后,對外可見

inout

① 接受函數外傳入的初始值

② 在函數內修改后,對外可見

① 參數限定詞只需要用在函數上,函數調用時不用帶。

② 不允許函數遞歸    這一限制的原因是編譯器會把函數都內聯展開,以支持沒有堆棧的GPU

float square(float value) // 求平方
{
    return value * value;
}

void fuc1(const float value) // const參數不能在函數內部修改
{
    //value = 0.2; // assignment to const variable value  編譯錯誤
}

void fuc2(out float value)  // value進入函數時,會被重新初始化為0;在函數內修改,對外可見
{
    value += 0.5;
}

void fuc3(inout float value) // value的初始值從函數外傳入;在函數內修改,對外可見
{
    value += 0.5;
}

int fun4(int n)  // 如果在main函數中直接或間接調用fun4函數,會編譯報錯:recursive call to function
{
    if (n == 0 || n == 1)
    {
        return 1;
    }
    return fun4(n-1) + fun4(n-2);
}

 

內置函數

類別 內置函數
角度函數

radians //角度轉弧度

degrees // 弧度轉角度

三角函數

sin // 正弦

cos // 余弦

tan // 正切

asin // 反正弦

acos // 反余弦

atan // 反正切

指數函數

pow // x^y 

exp // 自然指數

log // 自然對數

exp2  // 2^x 

log2 // 以2為底對數

sqrt // 開平方

inversesqrt // 開平方倒數 

通用函數

abs // 絕對值

min // 最小值

max // 最大值

mod // 取余數

sign // 取正負號

floor // 向下取整

ceil // 向上取整

clamp // 限定范圍

mix // 線性內插

step // 步進函數

smoothstep // 艾米內插步進

fract // 獲取小數部分

幾何函數

length // 矢量長度

distance // 兩點間距離

dot // 內積

cross // 外積

normalize // 歸一化 

reflect // 矢量反射

faceforward // 使矢量“朝前”

矩陣函數 matrixCmpMult // 逐元素乘法
矢量函數

lessThan // 逐元素小於

lessThanEqual // 逐元素小於等於

greaterThan // 逐元素大於

greaterThanEqual // 逐元素大於等於

equal // 逐元素相等

notEqual // 逐元素不等

any // 任一元素為true則為true

all // 所有元素為true則為true

not // 逐元素取補

紋理查詢函數

texture2D // 在二維紋理中獲取紋素

textureCube // 在立方體紋理中獲取紋素

texture2DProj // texture2D的投影版本

texture2DLod // texture2D的金字塔版本

textureCubeLod // textureCube的金字塔版本

texture2DProjLod // texture2DLod的投影版本

 

限定符順序規則

一般變量中:不變性(invariant ) >  插值(smooth、flat)  > 存儲(const、in、out、uniform、centroid in、centroid out)  >  精度(highp、mediump、lowp)

參數變量中:存儲(const、in、out、uniform、centroid in、centroid out)  >  參數(in、out、inout)   >  精度(highp、mediump、lowp)

 

幫助手冊

OpenGL ES 1.1 API(含GLSL內置函數)幫助手冊:https://www.khronos.org/registry/OpenGL-Refpages/es1.1/xhtml/

OpenGL ES 2.0 API(含GLSL內置函數)幫助手冊:https://www.khronos.org/registry/OpenGL-Refpages/es2.0/

OpenGL ES 3.0 API(含GLSL內置函數)幫助手冊:https://www.khronos.org/registry/OpenGL-Refpages/es3.0/

OpenGL ES 3.1 API(含GLSL內置函數)幫助手冊:https://www.khronos.org/registry/OpenGL-Refpages/es3.1/

OpenGL ES 3.2 API(含GLSL內置函數)幫助手冊:https://www.khronos.org/registry/OpenGL-Refpages/es3/

 

OpenGL 2.1, GLX, and GLU幫助手冊:https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/

OpenGL 4.5 API(含GLSL內置函數)幫助手冊:https://www.khronos.org/registry/OpenGL-Refpages/gl4/

 

Khronos OpenGL and OpenGL ES 參考頁:https://www.khronos.org/registry/OpenGL-Refpages/

 

WebGL 1.0 API幫助手冊:https://www.khronos.org/registry/webgl/specs/latest/1.0/

WebGL 2.0 API幫助手冊:https://www.khronos.org/registry/webgl/specs/latest/2.0/

 

參考卡片

OpenGL ES 2.0(含API和GLSL)參考卡片:https://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf

OpenGL ES 3.0(含API和GLSL)參考卡片:https://www.khronos.org/files/opengles3-quick-reference-card.pdf

OpenGL ES 3.1(含API和GLSL)參考卡片:https://www.khronos.org/files/opengles31-quick-reference-card.pdf

OpenGL ES 3.2(含API和GLSL)參考卡片:https://www.khronos.org/files/opengles32-quick-reference-card.pdf 

OpenGL ES 3.2(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl-quick-reference-card.pdf

 

OpenGL 3.2(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl-quick-reference-card.pdf

OpenGL 4.1(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl41-quick-reference-card.pdf

OpenGL 4.2(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl42-quick-reference-card.pdf

OpenGL 4.3(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl43-quick-reference-card.pdf

OpenGL 4.4(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl44-quick-reference-card.pdf

OpenGL 4.5(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl45-quick-reference-card.pdf

OpenGL 4.6(含API和GLSL)參考卡片:https://www.khronos.org/files/opengl46-quick-reference-card.pdf 

 

WebGL 1.0(含API和GLSL)參考卡片:https://www.khronos.org/files/webgl/webgl-reference-card-1_0.pdf

WebGL 2.0(含API和GLSL)參考卡片:https://www.khronos.org/files/webgl20-reference-guide.pdf

 

Vulkan 1.0(含API)參考卡片:https://www.khronos.org/files/vulkan10-reference-guide.pdf

Vulkan 2.0(含API)參考卡片:https://www.khronos.org/files/vulkan11-reference-guide.pdf

 

參考

高級GLSL

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM