附录(四)绘制纹理

绘制纹理

精度限定符用于指定任何基于浮点或者整数变量的精度,关键字有高、中、低。

highp vec4        position;
varying lowp vec4 color;
mediump float     specularExp;

精度限定符,还有默认精度的概念,如果没有设置,就设置默认的,默认精度限定符使用以下语法在顶点或片段着色器的顶部指定:

precision highp float;
precision mediump int;

为浮点指定的精度将用作基于浮点值的所有变量的默认精度。同样,为int指定的精度将用作所有基于整数的变量的默认精度。在顶点着色器中,如果没有指定默认精度,则int和float的默认精度都很高。

精度选择:

  • 对于通常在顶点着色器中执行的操作,最可能需要的精度限定符是高精度限定符。
  • 用矩阵变换位置,变换法线和纹理坐标,或者生成纹理坐标的操作需要高精度地完成。
  • 颜色计算和光照方程很可能以中等精度完成。

这将取决于正在执行的颜色计算的种类以及正在执行的操作所需的范围和精度。我们相信highp很可能是顶点着色器中大多数操作使用的默认精度,因此在下面的示例中使用highp作为默认精度限定符。

Open gl es的着色器限制

这些限制应该会有所帮助开发人员编写了一个便携式顶点着色器,可以在大多数OpenGL ES 2.0实现上编译和运行。

顶点着色器的长度

指令计数超过顶点 着色器允许的最大指令,顶点着色器源将无法编译。所以出现了一些限制,来保证可以正常运行。

临时变量

临时变量是指在函数内部声明的变量或存储中间值的变量。
因为OpenGL ES着色语言是高级语言,所以没有办法指定所有OpenGL ES 2.0实现必须支持的最小临时变量数。
因此,顶点着色器可能会遇到这个问题,并且不会在所有ES 2.0实现上编译。

流量控制

OpenGL ES 2.0要求实现支持顶点着色器中的循环,而不要求它们必须展开。例如,您可以有一个For循环,循环索引从0到1023。这通常不会被着色器编译器展开,因为展开的着色器的代码大小对于大多数ES 2.0实现来说可能太大。以下限制适用于顶点着色器中使用的循环:
【循环可以减小程序的大小】

  • 在for循环中只能使用一个循环索引。
  • 循环索引必须初始化为常数整数表达式。
  • for循环中声明的条件表达式必须是下列之一:
    loop_indx < constant_expression
    loop_indx <= constant_expression
    loop_indx > constant_expression
    loop_indx >= constant_expression
    loop_indx != constant_expression
    loop_indx == constant_expression
    
  • 只能使用以下表达式之一在for循环语句中修改循环索引:
    loop_index--
    loop_index++
    loop_index -= constant_expression
    loop_index += constant_expression
    
  • 循环索引可以作为只读参数传递给for循环中的函数(即循环索引可以与使用in参数限定符声明的参数一起使用)。
Examples of valid for loop constructs are shown here.
const int numLights = 4;
int i, j;
for (i=0; i<numLights; i++)
{
   …
}
for (j=4; j>0; j--)
{
   …
   foo(j);  // argument to function foo that takes j
            // is declared with the in qualifier.
}
Examples of invalid for loop constructs are shown here.
uniform int numLights;
int i;
for (i=0; i<numLights; i++)  // conditional expression is 
                             // not constant
{
   …
}
for (i=0; i<8; i++)
{
   i = foo();   // return value of foo() cannot be 
                // assigned to loop index i
}
for (j=4; j>0;)
{
   …
   j--;   // loop index j cannot be modified 
          // inside for loop
}

虽然OpenGL ES 2.0着色语言规范指定了while和do-while循环,但这并不是必需的,因此可能不被所有OpenGL ES 2.0实现所支持。

条件语句

完全支持以下条件语句,没有任何限制。

if(bool_expression)
{
   …
}
if(bool_expression)
{
   …
}
else
{
   …
}

图形处理器通常并行执行具有多个顶点的顶点着色器或具有多个片段的片段着色器。
并行执行的顶点或片段的数量将取决于GPU的性能目标。
if和if-else条件语句中的bool_expression对于并行执行的顶点或片段可以有不同的值。
由于GPU并行执行的顶点或片段数量减少,这可能会影响性能。
我们建议,为了获得最佳性能,条件语句应该与bool_expression值一起使用,这些值对于并行执行的顶点或片段是相同的。如果使用统一的表达式,就会出现这种情况.

数组索引

完全支持制服(不包括采样器)的数组索引。数组索引可以是常量、统一值或计算值。采样器只能使用常数积分表达式进行索引。常数积分表达式是文字值(如4),常数整数变量(如const int sampler _ indx = 3;),或者常量表达式(例如3 + sampler_indx)。
属性矩阵和向量可以使用常数积分表达式进行索引。不强制使用非常数积分表达式对属性矩阵和向量进行索引。然而,这是一个非常有用的特性。下面的代码显示了一个执行顶点蒙皮的顶点着色器。a_matrixweights是一个存储矩阵权重的顶点属性,最多可存储四个矩阵。

attribute vec4 a_matrixweights; // matrix weights 
attribute vec4 a_matrixindices;  // matrix palette indices
int i;
for (i=0; i<=3; i++)
{
   float   m_wt = a_matrixweights[i];
   int     m_indx = int(a_matrixindices[i]) * 3;
   …
}

以粗体突出显示的代码a_matrixweights[i]和a_matrixindices[i]不需要支持,因此可能无法编译。

