什么是着色器?
固定渲染管线: ——标准的几何&光照(T&L)管线,功能是固定的,它控制着世界、视、投影变换及固定光照控制和纹理混合。T&L管线可以被渲染状态控制,矩阵,光照和采制参数。如果有了固定渲染管线,编写程序就比较容易了,因为所有的变换都是由固定渲染管线来完成的,但是缺点就是自由度低。固定渲染管线只能完成一些最基本的操作,如果想要做一些特殊的处理,就比较麻烦了。
可编辑渲染管线:——WebGL中不存在固定渲染管线,坐标变换必须全部由自己来做,这个记述了坐标变换的机制就叫做着色器(Shader),这样可以由程序员控制的机制叫做可编辑渲染管线。而着色器又有 处理几何图形顶点的顶点着色器和处理像素的片段着色器两种类型。由于WebGL中没有固定管线,所以必须准备好顶点着色器和片段着色器。
着色器的处理方法
准备顶点着色器和片元着色器:
着色器的添加有多种方法,着色器是由程序员编写的,而且着色器的代码就是简单的字符串。所以,不管用什么方法,只要把这个着色器字符串传给程序就可以了。
最简单的方法,就是把着色器记录在HTML中。该方法利用HTML的script标签来做的,下面是一个简单的例子,写在HTML中:
<script id="vshader" type="x-shader/x-vertex">
※顶点着色器
</script>
<script id="fshader" type="x-shader/x-fragment">
※片段着色器
</script>
canvas也一样,为了在javascript中可以调用,给script标签加上了id属性。另外,type属性是和javascript不同的,不要误认为是javascript代码。
指定type属性的理由
type属性指定了[x-shader/x-vertex]和[x-shader/x-fragment],这并不是HTML中定义的正式写法。但是一般的浏览器如果遇到不识别的标签的话会无视掉的,浏览器不会认为这是javascript代码的,只会把它当成无意义的字符串,而程序中则可以使用标签里面的内容。
通俗讲,其实就是在script标签中,定义了属性type=“x-shader/x-fragment”,浏览器就不会认为这是一个单独的新的script标签(js文件),而是一段用script首尾标签包含起来的普通字符串文本,在程序代码中可以通过id属性来访问到script里的这段文本,可以优化代码结构。
另外可以直接在javascript内部定义字符串,这样的话,着色器就被定义在了javascript文件中,HTML的代码就变的简单多了,但并不是说,这种做法比前一种做法好。
着色器的三个变量与运行方式:
- Uniforms是所有顶点都具有相同的值的变量。 比如灯光,雾,和阴影贴图就是被储存在uniforms中的数据。uniforms可以通过顶点着色器和片元着色器来访问。
- Attributes是 与每个顶点关联的变量。例如,顶点位置,法线和顶点颜色都是存储在attributes中的数据。attributes 只可以在顶点着色器中访问。
- Varyings是从顶点着色器传递到片元着色器的变量。对于每一个片元,每一个varying的值将是相邻顶点值的平滑插值。
顶点着色器首先运行; 它接收attributes, 计算/操纵每个单独顶点的位置,并将其他数据(varyings)传递给片元着色器。片元(或像素)着色器后运行; 它设置渲染到屏幕的每个单独的“片元”(像素)的颜色。
着色器材质
threejs所谓的材质对象Material本质上就是着色器代码和需要传递的uniform数据(光源、颜色、矩阵…)。
很多时候如果想写一些特效,往往需要编写着色器代码GLSL,如果不熟悉着色器语言,自然需要学习着色器语言语法,如果有着色器语言基础,直接使用Threejs引擎的ShaderMaterial或RawShaderMaterial API编写就可以。相比较在原生WebGL代码中编写着色器要方便的多,在threejs中想着色器传递数据不需要像WebGL中要使用WebGL API来传递,threejs会自动处理。
RawShaderMaterial
和原生WebGL中一样,顶点着色器、片元着色器代码基本没有任何区别,
不过顶点数据和uniform数据可以通过threejs的API快速传递,要比使用WebGL原生的API与着色器变量绑定要方便得多。
ShaderMaterial
ShaderMaterial比RawShaderMaterial更方便些,着色器中的很多变量不用声明,threejs系统会自动帮你设置,比如顶点坐标变量、投影矩阵、视图矩阵…
构造函数(Constructor)
ShaderMaterial( parameters : Object )
parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
常用属性:
attributes:Object
接受如下形式的对象,{ “attribute1”: { value: []} } 指定要传递给顶点着色器代码的attributes;键为attribute修饰变量的名称,值也是对象格式,如{ value: [] },value是固定名称,因为attribute相对于所有顶点,所以应该回传一个数组格式。在threejs中,只有bufferGeometry类型的能使用该属性。
.uniforms : Object
如下形式的对象:
{ “uniform1”: { value: 1.0 }, “uniform2”: { value: 2.0 } } 指定要传递给shader代码的uniforms;键为uniform的名称,值(value)是如下形式:
{ value: 1.0 } 这里 value 是uniform的值。名称必须匹配着色器代码中 uniform 的name,和GLSL代码中的定义一样。 注意,uniforms逐帧被刷新,所以更新uniform值将立即更新GLSL代码中的相应值。
.fragmentShader : String
片元着色器的GLSL代码。这是shader程序的实际代码。在上面的例子中, vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。
.vertexShader : String
顶点着色器的GLSL代码。这是shader程序的实际代码。 在上面的例子中,vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。
示例用法:
var material = new THREE.ShaderMaterial( {
attributes: {
vertexVal: { value: 1.0 }
},
uniforms: {
time: { value: 1.0 },
resolution: { value: new THREE.Vector2() }
},
vertexShader: document.getElementById( 'vertexShader' ).textContent.trim(),
fragmentShader: document.getElementById( 'fragmentShader' ).textContent.trim()
} );