当前位置: 首页 > 编程笔记 >

OpenGL ES着色器使用详解(二)

董永宁
2023-03-14
本文向大家介绍OpenGL ES着色器使用详解(二),包括了OpenGL ES着色器使用详解(二)的使用技巧和注意事项,需要的朋友参考一下

本文介绍了OpenGL ES着色器使用的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

1.着色器语言

着色器语言是一种高级图形编程语言,和C/C++语言很类似,但存在很大差别,比如,不支持double,byte

,short,不支持unin,enum,unsigned以及位运算等,但其加入了很多原生的数据类型,如向量,矩阵等。

数据类型可分为标量、向量、矩阵、采样器、结构体、数组等

向量

向量传递参数,如果只提供一个标量,这个值用于设置所有向量的值;如果输入是多个标量或者是矢量,从左到右设置矢量变量的参数,如果多个矢量作为参数,那么至少要有和变量一样多的分量

vec4 myVec4 = vec4(1.0); // myVec4 = {1.0, 1.0, 1.0, 1.0}
vec3 myVec3 = vec3(1.0, 0.0, 0.5); // myVec3 = {1.0, 0.0, 0.5}
vec3 temp = vec3(myVec3); // temp = myVec3
vec2 myVec2 = vec2(myVec3); // myVec2 = {myVec3.x, myVec3.y}
myVec4 = vec4(myVec2, temp); // myVec4 = {myVec2.x, myVec2.y, temp.x, temp.y}

矩阵

矩阵操作在OpenGL ES中的使用非常广泛,涉及到图形的平移缩放旋转等操作都是由矩阵来实现的.

向矩阵传递参数:

  • 提供的是一个标量,那么标量复制给与矩阵的主对角线
  • 一个矩阵能被多个向量赋值,如,mat2可以用两个vec2赋值
  • 一个的矩阵被多个标量赋值,按列赋值

向量和矩阵的分量

向量一般用来存储位置、颜色纹理坐标等包含不止一个的量,访问向量中某个分量的方法为:<向量名.分量名>

  • 将向量看做颜色对待,四个分量为r、g、b、a,分别代表红、绿、蓝、透明度
  • 将向量看做位置对待,四个分量为x、y、z、w,分别代表x轴、y轴、z轴、w
  • 将向量看做纹理坐标对待,四个分量为s、t、p、q,分别代表纹理坐标的不同分量

这三种不同的命名方案不能混合使用,除此之外还可以将向量当做数组看待,用下表来访问。

vec3 myVec3 = vec3(0.0, 1.0, 2.0); // myVec3 = {0.0, 1.0, 2.0}
float x = myVec3.x;
vec3 temp;
temp = myVec3.xyz; // temp = {0.0, 1.0, 2.0}
temp = myVec3.xxx; // temp = {0.0, 0.0, 0.0}
temp = myVec3.zyx; // temp = {2.0, 1.0, 0.0}
vec4 temp2 = myVec3.xxyz; // temp2 = {0.0, 0.0, 1.0, 2.0}

对矩阵的访问当成一个二维数组即可,矩阵可以认为是由多个向量组成的

mat4 myMat4 = mat4(1.0); // Initialize diagonal to 1.0 (identity)
vec4 col0 = myMat4[0]; // Get col0 vector out of the matrix
float m1_1 = myMat4[1][1]; // Get element at [1][1] in matrix
float m2_2 = myMat4[2].z; // Get element at [2][2] in matrix

采样器

采样器专门用于进行纹理采样的相关操作,一般情况下一个采样器变量代表了衣服纹理切贴图。

sampler2D/sampler3D/samplerCube

采样器变量不是在着色器中初始化的,一般是由主程序传递进来的。

数组

声明数组时指定数组大小,反之,访问数组时的下表必须是编译时常量,这样的话,编译器会自动创建适当大小的数组

类型转换

着色器语言没有自动提升的功能,也不能强制转换,只能用构造器完成类型转换,每中内建变量类型都有一组相关的构造器。

float f = 1; // error
int i = 0.0; // error
float f = 1.0 // ok
bool b = bool(f) // ok,非0当做true
float f = float(b) // ok,bool转为浮点数,true转为1.0,false转为0.0
int i = 0; //ok
bool b = bool(i) // ok,int转为bool