注意:索引常数矩阵和向量、变量和变量或变量和变量数组的规则与已经描述的属性的规则相同

计算顶点着色器中使用的制服数量

gl _ MaxVertexUniformVectors描述顶点着色器中可以使用的最大制服数量。任何兼容的OpenGL ES 2.0实现都必须支持的gl _ MaxVertexUniformVectors的最小值是128个vec4条目。统一存储用于存储以下变量:

  • 用统一限定符声明的变量。
  • 常量变量。
  • • Literal values.
  • 特定于实现的常数

顶点着色器中使用的统一变量的数量以及用常量限定符、文字值和特定于实现的常量声明的变量必须符合第5章中描述的打包规则。如果这些不适合,那么顶点着色器将无法编译。开发人员可以应用打包规则,并确定存储统一变量、常量变量和文字值所需的统一存储量。无法确定特定于实现的常量的数量,因为该值不仅会因实现而异,还会根据顶点着色器使用的内置着色语言函数而变化。通常,当使用内置超越函数时,需要特定于实现的常数。

就文字值而言,OpenGL ES 2.0着色语言规范声明不假设常数传播。这意味着同一文字值的多个实例将被多次计数。可以理解,在顶点着色器中使用文字值(如0.0或1.0)更容易,但我们建议尽可能避免这种情况。应该声明适当的常量变量,而不是使用文字值。这避免了多次使用相同的文字值计数,如果顶点统一存储要求超过实现支持的范围,这可能导致顶点着色器无法编译。

考虑下面的例子,它描述了顶点着色器代码的一个片段,该代码为每个顶点变换两个纹理坐标:

#define NUM_TEXTURES   2
uniform mat4  tex_matrix[NUM_TEXTURES];        // texture matrices
uniform bool  enable_tex[NUM_TEXTURES];        // texture enables
uniform bool  enable_tex_matrix[NUM_TEXTURES]; // texture matrix 
                                               // enables
attribute vec4  a_texcoord0;  // available if enable_tex[0] is true
attribute vec4  a_texcoord1;  // available if enable_tex[1] is true
varying vec4    v_texcoord[NUM_TEXTURES];
v_texcoord[0] = vec4(0.0, 0.0, 0.0, 1.0);
// is texture 0 enabled
if (enable_tex[0])
{
   // is texture matrix 0 enabled
   if(enable_tex_matrix[0])
      v_texcoord[0] = tex_matrix[0] * a_texcoord0;
   else
      v_texcoord[0] = a_texcoord0;
}
v_texcoord[1] = vec4(0.0, 0.0, 0.0, 1.0);
// is texture 1 enabled
if (enable_tex[1])
{
   // is texture matrix 1 enabled
   if(enable_tex_matrix[1])
      v_texcoord[1] = tex_matrix[1] * a_texcoord1;
   else
      v_texcoord[1] = a_texcoord1;
}

刚才描述的代码可能导致对文字值0、1、0.0、1.0的每个引用都按照统一存储进行计数。为了保证这些文字值在统一存储中只计数一次,顶点着色器代码段应该编写如下

#define NUM_TEXTURES   2
const int  c_zero = 0;
const int  c_one  = 1;
uniform mat4  tex_matrix[NUM_TEXTURES];        // texture matrices
uniform bool  enable_tex[NUM_TEXTURES];        // texture enables
uniform bool  enable_tex_matrix[NUM_TEXTURES]; // texture matrix 
                                               // enables   
attribute vec4  a_texcoord0;  // available if enable_tex[0] is true
attribute vec4  a_texcoord1;  // available if enable_tex[1] is true
varying vec4    v_texcoord[NUM_TEXTURES];
v_texcoord[c_zero] = vec4(float(c_zero), float(c_zero), 
                          float(c_zero), float(c_one));
// is texture 0 enabled
if(enable_tex[c_zero])
{
   // is texture matrix 0 enabled
   if(enable_tex_matrix[c_zero])
      v_texcoord[c_zero] = tex_matrix[c_zero] * a_texcoord0;
   else
      v_texcoord[c_zero] = a_texcoord0;
}
v_texcoord[c_one] = vec4(float(c_zero), float(c_zero), 
                         float(c_zero), float(c_one));
// is texture 1 enabled
if(enable_tex[c_one])
{
   // is texture matrix 1 enabled
   if(enable_tex_matrix[c_one])
      v_texcoord[c_one] = tex_matrix[c_one] * a_texcoord1;
   else
      v_texcoord[c_one] = a_texcoord1;
}

希望这一节有助于很好地理解OpenGL ES 2.0着色语言的局限性,以及如何编写应该在大多数OpenGL ES 2.0实现上编译和运行的顶点着色器。

一个简单的顶点着色器

顶点着色器将位置及其相关的颜色数据作为输入或属性,通过4 × 4矩阵转换位置,并输出转换后的位置和颜色。

Example 8-1 A Simple Vertex Shader 
// uniforms used by the vertex shader
uniform mat4    u_mvp_matrix; // matrix to convert P from 
                              // model space to clip space.
// attributes input to the vertex shader
attribute vec4  a_position;   // input position value
attribute vec4  a_color;      // input vertex color
// varying variables – input to the fragment shader
varying vec4    v_color;      // output vertex color
void
main()
{
   v_color = a_color;
   gl_Position = u_mvp_matrix * a_position;
}

然后,设置和光栅化阶段使用变换的顶点位置和图元类型将图元光栅化成片段。对于每个片段,插值的v_color将被计算并作为输入传递给片段着色器。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容