WebGL入门与进阶2

栏目: 编程工具 · 发布时间: 7年前

内容简介:程序创建完之后,我们需要需要对着色器进行动态控制才能达到我们所需要的功能。(如不知道怎么创建WebGL,可参考上篇文章)。首先让我来介绍2个变量,我们需要借助这2个变量搭建的桥梁才能使JavaScript与GLSL ES之间进行沟通。先在顶点着色器代码中,将对应的vec4的固定值变成变量。

程序创建完之后,我们需要需要对着色器进行动态控制才能达到我们所需要的功能。(如不知道怎么创建WebGL,可参考上篇文章)。

首先让我来介绍2个变量,我们需要借助这2个变量搭建的桥梁才能使JavaScript与GLSL ES之间进行沟通。

  • attribute: 用于顶点点着色器( Vertex Shader )传值时使用。
  • uniform:可用于顶点着色器( Vertex Shader )与片元着色器( Fragment Shader )使用。

将顶点动态化

先在顶点着色器代码中,将对应的vec4的固定值变成变量。

var VSHADER_SOURCE =
 'attribute vec4 a_Position;\n' +
 'void main() {\n' +
   '  gl_Position = a_Position;\n' +
   '  gl_PointSize = 10.0;\n' +
 '}\n';

位置参数使用了 attribute 变量来承载。这样WebGL对象就可以获取到对应的存储位置,就可以去动态改变GLSL变量了。

使用WebGL来获取对应参数的存储地址。

//返回对应的地址信息
var aPosition = gl.getAttribLocation(gl.program, 'a_Position');
//判断地址是否获取成功
if(aPosition < 0) {
   console.log('没有获取到对应position');
}

然后给变量赋值。

gl.vertexAttrib3f(aPosition, 1.0, 1.0, 0.0);
//或者使用Float32Array来传参
var p = new Float32Array([1.0, 1.0, 1.0]);
gl.vertexAttrib3fv(aPosition, p);

注意:vertexAttrib3fv这个函数是典型的GLSL语法命名规范,vertexAttrib函数功能:

3:对应需要传3个参数,或者是几维向量。

f:表示参数是float类型。

v:表示传如的为一个vector变量。

也就是说对应设置顶点着色器的函数有一下几种功能:

void gl.vertexAttrib1f(index, v0);
void gl.vertexAttrib2f(index, v0, v1);
void gl.vertexAttrib3f(index, v0, v1, v2);
void gl.vertexAttrib4f(index, v0, v1, v2, v3);
void gl.vertexAttrib1fv(index, value);
void gl.vertexAttrib2fv(index, value);
void gl.vertexAttrib3fv(index, value);
void gl.vertexAttrib4fv(index, value);

同样操作可以如下修改PointSize:

//着色器中添加变量
var VSHADER_SOURCE =
 'attribute vec4 a_Position;\n' +
 'attribute float a_PointSize;\n' +
 'void main() {\n' +
   '  gl_Position = a_Position;\n' +
   '  gl_PointSize = a_PointSize;\n' +
 '}\n';
var aPointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
gl.vertexAttrib1f(aPointSize, 10.0);

片元着色器编程

对片元着色器变成需要使用uniform变量来承载。

var FSHADER_SOURCE =
'precision mediump float;\n'+
'uniform vec4 vColor;\n'+
'void main() {\n' +
'  gl_FragColor = vColor;\n' + // Set the point color
'}\n';

获取片元着色器变量地址。

var vColor = gl.getUniformLocation(gl.program, 'vColor');

给变量赋值。

gl.uniform4f(vColor, 1.0, 0.0, 0.0, 1.0);
//或使用Float32Array来传参
var color = new Float32Array([1.0, 0.0, 0.0, 1.0]);
gl.uniform4fv(vColor,color)

注意:uniform3fv这个函数是典型的GLSL语法命名规范,uniform3fv函数功能:

3:对应需要传3个参数,或者是几维向量。

f:表示参数是float类型。

u:表示参数是Uint32Array类型。

i:表示参数是integer类型。

ui:表示参数是unsigned integer类型。

v:表示传如的为一个vector变量。

