OpenGL+MetalOpenGL ES图形处理Web前端之路

学习WebGL之深入了解Shader

2017-07-07  本文已影响286人  handyTOOL

本系列所有文章目录

本文将带大家深入了解Shader,下面是运行截图,可以前往我的博客查看代码演示。

前言

上篇文章中我们已经和Shader有了一面之缘,本文将带大家深入Shader的世界,介绍Shader的语言特性,数据类型,内置方法等等。Shader语言和C语言很相似,如果你学过C语言应该可以很快适应Shader的编程风格。本文提供了一个具备Shader基本编程元素的例子,通过Shader控制三角形旋转,并把位置转变成了颜色,读者可以通过修改这个例子更快的熟悉Shader。

代码框架

无论是Vertex Shader还是Fragment Shader,都有基本的代码框架。下面是本文使用的Vertex Shader。

attribute vec4 position;
varying vec4 fragColor;
uniform float elapsedTime;
void main() {
    fragColor = position * 0.5 + 0.5;
    float rotateAngle = elapsedTime * 0.001;
    float x = position.x * cos(rotateAngle) - position.y * sin(rotateAngle);
    float y = position.x * sin(rotateAngle) + position.y * cos(rotateAngle);
    gl_Position = vec4(x, y, 0.0, 1.0);
}

只有Vertex Shader可以声明attribute变量,它用来接受CPU传递过来的顶点数据。除了attribute变量之外,还可以声明uniform变量和varying变量。具体含义还以下面会作详解。main方法是Shader代码执行的入口,这和C语言一模一样。在Vertex Shader中你必须给gl_Position赋值,否则这个Vertex Shader没有任何意义,没有任何顶点会传递给GPU。

下面是本文使用的Fragment Shader。

varying mediump vec4 fragColor;
void main() {
    gl_FragColor = fragColor;
}

Fragment Shader除了attribute变量其他变量都可以拥有,varying变量必须和Vertex Shader中的varying变量类型保持一致,varying变量会从Vertex Shader传递到Fragment Shader中。那么问题来了,Vertex Shader是每个顶点调用一次,而Fragment Shader是每个像素调用一次,那么顶点之间像素的varying变量值是如何计算的呢?答案是GPU会根据要绘制的形状自动插值计算。大家可以观察示例,三角形顶点之间的颜色正是通过各个顶点的fragColor插值计算出来的。

变量类型

Shader有下面几种变量类型:

变量精度

细心的读者可能会发现同样是varying变量,在Fragment Shader中多了一个mediump修饰符。mediump表示的是变量类型的精度。因为Fragment Shader是逐像素执行,所以会尽量控制计算的复杂度。对于不需要过高精度的变量,可以手动指定精度从而提高性能。精度主要分为下面3种。

运算符

Shader可以使用所有C语言的运算符。不过要注意的是二元运算比如加法,乘法等,只能用在两个类型相同的变量上,比如float只能和float相加。因为Shader不会为你进行隐式的类型转换,这样会增加GPU的负担。我们表示float变量时,需要自行增加小数点,比如浮点数5要写成5.0,否则会被认定为整数。下面是能够使用的运算符,读者可以当做参考。


�uniform变量

uniform变量会被所有Shader共享,比如有3个顶点,Vertex Shader会被执行3次,每次访问的uniform变量都是同一个由js代码设定好的值。下面是本文使用的设定uniform elapsedTime的js代码。

  elapsedTimeUniformLoc = gl.getUniformLocation(program, 'elapsedTime');
  gl.uniform1f(elapsedTimeUniformLoc, elapesdTime);

首先获取uniform elapsedTime在Shader中的位置,然后设置它的值。uniform1funiformXXX函数簇里面用来设置一个float类型uniform的方法。通过uniformXXX里的XXX很容易看出来这个方法是设置什么类型的uniform的,下面是常见的几种格式。

varying变量

varying变量是Vertex Shader和Fragment Shader的桥梁,Fragment Shader中的varying变量由Vertex Shader中的varying变量自动插值计算出来。因为Fragment Shader是逐像素执行,某些使用varying变量的效果在Fragment Shader中实现会更加细腻,比如光照效果。

向量的访问

当我们拥有一个vec4变量,我们可以有很多种方法访问它内部的值。

内置方法

有很多内置方法可以使用,如果可以选择内置方法实现算法,避免自己写代码再实现一遍,因为内置的方法能够得到更好的硬件支持。下面是可用的方法表格。



可能很多方法你都不知道有什么用,没关系,后面使用到时我会再做解释。

上面的介绍覆盖了Shader的大部分基础知识,当然还有很多使用细节和不常用的知识没有介绍,这些知识会在后面使用到时再详细介绍,这样可以避免大家刚开始就对Shader产生畏惧感。

上一篇 下一篇

猜你喜欢

热点阅读