着色器语言(下)

416

函数参数的限定符:

函数的参数默认是以拷贝的形式传递的,也就是值传递,任何传递给函数参数的变量,其值都会被复制一份,然后再交给函数内部进行处理。所以,可以为参数添加限定符来达到传递引用的目的。

限定符说明
none:default默认使用in限定符
in/centroid in复制到函数中在函数中可读可写。默认限定符,最终真正传入函数形参的其实是实参的一份拷贝,在函数中,修改in修饰的形参不会影响到实参变量本身。centroid in 变量于插值类型有关
out/centroid out返回时从函数中复制出来。他的作用是想函数外部传递性质,out模式下传递进来的参数是write-only(可写不可读)的,在函数中,修改out修饰的形参回影响到实参本身。centroid out 变量于插值类型有关
ninout复制到函数中斌返回时复制出来。可读可写,在函数中,修改inout修饰的形参会影响到实参本身

GLSL的函数:

glsl允许在程序的最外部声明函数。函数不能嵌套,不能递归调用,且必须声明返回值类型(无返回值时声明为void).

    vec4 getPosition(){
            vec4 v4=vec4(0.0,0.0,0.0,1.0);
            return v4;
    }
    void doubleSize(inout float size){
            size=size*2.0;
    }
    void main(){
        float psize= 10.0;
        doubleSize(psize);
        gl_Position = getPosition();
        gl_PointSize = psize;
    }

构造函数:

glsl中变量可以在声明的时候初始化,也可以先声明再在需要时赋值。而聚合类型对象,如(向量,举证,数组,结构),需要使用其构造函数来进行初始化。

    //一般类型
    float pSize=10.0;
    float pSize1;
    pSize1=10.0;
    //复合类型,如向量
    vec4 color=vec4(0.0,1.0,0.0,1.0);
    vec4 color1;
    color1=vec4(0.0,1.0,0.0,1.0);
    //结构
    struct light{
            float intensity;
            vec3 position;
    }
    light lightVar=light(3.0,vec3(1.0,2.0,3.0));
    //数组
    const float c[3]=float[3](5.0,7.2,1.1);

精度限定:

glsl在进行光栅化着色的时候,会产生大量的浮点数运算,这些运算可能会超出当前设备的承受能力,所以glsl提供了三种浮点数精度。在变量前面加上highp 、mediump 、lowp,即可对该变量的精度声明。

  • highp (-2的16次方, 2的16次方); 
  • mediump (-2的10次方, 2的10次方); 
  • lowp (-2的8次方, 2的8次方);
    lowp float color;
    varying mediump vec2 Coord;
    lowp ivec2 foo(lowp mat3);
    highp mat4 m

确定精度:

变量的精度首先都是由精度限定符确定的,如果没有精度限定符,则要寻找右侧表达式中已经确定精度的变量,一旦找到,那么整个表达式都将在该精度下运行。如果找到多个,则选择精度较高的,如果未找到,则会使用默认或者更大的精度类型。

    uniform highp float h1;
    highp float h2=2.3*4.7;//运算过程和结果都会使用高精度
    mediump float m;
    m=3.7*h1*h2;//运算过程是高精度
    h2=m*h1;//运算过程是高精度
    h2=m+m//运算过程和结果都是中精度
    //形参p是高精度,传入的3.3是高精度
    void f(highp float p);
    f(3.3);

invariant

关键: 由于shader在编译时会进行一些内部优化,可能会导致同样的运算在不同shader里结果不一定精确相等,这会引起一些问题,尤其是vertex shader向fragment shader传值的时候。所以需要使用invariant关键字来显示要求计算结果必须精确一直。当然也可以使用#pragma STDGL invariant(all)来命令所有输出变量必须精确一致,但这样会限制编译器优化程度,降低性能。

#pragma STDGL invariant(all) //所有输出变量为 
invariant invariant varying texCoord; //varying在传递数据的时候声明为invariant

限定符的顺序:
当需要用到多个限定符的是要遵循以下顺序:
1.在一般变量中: invariant > storage > precision
2.在参数中: storage > parameter > precision

预编译指令

以#开头的是预编译指令,常用的有: #define 、 #undef 、 #if 、 #ifdef 、#ifndef 、#else、#elif、 #endif 、#error 、#pragma 、#extension、#version 、#line 比如#version 100,表示规定当前shader使用GLSL ES 1.00标准进行编译,如果使用该指令,则必须出现在程序最开始的位置。

内置的宏: LINE:当前源码中的行号。 VERSION:一个整数,指示当前的GLSL版本。 GL_ES:如果当前是在OpenGL ES环境中运行则GL_ES被设置成1,一般用来检查当前环境是不是OpenGL ES. GL_FRAGMENT_PRECISION_HIGH:如果当前系统glsl的片元着色器支持高浮点精度,则设置为1,一般用来检查着色器的精度。

实例: 1.如何通过判断系统环境,来选择合适的精度:

    #ifdef GL_ES //
    #ifdef GL_FRAGMENT_PRECISION_HIGH
    precision highp float;
    #else
    precision mediump float;
    #endif
    #endif

2.自定义宏:

    #define NUM 100 
    #if NUM==100 
    #endif

内置的特殊变量

GLSL程序使用一些特殊的内置变量与硬件进行沟通。大致分为两种,一种是input类型,负责向硬件(渲染管线)发送数据,另一种是output类型,负责向程序回传数据,以便编程需要。
在vertex shader中:
output类型的内置变量:

变量说明单位
highp vec4 gl_Positiongl_Position放置顶点坐标信息vec4
mediump float gl_PointSizegl_PointSize需要绘制点的大小(只在gl.POINTS模式下有效)float

在fragment shader中:
input类型:

变量说明单位
mediump vec4 gl_FragCoord片元在framebuffer画面的相对位置vec4
bool gl_FrontFaceing标志当前图元是不是正面图元的一部分bool
mediump vec2 gl_PointCoord经过插值计算后的纹理坐标,点的范围是0.0~1.0vec2

output类型:

变量说明单位
mediump vec4 gl_FragColor设置当前片点的颜色vec4 RGBA color
mediump vec4 gl_FragData[n]设置当前片点的颜色,使用glDrawBuffers数据数组vec4 RGBA color