变量限定符

const:常量,编译时常量,其值不可变,可以提高运行效率

attribute:属性变量,仅仅用在顶点着色器,用该限定符修饰的变量用来接受从宿主程序传进渲染管线的变量。一般用于每个顶点都不相同的量,比如顶点位置,颜色,法线等

uniform:统一变量,一般用于对同一组顶点组成的一个物体所有顶点都相同的量,比如光源位置,转换矩阵,颜色,光照等

varying:变量被用来存储顶点着色器的输出和片元着色器的输入,每个顶点着色器把输出数据转变成一个或更多片元着色器的输入,在光栅化阶段就会插值生成一系列变量

varying变量的原理

在线段上进行混合插值

在三角形上进行混合插值

获取着色器变量

获取attribute类型变量。对于attribute限定符修饰的变量的值是由宿主程序传入渲染管线的,使用glGetAttribLocation函数获得着色器中某属性变量的引用

public static native int glGetAttribLocation(
  int program, // 创建的程序对象
  String name // 着色器中变量名
);

然后使用glVertexAttribPointer函数将数据传递到glGetAttribLocation返回的着色器变量引用所代表的变量中去

public static void glVertexAttribPointer(
  int indx, // 属性变量的引用
  int size, //每个顶点的数据个数,比如x、y、z就是3
  int type, // 数据类型,如GLES20.GL_FLOAT
  boolean normalized, // 是否规格化,只有使用整形数据才有意义
  int stride, // 跨距,一个数组存储多个属性才有意义,指的是两个点之间有多少个字节
  java.nio.Buffer ptr // 存放顶点数据缓冲
 )

获取uniform类型的变量。使用glGetUniformLocation函数获得着色器中某统一变量的引用

public static native int glGetUniformLocation(
  int program,
  String name
 );

然后使用glUniformXXX函数将数据传递到着色器中,比如glUniformMatrix4fv函数

public static native void glUniformMatrix4fv(
  int location, // 统一变量的引用
  int count, // 指明要更改的元素个数。如果变量不是数组,这个值应该设为1
  boolean transpose, // 是否要转置矩阵,并将它作为uniform变量的值。必须为false
  float[] value, // 传递给统一变量的数组元素
  int offset // 偏移,取0
 );

glUniformNf/glUniformNfv:将N个浮点数传入管线

glUniformNi/glUniformNiv:将N个整数传入管线

glUniformMatrixNfv:将N个整数传入管线,将N*N矩阵传入管线

内建变量

内建变量不需要声明即可使用,内建变量分为两种,输入与输出变量。

输入变量负责将渲染管线中固定功能部分生成的信息传递进着色器以供程序员使用,输出变量负责将着色器产生的信息传递给渲染管线中的固定功能。

顶点着色器

顶点着色器的内建变量主要是输出变量,即将着色器产生的值传递给渲染管线,因此在顶点着色器中要对这些内建变量赋值,包括gl_Position、gl_PointSize等。

  • gl_Position:在顶点着色器对获取到的定点原始数据进行平移缩放旋转等变换后,生成新的位置,新的顶点位置通过该变量传递给渲染管线的后续操作。
  • gl_PointSize:顶点着色器中可以计算一个点的大小,单位为像素,默认值为1,一般对点绘制方式有意义。

片元着色器

片元着色器中的内建输入变量,gl_FragCoord、gl_FrontFacing,并且还是只读的,是由渲染管线片元着色器之前阶段生成的。

  • gl_FragCoord:vec4类型数据,含有当前片元相对窗口位置的坐标。
  • gl_FrontFacing:bool类型的内建输入变量,该值表明当前正在处理的片元是否属于在光栅化阶段生成此片元对应图元的正面。点、线段没有正反面之分的图元。其生成的偏远都会被默认为是正面,三角形图元其正面取决于程序中队卷绕的设置及图元中顶点的具体卷绕情况。

片元着色器中的内建输出变量gl_FragColor、gl_FragData,在片元着色器中给这两个内建变量写入值。

  • gl_FragColo:vec4变量,用来传入由片元着色器计算出来的片元颜色值。

函数

和其他语言一样,差别在于参数可以指定用途,具体的有in,out,inout修饰符表明该参数是入参还是出参。

