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. HDU 4059:The Boss on Mars(数学公式+容斥原理)

    http://acm.hdu.edu.cn/showproblem.php?pid=4059 题意:给出一个n,求1~n里面与n互质的数的四次方的和是多少. 思路:不知道1~n的每个数的四次方的求和公 ...

  2. [转]sublime text3在指定浏览器上本地服务器(localhost)运行文件(php)

    昨天在使用sublime text3时,发现能在本地服务器上运行php文件,于是百度了一下有关知识, 终于成功了,今天总结一下. 首先要让sublime text3 出现侧边栏sidebar,不会的可 ...

  3. redis 命令的调用过程

    参考文献: Redis 是如何处理命令的(客户端) 我是如何通过添加一条命令学习redis源码的 从零开始写redis客户端(deerlet-redis-client)之路--第一个纠结很久的问题,r ...

  4. python3 连接数据库注意点

    类库:pymysql ''' Created on 2019年 @author: Root ''' import pymysql from name import getName # 数据库连接信息 ...

  5. 关于ffmpeg /iis 8.5 服务器下,视频截取第一帧参数配置

    ffmpeg 视频截取第一帧参数配置: 网站找了很多资料,但是都不能满足要求,然后自己写下解决过程. 首先看自己PHP 版本,安全选项里面 php5.4  跟php5.6 是不一样的.去除里面的sys ...

  6. Android安卓书籍推荐《Android驱动开发与移植实战详解》下载

    百度云下载地址:点我 Android凭借其开源性.优异的用户体验和极为方便的开发方式,赢得了广大用户和开发者的青睐,目前已经发展成为市场占有率很高的智能手机操作系统. <Android驱动开发与 ...

  7. 数据库中 ’’ 和 NULL的区别

    null不是对象,''是对象 从'',你就可以知道这是一个字符串类型的数据,是一个长度为零的字符串. 从NULL,你只能知道这里没有赋过值,是空的,他不属于任何数据类型. 我们在数据库实际使用中,一般 ...

  8. py+selenium 报错NameError: name 'NoSuchElementException' is not defined【已解决】

     报错:NameError: name 'NoSuchElementException' is not defined  如图 解决方法: 头部加一句:from selenium.common.exc ...

  9. MsgWaitForMultipleObjects

    Use caution when calling the wait functions and code that directly or indirectly creates windows. If ...

  10. 使用java语言基于SMTP协议手写邮件客户端

    使用java语言基于SMTP协议手写邮件客户端 1. 说明 电子邮件是互联网上常见的应用,他是互联网早期的产品,直至今日依然受到广大用户的喜爱(在中国可能因为文化背景不同,电子邮件只在办公的时候常用) ...