WebGL简易教程(二):向着色器传输数据
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简易教程(二):向着色器传输数据的更多相关文章
- WebGL简易教程(三):绘制一个三角形(缓冲区对象)
目录 1. 概述 2. 示例:绘制三角形 1) HelloTriangle.html 2) HelloTriangle.js 3) 缓冲区对象 (1) 创建缓冲区对象(gl.createBuffer( ...
- WebGL简易教程(四):颜色
目录 1. 概述 2. 示例:绘制三角形 1) 数据的组织 2) varying变量 3. 结果 4. 理解 1) 图形装配和光栅化 2) 内插过程 5. 参考 1. 概述 在上一篇教程<Web ...
- WebGL简易教程——目录
目录 1. 绪论 2. 目录 3. 资源 1. 绪论 最近研究WebGL,看了<WebGL编程指南>这本书,结合自己的专业知识写的一系列教程.之前在看OpenGL/WebGL的时候总是感觉 ...
- WebGL简易教程(十二):包围球与投影
目录 1. 概述 2. 实现详解 3. 具体代码 4. 参考 1. 概述 在之前的教程中,都是通过物体的包围盒来设置模型视图投影矩阵(MVP矩阵),来确定物体合适的位置的.但是在很多情况下,使用包围盒 ...
- WebGL简易教程(十三):帧缓存对象(离屏渲染)
目录 1. 概述 2. 示例 2.1. 着色器部分 2.2. 初始化/准备工作 2.2.1. 着色器切换 2.2.2. 帧缓冲区 2.3. 绘制函数 2.3.1. 初始化顶点数组 2.3.2. 传递非 ...
- WebGL简易教程(十四):阴影
目录 1. 概述 2. 示例 2.1. 着色器部分 2.1.1. 帧缓存着色器 2.1.2. 颜色缓存着色器 2.2. 绘制部分 2.2.1. 整体结构 2.2.2. 具体改动 3. 结果 4. 参考 ...
- WebGL简易教程(六):第一个三维示例(使用模型视图投影变换)
目录 1. 概述 2. 示例:绘制多个三角形 2.1. Triangle_MVPMatrix.html 2.2. Triangle_MVPMatrix.js 2.2.1. 数据加入Z值 2.2.2. ...
- WebGL简易教程(七):绘制一个矩形体
目录 1. 概述 2. 示例 2.1. 顶点索引绘制 2.2. MVP矩阵设置 2.2.1. 模型矩阵 2.2.2. 投影矩阵 2.2.3. 视图矩阵 2.2.4. MVP矩阵 3. 结果 4. 参考 ...
- WebGL简易教程(九):综合实例:地形的绘制
目录 1. 概述 2. 实例 2.1. TerrainViewer.html 2.2. TerrainViewer.js 3. 结果 4. 参考 1. 概述 在上一篇教程<WebGL简易教程(八 ...
随机推荐
- hihoCoder 1312:搜索三·启发式搜索(A* + 康托展开)
题目链接 题意 中文题意 思路 做这题的前置技能学习 康托展开 这个东西我认为就是在排列组合问题上的Hash算法,可以压缩空间. A*搜索. 这里我使用了像k短路一样的做法,从最终状态倒回去预处理一遍 ...
- vue中ajax应用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- web前端css(一)
一 css的引入方式: 1) 行内样式: <p style=”color: green”>我是一个段落</p> 2) 内接样式: <style ty ...
- c++ 函数知识点汇总
c++ 函数知识点汇总 swap函数 交换两个数组元素 比如 swap(a[i],a[j]); 就是交换a[i] 和 a[j] 的值 strcpy() 复制一个数组元素的值到另一个数组元素里 strc ...
- JAVA超级简单的爬虫例子(1)
爬取整个页面的数据,并进行有效的提取信息,注释都有就不废话了: public class Reptile { public static void main(String[] args) { Stri ...
- 走近Java之幕后的String
前几天,有个同事问了我一个表面看起来显而易见的问题,是关于String的,我们一起来看一下(如果有说的不正确的地方,欢迎大家指正). java中,字面量在编译期计算,并且String字面量作为常量,存 ...
- CDQZ集训DAY4 日记
早上起来之后发现座位被zzh占了,得知座位改为先来后到,什么鬼…… 于是去了另一个有耳机的机房,然而并没有什么卵用. T1上来感觉很有意思,先切50分再说.T2好像是原题的说,切了原题30分后大胆猜测 ...
- springcloud-高可用部署
1.场景描述 前端时间只简单介绍了下springcloud的高可用方案(springcloud高可用方案),今天详细介绍下如何实施springcloud的高可用部署. 2.解决方案 2.1 架构方案 ...
- css3系列之弹性盒子 flex
弹性盒子(伸缩盒) 注意,本篇会很长,非常长, 因为弹性盒子的知识点比较多 搜索 弹性盒子的属性 ctrl + F 如果觉得图太小, ctrl + +键 设置弹性盒子的属性: display:f ...
- while 循环,运算符,字符串的格式化
1.while 关键字 (死循环) while 条件: 循环体 条件:只要条件是 Ture就可以循环. while 空格 条件 冒号 缩进 循环体 while else while 空格 条件 冒号 ...