片元着色器浮点变量精度

片元着色器中的浮点类型数据必须制定精度,不指定精度可能引起编译错误。有三种精度类型:lowp、mediump、highp,一般使用mediump类型即可。如果在开发中同一个片元着色器中浮点类型变凉都是同一种精度类型,可以整个指定着色器中浮点类型默认精度。

precision <精度> <类型>
precision mediump float;

2.着色器程序

需要创建两个对象才能用着色器进行渲染:着色器对象和程序对象。

着色器源代码被编译成一个目标形式(类似obj文件),编译之后,着色器对象可以连接到一个程序对象,程序对象可以连接多个着色器对象。

获得连接后的着色器对象的过程:

  1. 创建一个顶点着色器和一个片元着色器:
  2. 将源代码连接到每个着色器对象
  3. 编译着色器对象
  4. 创建一个程序对象
  5. 将编译后的着色器对象连接到程序对象
  6. 连接程序对象

如果没有出错,就可以在后面使用这个程序了,如从程序获取某个着色器变量,接下来为其传递值等操作。

创建着色器对象

public static native int glCreateShader(
 int type // 着色器类型,GLES20.GL_VERTEX_SHADER或GLES20.GL_FRAGMENT_SHADER
);

连接源代码到着色器对象

public static native void glShaderSource(
  int shader,
  String string // 着色器源码
 );

编译着色器对象

public static native void glCompileShader(
  int shader
 );

创建程序对象

mProgram = GLES20.glCreateProgram();

将编译后的着色器对象连接到程序对象

public static native void glAttachShader(
  int program,
  int shader
 );

连接程序对象

public static native void glLinkProgram(
  int program
 );

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 在Hello Triangle教程中提到,着色器(Shader)是运行在GPU上的小程序。这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器也是一种非常独立的程序,因为它们之间不能相互通信;它们之间唯一的沟通只有通过输入和输出。 前面的教程里我们简要地触及了一点着色器的皮毛,并了解了如何恰当地使用它们。现在我们会用一种更加广泛的形式详细解释

  • WebGL的着色器代码分为顶点着色器代码和片元着色器代码两部分,顶点着色器代码会在GPU的顶点着色器单元执行,片元着色器代码会在GPU的片元着色器单元执行,在WebGL渲染管线流程中,或者说GPU的渲染流程中,顶点着色器代码先执行处理顶点,得到一系列片元,然后再执行片元着色器代码处理片元。 main()函数 顶点着色器和片元着色器代码都有一个唯一的主函数main(),attribute、varyi

  • 标准着色器 Unity 标准着色器是一个内置着色器,具有非常全面的功能。它可以用于渲染『真实世界』的对象,例如,石头、木材、玻璃、塑料和金属,并支持各种各样的着色器类型和组合。通过使用或不使用材质编辑器中的各种纹理插槽和参数,可以很容易地启动或禁用其功能。 标准着色器还包括一个称为 物理着色器(Physically Based Shading,PBS) 的高级光照模型。物理着色器以模拟真实世界的方

  • 我正在用OpenGL(PyOpenGL和Python)显示几何图形(文件格式:.stl)。几何数据具有形式,由三角形组合而成。 我保存到 VBO 数据;顶点、法线和颜色。由于法线仅每 3 个顶点(三角形)定义,并且我为每个顶点定义颜色矢量,因此 VBO 中的数据具有以下形式: 大写:;首先我保存所有顶点,然后我“附加”(使用)所有法线(法线数比顶点数和顶点颜色少3倍),然后我附加每个顶点的颜色向量

  • 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点。几何着色器可以在顶点发送到下一着色器阶段之前对它们随意变换。然而,几何着色器最有趣的地方在于,它能够将(这一组)顶点变换为完全不同的图元,并且还能生成比原来更多的顶点。 废话不多说,我们直接先看一个几何着色器的例子: #version 330 core layout

  • 方法 构造方法 BK.Render.Material(vs,fs) 参数 类型 名称 备注 vs string 顶点描述文件 fs string 段描述文件 例子: var material = new BK.Render.Material( "GameRes://script/demo/render/shader/light2D.vs", "GameRes://script/demo/rend