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.vertexAttribPointerdata.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; // 1Uint8Array; // 1Uint8ClampedArray; // 1Int16Array; // 2Uint16Array; // 2Int32Array; // 4Uint32Array; // 4Float32Array; // 4Float64Array; // 8

不出意外的话,经过这些操作,你会得到一个色彩鲜艳的彩色三角形。

3. 总结

接下来回顾一下文章开始提出的问题:

3.1 webgl 中有几种类型的变量?

有三种。

attribute:影响单个顶点uniform:影响全部顶点varying:由顶点向片元传递数据

3.2 如何使用缓冲区对象向着色器传递数据?

1.创建 buffer : gl.createBuffer()2.创建缓冲区数据:new Float32Array()3.绑定缓冲区: gl.bindBuffer4.传入缓冲区数据: gl.bufferData5.获取变量: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 个

webgl基础:顶点到片元的联动

字节跳动技术学院抱枕 1 个

那么如何获奖呢?

获奖分为以下3步

抽奖和领取奖品等其他事项:


The     End

如果你觉得这篇文章对你有帮助,有启发,我想请你帮我2个小忙:

1、点个「在看」,让更多的人也能看到这篇文章内容;


1、豆皮范儿后台回复「vis」,还可以获取更多可视化免费学习资料。

2、豆皮范儿后台回复「webgl」,还可以获取webgl免费学习资料。

3、豆皮范儿后台回复「算法」,还可以获取算法的学习资料。

4、豆皮范儿后台回复「招聘」,获取各种内推。



以上是关于webgl基础:顶点到片元的联动的主要内容,如果未能解决你的问题,请参考以下文章

WebGL简易教程:颜色

渲染管线之深度测试与α融合—如何实现同时绘制不透明物体和透明物体

WebGL学习系列-片元着色器简介

学习WebGL:着色器绘制一个点

WebGl简单实践-烧灼纸张效果[转]

风场可视化:绘制轨迹