zoukankan      html  css  js  c++  java
  • OpenGL3:高级篇 GLSL

    一.简介

    这个世界有两种着色器(Shader):

    •   Vertex shaders – 在你的场景中,每个顶点都需要调用的程序,称为“顶点着色器”。假如你在渲染一个简单的场景:一个长方形,每个角只有一个顶点。于是vertex shader 会被调用四次。它负责执行:诸如灯光、几何变换等等的计算。得出最终的顶点位置后,为下面的片段着色器提供必须的数据。
      •   Fragment shaders – 在你的场景中,大概每个像素都会调用的程序,称为“片段着色器”。在一个简单的场景,也是刚刚说到的长方形。这个长方形所覆盖到的每一个像素,都会调用一次fragment shader。片段着色器的责任是计算灯光,以及更重要的是计算出每个像素的最终颜色。

     

    二.变量

    GLSL的变量命名方式与C语言类似。变量的名称可以使用字母,数字以及下划线,但变量名不能以数字开头,还有变量名不能以gl_作为前缀,这个是GLSL保留的前缀,用于GLSL的内部变量。当然还有一些GLSL保留的名称是不能够作为变量的名称的

    三.基本类型

    除了布尔型,整型,浮点型基本类型外,GLSL还引入了一些在着色器中经常用到的类型作为基本类型。这些基本类型都可以作为结构体内部的类型。如下表:

    类型 描述
    void 跟C语言的void类似,表示空类型。作为函数的返回类型,表示这个函数不返回值。
    bool 布尔类型,可以是true 和false,以及可以产生布尔型的表达式。
    int 整型 代表至少包含16位的有符号的整数。可以是十进制的,十六进制的,八进制的。
    float 浮点型
    bvec2 包含2个布尔成分的向量
    bvec3 包含3个布尔成分的向量
    bvec4 包含4个布尔成分的向量
    ivec2 包含2个整型成分的向量
    ivec3 包含3个整型成分的向量
    ivec4 包含4个整型成分的向量
    mat2 或者 mat2x2 2x2的浮点数矩阵类型
    mat3或者mat3x3 3x3的浮点数矩阵类型
    mat4x4 4x4的浮点矩阵
    mat2x3 2列3行的浮点矩阵(OpenGL的矩阵是列主顺序的)
    mat2x4 2列4行的浮点矩阵
    mat3x2 3列2行的浮点矩阵
    mat3x4 3列4行的浮点矩阵
    mat4x2 4列2行的浮点矩阵
    mat4x3 4列3行的浮点矩阵
    sampler1D 用于内建的纹理函数中引用指定的1D纹理的句柄。只可以作为一致变量或者函数参数使用
    sampler2D 二维纹理句柄
    sampler3D 三维纹理句柄
    samplerCube cube map纹理句柄
    sampler1DShadow 一维深度纹理句柄
    sampler2DShadow 二维深度纹理句柄

    构造函数可以用于初始化包含多个成员的变量,包括数组和结构体。构造函数也可以用在表达式中。调用方式如下

    vec3 myNormal = vec3(1.0, 1.0, 1.0);

    greenTint = myColor + vec3(0.0, 1.0, 0.0);

    ivec4 myColor = ivec4(255);

    vec4 color = vec4(1.0, vec2(0.0, 1.0), 1.0);

    vec3 v = vec3(1.0, 10.0, 1.0);

    vec3 v1 = vec3(v);

    vec2 fv = vec2(5.0, 6.0);

    四.结构体

    结构体可以组合基本类型和数组来形成用户自定义的类型。在定义一个结构体的同时,你可以定义一个结构体实例。或者后面再定义。

    struct surface {float indexOfRefraction;
    
    vec3 color;float turbulence;
    
    } mySurface;
    
    surface secondeSurface;

    五.数组

    GLSL中只可以使用一维的数组。数组的类型可以是一切基本类型或者结构体

    surface mySurfaces[];
    vec4 lightPositions[8];
    vec4 lightPos[] = lightPositions;const int numSurfaces = 5;
    surface myFiveSurfaces[numSurfaces];float[5] values;

    数组的下标从0开始。合理的范围是[0, size - 1]。跟C语言一样。如果数组访问越界了,那行为是未定义的。如果着色器的编译器在编译时知道数组访问越界了,就会提示编译失败。

    vec4 myColor, ambient, diffuse[6], specular[6];

    myColor = ambient + diffuse[4] + specular[4];

     

    六.修饰符

    修饰符 描述
    const 常量值必须在声明是初始化。它是只读的不可修改的。
    attribute 表示只读的顶点数据,只用在顶点着色器中。数据来自当前的顶点状态或者顶点数组。它必须是全局范围声明的,不能再函数内部。一个attribute可以是浮点数类型的标量,向量,或者矩阵。不可以是数组或则结构体
    uniform 一致变量。在着色器执行期间一致变量的值是不变的。与const常量不同的是,这个值在编译时期是未知的是由着色器外部初始化的。一致变量在顶点着色器和片段着色器之间是共享的。它也只能在全局范围进行声明。
    varying 顶点着色器的输出。例如颜色或者纹理坐标,(插值后的数据)作为片段着色器的只读输入数据。必须是全局范围声明的全局变量。可以是浮点数类型的标量,向量,矩阵。不能是数组或者结构体。
    centorid varying 在没有多重采样的情况下,与varying是一样的意思。在多重采样时,centorid varying在光栅化的图形内部进行求值而不是在片段中心的固定位置求值。
    invariant (不变量)用于表示顶点着色器的输出和任何匹配片段着色器的输入,在不同的着色器中计算产生的值必须是一致的。所有的数据流和控制流,写入一个invariant变量的是一致的。编译器为了保证结果是完全一致的,需要放弃那些可能会导致不一致值的潜在的优化。除非必要,不要使用这个修饰符。在多通道渲染中避免z-fighting可能会使用到。
    in 用在函数的参数中,表示这个参数是输入的,在函数中改变这个值,并不会影响对调用的函数产生副作用。(相当于C语言的传值),这个是函数参数默认的修饰符
    out 用在函数的参数中,表示该参数是输出参数,值是会改变的。
    inout 用在函数的参数,表示这个参数即是输入参数也是输出参数。

    七.内置变量

    顶点着色器可用的内置变量如下表

    名称 类型 描述
    gl_Color vec4 输入属性-表示顶点的主颜色
    gl_SecondaryColor vec4 输入属性-表示顶点的辅助颜色
    gl_Normal vec3 输入属性-表示顶点的法线值
    gl_Vertex vec4 输入属性-表示物体空间的顶点位置
    gl_MultiTexCoordn vec4 输入属性-表示顶点的第n个纹理的坐标
    gl_FogCoord float 输入属性-表示顶点的雾坐标
    gl_Position vec4 输出属性-变换后的顶点的位置,用于后面的固定的裁剪等操作。所有的顶点着色器都必须写这个值。
    gl_ClipVertex vec4 输出坐标,用于用户裁剪平面的裁剪
    gl_PointSize float 点的大小
    gl_FrontColor vec4 正面的主颜色的varying输出
    gl_BackColor vec4 背面主颜色的varying输出
    gl_FrontSecondaryColor vec4 正面的辅助颜色的varying输出
    gl_BackSecondaryColor vec4 背面的辅助颜色的varying输出
    gl_TexCoord[] vec4 纹理坐标的数组varying输出
    gl_FogFragCoord float 雾坐标的varying输出

    片段着色器的内置变量如下表

    名称 类型 描述
    gl_Color vec4 包含主颜色的插值只读输入
    gl_SecondaryColor vec4 包含辅助颜色的插值只读输入
    gl_TexCoord[] vec4 包含纹理坐标数组的插值只读输入
    gl_FogFragCoord float 包含雾坐标的插值只读输入
    gl_FragCoord vec4 只读输入,窗口的x,y,z和1/w
    gl_FrontFacing bool 只读输入,如果是窗口正面图元的一部分,则这个值为true
    gl_PointCoord vec2 点精灵的二维空间坐标范围在(0.0, 0.0)到(1.0, 1.0)之间,仅用于点图元和点精灵开启的情况下。
    gl_FragData[] vec4 使用glDrawBuffers输出的数据数组。不能与gl_FragColor结合使用。
    gl_FragColor vec4 输出的颜色用于随后的像素操作
    gl_FragDepth float 输出的深度用于随后的像素操作,如果这个值没有被写,则使用固定功能管线的深度值代替

    八.控制流

    循环

    与C和C++相似,GLSL语言也提供了for, while, do/while的循环方式。使用continue跳入下一次循环,break结束循环

    for (l = 0; l < numLights; l++)
    {if (!lightExists[l])continue;
        color += light[l];
    }while (i < num)
    {
        sum += color[i];
        i++;
    }do{
        color += light[lightNum];
        lightNum--;
    }while (lightNum > 0)


    if/else

    color = unlitColor;if (numLights > 0)
    {
        color = litColor;
    }else{
        color = unlitColor;
    }


    discard

    片段着色器中有一种特殊的控制流成为discard。使用discard会退出片段着色器,不执行后面的片段着色操作。片段也不会写入帧缓冲区

    if (color.a < 0.9)

      discard;

    九.函数

    在每个shader中必须有一个main函数。main函数中的void参数是可选的,但返回值是void时必须的。

    void main(void)
    {
     ...
    }

    GLSL中的函数,必须是在全局范围定义和声明的。不能在函数定义中声明或定义函数。函数必须有返回类型,参数是可选的。参数的修饰符(in, out, inout, const等)是可选的
    结构体和数组也可以作为函数的参数。如果是数组作为函数的参数,则必须制定其大小。在调用传参时,只传数组名就可以了。
    GLSL的函数是支持重载的。函数可以同名但其参数类型或者参数个数不同即可
  • 相关阅读:
    计算机组成原理--中断系统
    操作系统--文件管理2
    操作系统--文件管理1
    操作系统--存储管理4
    操作系统--存储管理3
    操作系统--存储管理2
    操作系统--存储管理1
    有序线性表(存储结构数组)--Java实现
    【Java】之static静态方法与非static静态方法区别
    【Android Studio】之构建项目报错
  • 原文地址:https://www.cnblogs.com/k5bg/p/12552115.html
Copyright © 2011-2022 走看看