uniform对应函数同attribute的函数构成相似,这里就不详细列举,具体请参考 [1]。

着色器中的代码 precision mediump float; 表示的意思是着色器中配置的float对象会占用中等尺寸内存。 具体包含的尺寸:

  • highp for vertex positions,
  • mediump for texture coordinates,
  • lowp for colors.

如果不设置此参数会报错:

WebGL入门与进阶2

我们可以绘制自定义的点了,接下来我们就可以尝试绘制大批量点来达到波浪的基础效果,但是之前的操作都是针对一个点的,如何可以同时绘制多个订点呢,如果你的回答是循环数据,BINGGO,没错这样你的确是可以达到这个目的,但是不是我们接下来要讲的,因为在3D绘制的时候是会经常出现大批量点、线、面的绘制的,所以WebGL提供了一种承载机制来达到传递多点的能力,说了这么多,也让我们来看看它到底是什么吧。

缓存区对象

之前的方式可以通过循环来绘制多个点,一次需要绘制多个点,需要同时传递进去多个点的数据。刚好,在WebGL中提供了一种机制: 缓存区对象(buffer data) ,缓存区对象可以同时向着色器传递多个顶点坐标。缓存区是WebGL中的一块内存区域,我们可以向里面存放大量顶点坐标数据,可随时供着色器使用。

使用缓存区步骤

  • 创建缓存区对象(gl.createBuffer())
  • 绑定缓存区对象(gl.bindBuffer())
  • 将数据写入缓存区对象(gl.bufferData())
  • 将缓存区对象分配给一个attribute变量(gl.vertexAttribPointer())
  • 开启attribute变量(gl.enableVertexAttribArray())

我们需要进行缓冲区的操作: 首先,需要创建一个缓冲区来承载大量顶点的坐标。(代码继续上文)

// 创建缓存区
var vertexBuffer = gl.createBuffer();
if(!vertexBuffer) {
   log('创建缓存区失败。');
   return -1;
}
// 将创建的缓存区对象绑定到target表示的目标上
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 开辟存储空间,向绑定在target上的缓存区对象中写入数据
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// 获取着色器中的变量值
var a_position = gl.getAttribLocation(gl.program, 'a_p');
// 将缓存区对象绑定到着色器变量中
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0);
// 启用缓存区
gl.enableVertexAttribArray(a_position);
// 绘制缓存区中画的多个顶点
gl.drawArrays(gl.POINTS, 0 , array);

看完了绘制过程,让我们来拆解一下具体内容:

首先,我们要在茫茫内存中申请一个区域来放置缓存区对象的内容,但是我们无法直接放置缓存对象进入内存中,否则会无法识别对应的数据类型,从而无法达到存取自如的境界,那我们就需要将数据的类型告知内存, bingBuffer 就是为解决此问题诞生的,函数会在内存中申请一部分区域,并且通过target来制定数据类型,也就是说,缓存区是需要放置在target表示的类型部分去存储。

gl.bindBuffer(target, buffer):

target: 指定存储缓存区的目标类型,

  • gl.ARRAY_BUFFER : 指缓存区中包含了顶点的数据。
  • gl.ELEMENTARRAYBUFFER : 指缓存区中包含了顶点数据的索引值。

buffer: 自己创建的缓存区对象,

接下来,我们需要做的是填充刚刚申请的缓存区,我们需要使用一个符合GLSL语法的数据格式,Javascript中可用 Float32Array 类型来创建支持GLSL的数据。使用 bufferData 函数将数据放入缓存区内。

gl.bufferData(target, size, usage):

target: 同上,

size: 为多个顶点坐标的集合数组,

usage: 表示程序将如何使用缓存区中的数据,

  • gl.STATIC_DRAW : 只会向缓存区对象中写入一次数据,但需要绘制很多次。
  • gl.STREAM_DRAW : 只会向缓存区对象中写入一次数据,然后绘制若干次。
  • gl.DYNAMIC_DRAW : 会想缓存区对象中多次写入数据,并绘制很多次。

