OpenGL ES 入門之旅--OpenGL ES頂點着色器和片元着色器

此次咱們來從OpenGL ES的角度來學習一下頂點着色器和片元着色器。在這以前咱們先來看一下在OpenGL ES 3.0下的圖形管線:編程

圖形管線.png
這裏展現的只是一個簡圖,具體流程圖請參見 OpenGL 下的渲染流程和存儲着色器.

頂點着色器 Vertex Shader

頂點着色器,實現了一種通用的可編程方法操做頂點。 頂點着色器可用於傳統的基於頂點操做,例如經過矩陣變換位置、計算照明方程式以生成逐頂點的顏色以及生成或者變換紋理座標。數組

在編程中,頂點着色器的輸入主要有: 1.着色器程序 ShaderProgram---描述頂點上執行操做的頂點着色器程序編程源代碼或者可執行文件。 2.頂點着色器輸入屬性Attributes---用於頂點數組提供每一個頂點的數據。 3.統一變量Uniforms---頂點着色器和片元着色器使用的常量數據。 4.採樣器Samplers---表明頂點着色器使用的紋理的特殊統一變量類型,被Uniforms使用的特殊類型,在頂點着色器的貼圖中使用,且是可選的。緩存

相應的,頂點着色器的輸出叫作varying變量。 在最初的光柵化階段,這些變量被計算,做爲片斷着色器的輸入,從頂點着色器的矩陣使用插補的方法產生片斷着色器的變量,輸入和輸出以下圖所示: bash

頂點着色器輸入輸出.png
gl_Position:浮點型輸出變量,用於輸出頂點位置的裁剪座標,該值在裁剪和視口階段用於執行相應的圖元裁剪以及從裁剪座標到屏幕座標的頂點位置變換,頂點着色器沒有寫入gl_Position時其值是未定義的。 glPointSize:浮點輸出變量,用於寫入以像素表示的點尺寸,在渲染點時使用,頂點着色器輸出的這個變量值被限定在OpenGL ES 3.0實現支持的非平滑點大小範圍以內。

頂點着色器的業務:函數

1.矩陣變換位置 2.計算光照公式生成逐頂點顏色 3.生成或者變換紋理座標 下面來看一下頂點着色器的代碼片斷:性能

attribute vec4 position;  //四維向量
attribute vec2 textCoordinate;  // 紋理座標
uniform mat4 rotateMatrix; //旋轉4X4矩陣
varying lowp vec2 varyTextCoord; 
void main()
{
varyTextCoord = textCoordinate; 
vec4 vPos = position;
vPos = vPos * rotateMatrix; 
gl_Position = vPos;
}
複製代碼

#####頂點着色器中的內建變量 頂點着色器的內建變量能夠分爲:特殊變量(頂點着色器的輸入/輸出),統一狀態(深度範圍)以及規定的最大值(屬性數量,頂點着色器變量數量和統一變量數量)的常量.學習

內建特殊變量測試

gl_VertexID,是一個輸入變量,用於保存頂點的整數索引,這個整數型變量,用highp精度限定符聲明。優化

gl_InstanceID,是一個輸入變量,用於保存實例化繪圖調用中圖元的實例編號,對於常規調用的繪圖調用,該值爲0; gl_InstanceID是一個整數型變量,用highp精度限定符聲明。ui

gl_Position, 用於輸出頂點位置的裁剪座標,該值在裁剪和視口變換用於執行相應的圖元裁剪,以及從裁剪座標到屏幕座標的頂點位置變換。若是頂點着色器未寫入gl_Position,則gl_Position的值未定義,gl_Position是浮點型變量,用highp精度限定符聲明。

gl_PointSize,能夠寫入像素表示點精靈的尺寸,在渲染點精靈時使用,頂點着色器輸出的gl_PointSize值被限定在OPenGL ES 3.0實現支持的非平滑點大小範圍以內,gl_PointSize是一個浮點型變量,用highp精度限定符聲明。

gl_FrontFacing,是一個特殊變量,可是不是由頂點着色器直接寫入的,而是根據頂點着色器生成的位置值和渲染圖元的類型生成的,它是一個布爾值。

內建統一變量

在頂點着色器內可用的惟一內建Uniform狀態是窗口座標中的深度範圍,這些由內建統一變量名gl_DepthRange給出。

struct gl_DepthRangeParameters
{
highp float near; //near z 
highp float far; //near far 
highp float diff; //far - near
}
uniform gl_DepthRangeParameters gl_DepthRange;
複製代碼

