1. 概述

在上一篇教程《WebGL简易教程(一):第一个简单示例》中,通过一个绘制点的例子,对WebGL中的可编程渲染管线有了个基本的认识。在之前绘制点的例子中,点的位置,点的大小,点的颜色,都是固定写在着色器中的,这样的程序是缺乏可扩展性的。

比如我想绘制一张地形(DEM),平时地形数据是保存在地形文件之中的。被程序加载之后,数据信息首先要被读取到内存,然后传递给显存,最后由显卡进行绘制。渲染管线之所以灵活强大,正是由于可以向负责绘制工作的着色器传递数据。

2. 示例:绘制一个点(改进版)

在上一篇绘制点例子之上进行改进,改进后的HelloPoint1.js代码如下:

// 顶点着色器程序
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' + // attribute variable
'void main() {\n' +
' gl_Position = a_Position;\n' + // Set the vertex coordinates of the point
' gl_PointSize = 10.0;\n' + // Set the point size
'}\n'; // 片元着色器程序
var FSHADER_SOURCE =
'precision mediump float;\n' +
'uniform vec4 u_FragColor;\n' + // uniform変数
'void main() {\n' +
' gl_FragColor = u_FragColor;\n' + // Set the point color
'}\n'; function main() {
// 获取 <canvas> 元素
var canvas = document.getElementById('webgl'); // 获取WebGL渲染上下文
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
} // 初始化着色器
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
} // 获取attribute变量的存储位置
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return;
} // 将顶点位置传输给attribute变量
gl.vertexAttrib3f(a_Position, 0.5, 0.5, 0.0); //获取u_FragColor变量的存储地址
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
if (!u_FragColor) {
console.log('Failed to get the storage location of u_FragColor');
return;
} //将点的颜色传入到u_FragColor变量中
gl.uniform4f(u_FragColor, 0.0, 0.8, 0.0, 1.0); // 指定清空<canvas>的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0); // 清空<canvas>
gl.clear(gl.COLOR_BUFFER_BIT); // 绘制一个点
gl.drawArrays(gl.POINTS, 0, 1);
}

1) attribute变量

在顶点着色器中,可以看到声明了一个attribute的全局变量a_Position,并且将这其赋值给gl_Position:

// 顶点着色器程序
var VSHADER_SOURCE =
'attribute vec4 a_Position;\n' + // attribute variable
'void main() {\n' +
' gl_Position = a_Position;\n' + // Set the vertex coordinates of the point
' gl_PointSize = 10.0;\n' + // Set the point size
'}\n';

attribute是glsl中三种变量声明之一,代表的是与顶点相关的数据,只能用在顶点着色器中。这个变量存储了从外部传输进顶点着色器的数据。

在shader中定义好attribute变量之后,还需要通过JS与shader进行交互。通过WebGL的渲染上下文变量gl,可以得到获取attribute变量的存储地址的方法getAttribLocation(),其定义如下:

通过这个函数,获取着色器中attribute变量的位置:

  // 获取attribute变量的存储位置
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
if (a_Position < 0) {
console.log('Failed to get the storage location of a_Position');
return;
}

获取地址之后,就可以向attribute变量传送数据了。通过使用gl. vertexAttrib3f()函数来向着色器传入值。这里将想要绘制点的位置传送给顶点着色器。

  // 将顶点位置传输给attribute变量
gl.vertexAttrib3f(a_Position, 0.5, 0.5, 0.0);

其函数定义如下:

注意这个函数是有一系列的同族函数,都是以基础函数名+参数个数+参数类型来命名的,以应付传输不同的数据。具体可以查阅WebGL的API。

2) uniform变量

同样的,在片元着色器中,声明了一个全局的uniform变量u_FragColor,并将其赋值给gl_FragColor:

// 片元着色器程序
var FSHADER_SOURCE =
'precision mediump float;\n' +
'uniform vec4 u_FragColor;\n' + // uniform変数
'void main() {\n' +
' gl_FragColor = u_FragColor;\n' + // Set the point color
'}\n';

uniform是glsl中另外一种变量声明,表示的是JavaScript程序向顶点着色器和片元着色器传输的一致的(不变的)数据;也就是是说这种变量既可以用在顶点着色器也可以用于片元着色器。

与attribute变量类似,uniform变量也是先获取其地址,然后向其传值。这里将想要绘制的颜色传送给片元着色器:

//获取u_FragColor变量的存储地址
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
if (!u_FragColor) {
console.log('Failed to get the storage location of u_FragColor');
return;
} //将点的颜色传入到u_FragColor变量中
gl.uniform4f(u_FragColor, 0.0, 0.8, 0.0, 1.0);

可以看到uniform变量是通过gl.getUniformLocation()函数获取地址,gl.uniform4f()变量传送数据的。它们的函数定义如下:



3) varying变量

除了attribute变量和uniform变量之外,还有一种varying变量,它表示的是从顶点着色器流向片元着色器可变的变量。这一点会在以后讲到。如下所示为向着色器传输数据的方式:

3. 结果

再次打开HelloPoint1.html,其显示结果如下:

可以看到点的位置发生了变化,同时颜色也从红色变成了绿色。位置信息和颜色信息不再是硬编码在着色器中,而是从外部传入的。