缓存区中已经存储了多个顶点坐标,接下来我们需要将此数据运用到对应的着色器上,才能真正的绘制出来可视化图像,如何传递呢?首先我们需要在着色器中建立一个attribute类型的变量以方便我们操作,着色器中的对象,着色器中存在对象之后,我们可以使用Javascript中 getAttribLocation 函数获取着色器中的attribute类型变量,并且通过 vertexAttribPointer 将其赋值改变,从而达到改变图像呈现。

gl.getAttribLocation(program,name):

param: webgl之前创建的进程,

name: 变量名称,

gl.vertexAttribPointer(name, size, type, normalized, stride, offset):

name: 指定要赋值的attribute变量位置,

size: 指定每个顶点数据的分量个数(1或4),

type: 指定传入的数据格式,

  • gl.BYTE: 字节型, 取值范围[-128, 127]。
  • gl.SHORT: 短整型,取值范围[-32768, 32767]。
  • gl.UNSIGNED_BYTE: 无符号字节型,取值范围[0, 255]。
  • gl.UNSIGNED_SHORT: 无符号短整型, 取值范围[0, 65535]。
  • gl.FLOAT: 浮点型。

normalized: 表明是否将非浮点数的数据归入到[0, 1]或[-1, 1]区间,

stride: 指定相邻2个顶点间的字节数,默认为0,

offset: 指定缓存区对象中的偏移量,设置为0即可,

如为2,则
new Float32Array([
   1.0, 1.0,
   1.0,1.0
])
代表2个顶点
如为4,则
new Float32Array([
   1.0, 1.0, 1.0,1.0
])
代表1个顶点

现在缓存区已经存在多个顶点数据,接下来我们来启用携带缓存区数据的attribute变量,使用 enableVertexAttribArray 来启用对应变量。

gl.enableVertexAttribArray(name):

name: 待启动的变量指针,也就是名称,

所有的缓存区操作步骤我们都已经完成,那么接下来我们可以绘制出缓存区中的多个顶点。

gl.drawArrays(mode, first, count)

mode: 需要绘制的图像形状,

  • gl.POINTS: 绘制一个点。
  • gl.LINE_STRIP: 绘制一条直线到下一个顶点。
  • gl.LINE_LOOP: 绘制一条首尾相连的线。
  • gl.LINES: 绘制一条线。
  • gl.TRIANGLES: 绘制一个三角形。

first: 绘制的开始点,

count: 需要绘制的图形个数,

让我们先来创建多个点,上一课已经讲过,WebGL的坐标与真实坐标会有一些出入,所以我们需要转换一下,并且数据我们需要使用Float32Array对象来创建,我们创建一个三维的点数据,总数为200个。

function createPoints() {
   //波动最大幅度 10px;
   var arr = [];
   var n = 20;
   var m = 10;
   for(var i = 0; i < n; i++) {
       for(var j = 0; j < m; j++) {
           var x = webglX(-(width/2) + i*20);
           var y = webglY((height/2) - j*20);
           var z = -1;
           var item = [x, y, z];
           arr = arr.concat(item);
       }
   }
   return new Float32Array(arr)
}

接下来我们使用数据缓存区来讲此200个点一次渲染出来。

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, createPoints(), gl.STATIC_DRAW);
我们先获取到对应的顶点着色器中的变量
var a_position = gl.getAttribLocation(gl.program, 'a_Position');
//我们需要设置数据中的点的维度。否则会解析出错。
gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_position);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
//我们需要确定绘制的具体点的数量
gl.drawArrays(gl.POINTS, 0 , 200);

看看屏幕吧,是不是出来了好多点?没错你已经成功的掌握了着色器基本编程以及数据缓存区的知识。

WebGL入门与进阶2

我们掌握了这些知识之后,下一章让我们先来使用这些内容创建一个点的波浪吧。

扩展阅读

[1] https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/uniform


以上所述就是小编给大家介绍的《WebGL入门与进阶2》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP and MySQL Web Development

PHP and MySQL Web Development

Luke Welling、Laura Thomson / Sams / July 25, 2007 / $49.99

Book Description PHP and MySQL Web Development teaches you to develop dynamic, secure, commerical Web sites. Using the same accessible, popular teaching style of the three previous editions, this b......一起来看看 《PHP and MySQL Web Development》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具