內建常量 ·

const mediump int gl_MaxVertexAttribs = 16;
const mediump int gl_MaxVertexUniformVectors = 256; 
const mediump int gl_MaxVertexOutputVectors = 16;
const mediump int gl_MaxVertexTextureImageUnits = 16; 
const mediump int gl_MaxCombinedTextureImageUnits = 32;
複製代碼

gl_MaxVertexAttribs: 能夠指定的頂點數據最大的數量。 gl_MaxVertexUniformVectors:頂點着色器可使用的vect4 Uniform 變量最大數量。 gl_MaxVertexOutputVectors:表示輸出向量的最大數量。 gl_MaxVertexTextureImageUnits:頂點着色器可用紋理單元的最大數量。 gl_MaxCombinedTextureImageUnits:頂點/片元着色器中的可用紋理單元的最大數量的總和。

頂點着色器中的矩陣變換

MVP矩陣(模型--視圖--投影矩陣)頂點着色器的位置輸入保存的是物體座標,而輸出的座標保存爲裁剪座標,MVP矩陣是3D圖形中進行這種變換的3個很是重要的變換矩陣的乘積:模型矩陣,視圖矩陣,投影矩陣。 模型矩陣:---將物體座標變換爲世界座標 視圖矩陣:---將世界座標變換爲眼睛座標(觀察座標) 投影矩陣:---將眼睛座標(觀察座標)變換爲裁剪座標

