webgl基础:顶点到片元的联动
Posted 豆皮范儿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webgl基础:顶点到片元的联动相关的知识,希望对你有一定的参考价值。
豆皮粉儿们,大家好,又见面了。
继前期分享了 初入webgl
的一些内容之后,相信大家已经对webgl
有了一个初步的认识,今天再来分享一些基础内容,用以加深大家对于它的认知。
众所周知,3d
的内容是比较多的,也很容易让人看的很迷惑。所以,此系列文章的分享理念就一个 -- 说透彻,说清楚,说明白。
好了,话不多说,进入今天的分享内容。
1. 前言:
分享之前先来回顾一下两个内容:
•webgl
中有几种类型的变量?•如何使用缓冲区对象向着色器传递数据?
希望大家带着这两个问题来阅读本篇文章。
⚠️注意啦:字节跳动春招开始了,大家ready了吗?欢迎大家找我内推,最快方式进入到部门筛选,筛选方式可以在公众号后台回复关键字「招聘」,点击下面图片❤️
2. varying变量的使用
在之前的文章中介绍过 webgl
中的数据类型,现在我们来重温一下:
•attribute
:影响单个顶点•uniform
:影响全部顶点•varying
:由顶点向片元传递数据
同时也介绍了如何使用 attribute、uniform
这两个变量。相信对于这两个变量大家都有了一定程度的认识。但对于最后一个 varying
变量的使用,之前的文章中从未提过。
由介绍可得知,varying
变量的主要作用就是从顶点着色器向片元着色器传值。具体怎么使用呢?莫慌,一步步来看下面的实现:
2.1 绘制一个点,(老代码,回顾一下。无新知识)
const VERTEX_SHADER_SOURCE = '' +
'attribute vec4 apos;' +
'void main () {' +
' gl_Position = apos;' +
' gl_PointSize = 10.0;' +
'}'
const FRAGMENT_SHADER_SOURCE = '' +
'precision lowp float;' +
'varying vec4 vColor;' +
'void main() {' +
' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);' +
'}' +
''
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE);
const buffer = gl.createBuffer()
const data = new Float32Array([
-1.0, -1.0,
1.0, -1.0,
0.0, 1.0,
])
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW)
const apos = gl.getAttribLocation(program, 'apos');
gl.vertexAttribPointer(apos, 2, gl.FLOAT, false, 0, 0)
gl.enableVertexAttribArray(apos)
gl.drawArrays(gl.TRIANGLES, 0, 3)
这段代码相信大家已经非常熟悉,在画布中绘制一个红色的三角形,对于其中用到的方法也可以查下之前的文章。这里就不赘述了。
2.2 使用 varying 传递数据
使用 varying
传递数据需要分以下几步:
•在顶点着色器中创建一个变量,用于获取数据。可暂时先用 apos
。将位置信息作为颜色传入到片元着色器中•在顶点着色器中创建 varying
变量•将数据 apos
赋值给 varying
变量•在片元着色器中指定精度•在片元着色器中创建同名的 varying
变量•使用 varying
变量
注意:
varying
变量的类型与 attribute
的类型相同。也是四分量的浮点数 -- vec4
了解了以上步骤之后,来看下代码怎么写:
栗子:
const VERTEX_SHADER_SOURCE = '' +
'attribute vec4 apos;' + // 用于获取数据的 apos 变量
'varying vec4 vColor;' + // 用于传输数据的 varying 变量
'void main () {' +
' gl_Position = apos;' +
' gl_PointSize = 10.0;' +
' vColor = apos;' + // 将位置数据传输到片元着色器中
'}'
const FRAGMENT_SHADER_SOURCE = '' +
'precision lowp float;' + // 指定浮点数精度为低精度
'varying vec4 vColor;' + // 创建同名的 varying 变量
'void main() {' +
' gl_FragColor = vColor;' + // 使用 varying 变量
'}' +
''
再次运行后可以看到一个彩色的三角形。这里我们就将位置信息当做颜色信息传入到了片元着色器中。记得一定要指定精度。否则会出现渲染错误。
2.3 传入指定的颜色数据
在第二步中,通过传入位置信息来显示对应位置的颜色。接下来来看看,如何通过 varying
变量传入指定的颜色信息。
1. 首先修改着色器源代码。
const VERTEX_SHADER_SOURCE = '' +
'attribute vec4 apos;' +
'attribute vec4 aColor;' + // 新增颜色信息变量
'varying vec4 vColor;' +
'void main () {' +
' gl_Position = apos;' +
' gl_PointSize = 10.0;' +
' vColor = aColor;' + // 将颜色信息传入到 varying 变量中
'}'
const FRAGMENT_SHADER_SOURCE = '' +
'precision lowp float;' +
'varying vec4 vColor;' +
'void main() {' +
' gl_FragColor = vColor;' +
'}' +
''
2. 修改缓冲区数据。
// 在每个位置后新增颜色信息。vec4 的数据。
const data = new Float32Array([
-1.0, -1.0, 1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 0.0, 1.0, 1.0, 1.0,
0.0, 1.0, 1.0, 0.0, 1.0, 1.0,
])
3. 修改数据传入
绘制三角形的时候只有一个 apos
变量。现在新增了一个,所以需要修改数据的传入方式。修改后的代码如下
const apos = gl.getAttribLocation(program, 'apos');
gl.vertexAttribPointer(apos, 2, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 6, 0)
gl.enableVertexAttribArray(apos)
const aColor = gl.getAttribLocation(program, 'aColor');
gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 6, data.BYTES_PER_ELEMENT * 2);
gl.enableVertexAttribArray(aColor)
这里可以这样理解:
•data
缓冲区中,每 6
个元素表示一个顶点信息。•apos
需要两个,从每个顶点的第1
个数据开始查找。•aColor
需要四个,从每个顶点的第 3
个数据开始查找。
同时对于代码中所涉及到的新知识点 gl.vertexAttribPointer
、data.BYTES_PER_ELEMENT
两个内容,也来详细介绍下。
1.对于 gl.vertexAttribPointer
之前的文章里有过介绍,可能介绍的不太详细。再来详细介绍下:
gl.vertexAttribPointer(location, size, type, normalized, stride, offset);
location: 指定修改的着色器变量的位置
size: 每次绘制需要几个顶点,定义的数据如何分配。
type:顶点的数据类型。与类型化数组的类型相同。
gl.BYTE:带符号的8位整数
gl.SHORT:带符号的16位整数
gl.UNSIGNED_BYTE:无符号8位整数
gl.UNSIGNED_SHORT:无符号16位整数
gl.FLOAT:32位浮点数
normalized:是否将浮点数归一化到 [0, 1] 或 [-1, 1] 之间
stride:**可简单理解为一个点需要多少个数据。**
offset:偏移几个顶点开始绘制
这里也会注意到,最后的 stride 和 offset
两个参数都做了修改。而且是通过 data.BYTES_PER_ELEMENT
来实现的。
2. data.BYTES_PER_ELEMENT
表示数组中每个元素所占的字节数。主要有以下几个分类:
数组类型:占的字节数
Int8Array; // 1
Uint8Array; // 1
Uint8ClampedArray; // 1
Int16Array; // 2
Uint16Array; // 2
Int32Array; // 4
Uint32Array; // 4
Float32Array; // 4
Float64Array; // 8
不出意外的话,经过这些操作,你会得到一个色彩鲜艳的彩色三角形。
3. 总结
接下来回顾一下文章开始提出的问题:
3.1 webgl
中有几种类型的变量?
有三种。
•attribute
:影响单个顶点•uniform
:影响全部顶点•varying
:由顶点向片元传递数据
3.2 如何使用缓冲区对象向着色器传递数据?
1.创建 buffer
: gl.createBuffer()
2.创建缓冲区数据:new Float32Array()
3.绑定缓冲区: gl.bindBuffer
4.传入缓冲区数据: gl.bufferData
5.获取变量:const 获取到的变量 = gl.getAttribLocation(program, '变量名称')6.给变量赋值:gl.vertexAttribPointer(location, size, type, normalized, stride, offset)7.激活变量:gl.enableVertexAttribArray(获取到的变量)
4. 完整代码
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>顶点着色器向片元着色器传递数据</title>
</head>
<body>
<div>
<canvas id="canvas" width="300" height="300" style="border: 1px solid #666666;"></canvas>
</div>
<script>
const canvas = document.getElementById('canvas')
const gl = canvas.getContext('webgl')
const VERTEX_SHADER_SOURCE = '' +
'attribute vec4 apos;' +
'attribute vec4 aColor;' +
'varying vec4 vColor;' +
'void main () {' +
' gl_Position = apos;' +
' gl_PointSize = 10.0;' +
' vColor = aColor;' +
'}'
const FRAGMENT_SHADER_SOURCE = '' +
'precision lowp float;' +
'varying vec4 vColor;' +
'void main() {' +
' gl_FragColor = vColor;' +
'}' +
''
const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
gl.shaderSource(vertexShader, VERTEX_SHADER_SOURCE)
gl.shaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE)
gl.compileShader(vertexShader)
gl.compileShader(fragmentShader)
const program = gl.createProgram()
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.linkProgram(program)
gl.useProgram(program)
const buffer = gl.createBuffer()
const data = new Float32Array([
-1.0, -1.0, 1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 0.0, 1.0, 1.0, 1.0,
0.0, 1.0, 1.0, 0.0, 1.0, 1.0,
])
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW)
const apos = gl.getAttribLocation(program, 'apos');
gl.vertexAttribPointer(apos, 2, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 6, 0)
gl.enableVertexAttribArray(apos)
/*
Int8Array; // 1
Uint8Array; // 1
Uint8ClampedArray; // 1
Int16Array; // 2
Uint16Array; // 2
Int32Array; // 4
Uint32Array; // 4
Float32Array; // 4
Float64Array; // 8
*/
const aColor = gl.getAttribLocation(program, 'aColor');
gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, data.BYTES_PER_ELEMENT * 6, data.BYTES_PER_ELEMENT * 2);
gl.enableVertexAttribArray(aColor)
gl.drawArrays(gl.TRIANGLES, 0, 3)
</script>
</body>
</html>
相关阅读
••••
福利时间
字节跳动技术学院帆布包 1 个
字节跳动技术学院抱枕 1 个
那么如何获奖呢?
获奖分为以下3步
抽奖和领取奖品等其他事项:
The End
如果你觉得这篇文章对你有帮助,有启发,我想请你帮我2个小忙:
1、点个「在看」,让更多的人也能看到这篇文章内容;
1、豆皮范儿后台回复「vis」,还可以获取更多可视化免费学习资料。
2、豆皮范儿后台回复「webgl」,还可以获取webgl免费学习资料。
3、豆皮范儿后台回复「算法」,还可以获取算法的学习资料。
4、豆皮范儿后台回复「招聘」,获取各种内推。
以上是关于webgl基础:顶点到片元的联动的主要内容,如果未能解决你的问题,请参考以下文章