4. 参考

本来部分代码和插图来自《WebGL编程指南》。

代码和数据地址

上一篇

目录

下一篇

WebGL简易教程(二):向着色器传输数据的更多相关文章

  1. WebGL简易教程(三):绘制一个三角形(缓冲区对象)

    目录 1. 概述 2. 示例:绘制三角形 1) HelloTriangle.html 2) HelloTriangle.js 3) 缓冲区对象 (1) 创建缓冲区对象(gl.createBuffer( ...

  2. WebGL简易教程(四):颜色

    目录 1. 概述 2. 示例:绘制三角形 1) 数据的组织 2) varying变量 3. 结果 4. 理解 1) 图形装配和光栅化 2) 内插过程 5. 参考 1. 概述 在上一篇教程<Web ...

  3. WebGL简易教程——目录

    目录 1. 绪论 2. 目录 3. 资源 1. 绪论 最近研究WebGL,看了<WebGL编程指南>这本书,结合自己的专业知识写的一系列教程.之前在看OpenGL/WebGL的时候总是感觉 ...

  4. WebGL简易教程(十二):包围球与投影

    目录 1. 概述 2. 实现详解 3. 具体代码 4. 参考 1. 概述 在之前的教程中,都是通过物体的包围盒来设置模型视图投影矩阵(MVP矩阵),来确定物体合适的位置的.但是在很多情况下,使用包围盒 ...

  5. WebGL简易教程(十三):帧缓存对象(离屏渲染)

    目录 1. 概述 2. 示例 2.1. 着色器部分 2.2. 初始化/准备工作 2.2.1. 着色器切换 2.2.2. 帧缓冲区 2.3. 绘制函数 2.3.1. 初始化顶点数组 2.3.2. 传递非 ...

  6. WebGL简易教程(十四):阴影

    目录 1. 概述 2. 示例 2.1. 着色器部分 2.1.1. 帧缓存着色器 2.1.2. 颜色缓存着色器 2.2. 绘制部分 2.2.1. 整体结构 2.2.2. 具体改动 3. 结果 4. 参考 ...

  7. WebGL简易教程(六):第一个三维示例(使用模型视图投影变换)

    目录 1. 概述 2. 示例:绘制多个三角形 2.1. Triangle_MVPMatrix.html 2.2. Triangle_MVPMatrix.js 2.2.1. 数据加入Z值 2.2.2. ...

  8. WebGL简易教程(七):绘制一个矩形体

    目录 1. 概述 2. 示例 2.1. 顶点索引绘制 2.2. MVP矩阵设置 2.2.1. 模型矩阵 2.2.2. 投影矩阵 2.2.3. 视图矩阵 2.2.4. MVP矩阵 3. 结果 4. 参考 ...

  9. WebGL简易教程(九):综合实例:地形的绘制

    目录 1. 概述 2. 实例 2.1. TerrainViewer.html 2.2. TerrainViewer.js 3. 结果 4. 参考 1. 概述 在上一篇教程<WebGL简易教程(八 ...

随机推荐

  1. SpringBoot使用Docker快速部署项目

    1.简介 建议阅读本文最好对Dokcer有一些了解 首先我们先了解一下Docker是什么 Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口.它是目前最流行的 Linux 容器 ...

  2. 微信开发:微信js_sdk分享,使用场景,网页在微信app内部分享时的标题与描述,包括logo设置(一)

    主要有下面几步.首先大家先分清楚 小程序的appid,appSecret 跟公众号的appid,appSecret是不一样的.因为这两个都能拿到token,且是不同的值. 准备开始: 1.准备好 公众 ...

  3. 阿里云体验:安装jdk

    在阿里云的linux服务器上默认是没有安装java环境的,需要自己安装.查了许多资料,发现这篇文章简洁易用.http://www.cnblogs.com/cloudwind/archive/2012/ ...

  4. Pygame安装问题

    1.首先使用如下命令: conda install -c https://conda.anaconda.org/quasiben pygame 测试报错: >>> import py ...

  5. yum只下载不安装软件包

    一.通过yum自带的工具yumdownloader [root@host---- interpreter]# rpm -ql yum-utils package yum-utils is not in ...

  6. DataGrid通过DataSet保存为xml文件,并导入

    做了个小的DataGrid通过DataSet保存为xml_测试,DataGrid通过DataSet保存为xml_测试,通过dataSet.writeXML()和dataSet.readXML()方法完 ...

  7. HDU - 1232 畅通工程【并查集】

    畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  8. c++小游戏——职业战争

    #include<iostream> #include<cstdlib> #include<ctime> #include<cstring> #incl ...

  9. ThreadLocal的使用场景:Web容器、Spring容器、日志打印

    一.对于HTTP事务的理解 一次HTTP请求,就是一个事务.事务者,必须完整的执行其中的所有步骤,不能中断. 二.HTTP事务的隔离 每次HTTP请求对应一个HTTP事务,而每个请求都对应一个线程,线 ...

  10. Adaboost原理推导

    Adaptive Boosting是一种迭代算法.每轮迭代中会在训练集上产生一个新的学习器,然后使用该学习器对所有样本进行预测,以评估每个样本的重要性(Informative).换句话来讲就是,算法会 ...