在頂點着色器以後進入圖元裝配(Primitive Assembly)階段和光柵化(Rasterization)階段,此過程開發者沒法干預,(有關圖元裝配和光柵化的內容請參見:OpenGL 下的座標系和着色器渲染流程

片元着色器Fragment Shader

片元着色器是用於處理片元值及相關數據的可編程單元,其能夠執行紋理的採樣,顏色的彙總等操做。 片元着色器主要功能爲經過重複執行(每片元一次)將3D物體中的圖元光柵化後產生的每一個片元的顏色等屬性計算出來送入後繼階段;

片元着色器對光柵化階段產生的每一個片元進行操做,須要的輸入數據以下: 1.着色器程序Shader program:片元着色器的源碼或可執行文件,描述了將對片元執行的操做。 2.輸入變量Varying variables:頂點着色器輸出varying變量通過光柵化插值計算後產生的做用於每一個片元的值。 3.統一變量Uniforms:片元着色器使用的常量數據 4.採樣器Samplers:一種特殊的uniforms,表示片元着色器使用的紋理。

片元着色器的輸入和輸出以下圖所示:

片元.png

gl_FragColor值的是計算後此片元的顏色。通常在片元着色器的最後都須要對gl_FragColor進行賦值。

片元着色器的業務: 1.計算顏色 2.獲取紋理值 3.往像素點中填充顏色值(顏色值或者紋理值) 下面來看一下片元着色器的代碼片斷:

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap; //採樣器
void main()
{
//texture2D方法有兩個參數:(紋理採樣器,紋理座標),取得紋素(紋理的像素值)。
gl_FragColor = texture2D(colorMap, varyTextCoord); 
}
複製代碼

片元着色器中的內建變量

內建特殊變量

gl_FragCoord:片元着色器中的一個只讀變量,這個變量保存片元的窗口相對座標。

gl_FrontFacing:片元着色器中的一個只讀變量,這個布爾變量是正面圖元時爲true,不然爲false。

gl_PointCoord:只讀變量,能夠在渲染點精靈的時候使用,保存了點精靈的紋理座標,這個座標在點精靈光柵化期間自動生成,處於(0,1)區間。

gl_FragDepth:一個只寫輸出變量,在片元着色器寫入時,覆蓋片元的固定功能深度值,儘可能減小手動實現深度值寫入,這個功能須要謹慎使用,由於它可能禁用許多GPU的深度優化,例如:許多GPU都有「Early-z」的功能,在執行片元着色器以前進行深度測試,使用「Early-z」的好處就是不能經過深度測試的片元就不會被着色(從而下降了着色器的調用次數,提升了性能)可是使用gl_FragDepth,就必須禁用該功能,由於GPU在執行着色器以前不知道深度值。

內建常量

const mediump int gl_MaxFragmentInputVectors = 15;
const mediump int gl_MaxTextureImageUnits = 16;
const mediump int gl_MaxFragmentUniformVectors = 224;
const mediump int gl_MaxDrawBuffers = 4;
const mediump int gl_MinProgramTexelOffset = -8; 
const mediump int gl_MaxProgramTexelOffset = 7;
複製代碼

gl_MaxFragmentInputVectors: 片元着色器輸入的最大數量。 gl_MaxFragmentUniformVectors:可用紋理圖像單元的最大數量 gl_MaxFragmentUniformVectors:片元着色器可用vec4 Uniform變量最大數量 gl_MaxDrawBuffers:多重渲染目標最大支持數量

多重紋理混合

//⽚片元着⾊色器器代碼
attribute vec2 v_texCoord;
uniform sampler2D s_baseMap;
uniform sampler2D s_SecondMap;
void main()
{
  vec4 baseColor;
  vec4 secondColor;
  baseColor = texture(s_baseMap ,v_texCoord);
  secondColor = texture(s_SecondMap ,v_texCoord);
  gl_FragColor = baseColor * secondColor;
}
複製代碼
//客戶端代碼: 將各個紋理理對象綁定到紋理理單元0和1,爲採樣器器設置數 值,將採集器器綁定到對應的紋理理單元
glActiveTexutre(GL_TEXTURE0);
glBindTeture(GL_TEXTURE_2D ,baseMapTexId);
glUniformli(baseMapTexId,0);
glActiveTexutre(GL_TEXTURE1);
glBindTeture(GL_TEXTURE_2D ,secondMapTexId);
glUniformli(secondMapTexId,1);
複製代碼

逐片斷操做Per-Fragment Operations

先來看一下逐片斷操做的流程:

流程.png
像素歸屬測試:肯定幀緩存區中位置[Xw,Yw]的像素目前是否是歸屬於OpenGL ES全部。例如:若是一個顯示OpenGL ES幀緩存區View被另外一個View所遮蔽,則窗口系統能夠肯定被遮蔽的像素不屬於OpenGL ES上下文,從而不所有顯示這些像素。而像素歸屬測試是OpenGL ES的一部分,它不禁開發者人爲控制而是由OpenGL ES內部進行。

裁剪測試:裁剪測試肯定[Xw,Yw]是否位於做爲OpenGL ES狀態的一部分裁剪矩形範圍內,若是該片斷位於裁剪區域以外,則被拋棄。

深度測試:輸入片斷的深度值進行比較,肯定片斷是否拒絕測試。

混合:混合將新生成的片斷顏色與保存在幀緩存區的位置的顏色值組合起來。(這裏的混合與片元着色器的混合要區別開來。)

抖動:抖動可用於最小化由於使用有限精度在幀緩存區中保存顏色值而產生的僞像。

EGL(做爲了解)

OpenGL ES 命令須要渲染上下文和繪製表面才能完成圖形圖像的繪製。 渲染上下文:存儲的是相關OpenGL ES 狀態 繪製表面: 是用於繪製圖元的表面,它指定渲染所須要的緩存區類型,例如顏⾊緩存區,深度緩衝區和模板緩存區.

OpenGL ES API 並無提供如何建立渲染上下文或者上下文如何鏈接到原生窗口系統. EGL 是Khronos 渲染API(如OpenGL ES) 和原生窗口系統之間的接口.惟一⽀持 OpenGL ES 卻不支持EGL 的平臺是iOS. Apple 提供⾃自⼰的EGL API的iOS實現,稱爲EAGL. 由於每一個窗口系統都有不一樣的定義,因此EGL提供基本的不透明類型—EGLDisplay, 這個類型封裝了全部系統相關性,⽤於和原生窗⼝系統接口. 因爲OpenGL ES是基於C的API,所以它很是便攜且受到⼴泛支持。做爲C API,它與 Objective-C Cocoa Touch應⽤程序⽆縫集成。OpenGL ES規範沒有定義窗口層; 相 反,託管操做系統必須提供函數來建立一個接受命令的OpenGL ES 渲染上下文和一個幀緩衝區,其中寫入任何繪圖命令的結果。在iOS上使⽤用OpenGL ES須要使⽤iOS類來設置和呈現繪圖表面,並使⽤平臺中立的API來呈現其內容。

EGL的主要功能以下:

  1. 和本地窗⼝系統(native windowing system)通信;
  2. 查詢可用的配置;
  3. 建立OpenGL ES可用的「繪圖表面」(drawing surface);
  4. 同步不一樣類別的API之間的渲染,⽐如在OpenGL ES和OpenVG之間同步,或者在 OpenGL和本地窗口的繪圖命令之間;
  5. 管理「渲染資源」,⽐好比紋理映射(rendering map)。
相關文章
相關標籤/搜索