自定义着色器程序
自定义three.js着色器程序需要用到着色器语言GLSL ES和相关的WebGL API,因此在学习本节课之前最好具有一定WebGL基础。
着色器程序至少包含顶点着色器程序和片元着色器程序,对于原生WebGL应用而言,使用着色器语言GLSL编写好顶点、片元着色器程序后, 需要借助WebGL相关API进行编译处理后发送到GPU渲染管线的顶点、片元着色器单元执行,three.js引擎提供了一个接口着色器材质对象ShaderMaterial, 通过ShaderMaterial对象的属性vertexShader和fragmentShader用来接收着色器程序,着色器程序如何编译、如何传递给GPU的处理单元,这些过程已经被three.js引擎封装, three.js通过ShaderMaterial对象接收到着色器程序后会自动化为处理,说到这里大家可以看出three.js引擎的好处与作用,对WebGL API和着色器语言进行封装,一方面是降低Web3D的学习成本, 另一方面是对原生的WebGL程序进行封装,工程师更多的精力放在应用开发上。
下面的代码完整的展示了如何利用ShaderMaterial对象加载着色器程序,如何把顶点相关的数据传输到顶点着色器程序中。
<body> <!--顶点着色器程序--> <script type="x-shader/x-vertex" id="vertexshader"> void main() { gl_PointSize = 20.0; gl_Position = vec4( position, 1.0 ); } </script> <!--片元着色器程序--> <script type="x-shader/x-fragment" id="fragmentshader"> void main() { gl_FragColor = vec4(1.0,0.0,0.0,1.0); } </script> <script> ... ... /** * 创建模型对象 */ //类型数组创建顶点数据 var vertices = new Float32Array([ 0.5, 0.5, 0.5,//顶点0 -0.5, 0.5, 0.5,//顶点1 -0.5, -0.5, 0.5,//顶点2 0.5, -0.5, 0.5,//顶点3 ]); //类型数组格式顶点数据转为BufferAttribute对象 var verticesPosition = new THREE.BufferAttribute( vertices, 3 ); var geometry = new THREE.BufferGeometry();//缓冲几何对象 //顶点数据关联着色器程序 geometry.addAttribute('position',verticesPosition); var material=new THREE.ShaderMaterial({ //加载顶点着色器程序 vertexShader: document.getElementById( 'vertexshader' ).textContent, //加载片元着色器程序 fragmentShader: document.getElementById( 'fragmentshader' ).textContent, });//着色器材质对象 var points=new THREE.Points(geometry,material);//模型对象 scene.add(points);//模型添加到场景中 ... ... </script> </body>
加载着色器程序
ShaderMaterial对象的基类是材质对象MAterial,ShaderMaterial对象除了具有材质对象的属性和方法以外,与其它材质对象不同的是ShaderMaterial对象还具有处理着色器程序的相关属性或方法, 或者换句话说其它的各种材质对象对着色器程序进行了封装,three.js引擎会把材质对象的颜色属性、纹理贴图属性转化为着色器程序中的代码。
vertexShader、fragmentShader是着色器材质对象ShaderMaterial属性,属性值是字符串格式着色器程序,着色器程序可以编写在任何html标签中,通过getElementById获取标签表示的元素对象, textContent属性返回的是标签里面的着色器程序,数据类型是字符串。下面代码是以构造函数THREE.ShaderMaterial参数的形式把顶点和片元着色器程序分别赋值给vertexShader属性、fragmentShader属性。
var material=new THREE.ShaderMaterial({ //加载顶点着色器程序 vertexShader: document.getElementById( 'vertexshader' ).textContent, //加载片元着色器程序 fragmentShader: document.getElementById( 'fragmentshader' ).textContent, });//着色器材质对象
传入着色器顶点相关数据
所谓的三维模型效果本质上都是通过顶点数据渲染出来,通过原生WebGL编写三维应用,需要在着色器通过attribute等关键字声明一个变量, 然后通过Javascript可以控制的WebGL API把顶点数据传递给着色器,关联到该变量。three.js对这些代码进行了封装,对于工程师来说更加友好易用。
BufferGeometry
缓冲几何体对象BufferGeometry和几何体对象Geometry功能基本相似,都可使用来创建几何体,只是处理数据的方式有些差异。 比如Geometry对象具有顶点位置属性vertices、顶点颜色属性colors,而BufferGeometry对象不具有这些属性, BufferGeometry对象的顶点位置、颜色等数据需要通过方法.addAttribute()添加。
BufferAttribute
通过类型数组构造函数Float32Array创建一系列的顶点数据,这些数据可以作为顶点位置、颜色、法向量顶数据,代码中是作为位置使用, THREE.BufferAttribute( vertices, 3 )的含义表示类型数组的元素三个是一组,表示一个顶点的位置,相当于Vector3向量。 对象BufferAttribute可以作为BufferGeometry对象addAttribute方法的参数,实现顶点位置数据与顶点着色器程序中的位置变量块关联。
addAttribute
geometry.addAttribute('position',verticesPosition);代码的作用相当于在顶点着色器中创建代码“attribute vec4 position”, 然后把包含顶点数据的BufferAttribute对象与着色器程序中的position变量进行关联。直接使用WebGL API编写程序, 需要在着色器程序中编写代码“attribute vec4 position”,有了three.js引擎自然不要,在执行方法.addAttribute('position')的时候, 就相当于在着色器程序中添加了该语句。
//类型数组创建顶点数据 var vertices = new Float32Array([ 0.5, 0.5, 0.5,//顶点0 -0.5, 0.5, 0.5,//顶点1 -0.5, -0.5, 0.5,//顶点2 0.5, -0.5, 0.5,//顶点3 ]); //类型数组格式顶点数据转为BufferAttribute对象 var verticesPosition = new THREE.BufferAttribute( vertices, 3 ); var geometry = new THREE.BufferGeometry();//缓冲几何对象 //顶点数据关联着色器程序 geometry.addAttribute('position',verticesPosition);