webgl 参数传递
webgl是基于着色器进行绘制的.着色器本身无法与 JavaScript 进行通讯以及数据的传输.为了能够与 JavaScript 语言进行数据的交互,webgl 封装了很多函数,这些函数根据GLSL ES 暴露出来地址来传递参数.下面主要介绍两种变量:attribute变量和和 uniform变量
attribute变量
attribute 变量是一种 GLSL ES 变量,被用来从外部想顶点着色器内传输数据.只有顶点着色器可以使用它 ,在对变量命名的时候,对于顶点变量一般使用 a_开头.
使用attribute 变量包含以下几个步骤
- 在顶点着色器中声明 attribute 变量
- 将 attribute 变量赋值给 gl_Position 变量
- 向 attribute 变量传输数据
声明 attribute .attribute 变量必须声明为全局变量,数据从着色器外部传递给变量.变量声明的格式按照以下格式:<存储限定符><类型><变量名>
变量如下所示
attribute vec4 a_Position;
存储限定符号 - 类型 - 变量名
将 attribute 变量赋值给 gl_Position.在赋值的数据的类型必须一致,否则将会报错
如下所示
gl_Position = a_Position;
向 attribute 变量传输数据
gl.vertexAttrib3f(a_Position,0.2,0.0,0.0)
完整代码如下所示
<script id="vertextShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
void main () {
gl_Position = a_Position;
gl_PointSize = 20.0;
}
</script>
定义完变量之后,需要在 JavaScript调用 gl.getAttribLocation函数得到 attribute 变量的地址.如果返回的值小于 0,则代表读取的变量为空.示例如下:
const a_Position = gl.getAttribLocation(gl.program,'a_Position')
getAttribLocation函数表示获取 attribute 变量的地址,它拥有两个参数:program,name
- program:表示包含顶点着色器和片元着色器的程序对象
- name:指定想要获取到的 attribute 变量的名称,名称的长度必须小于 256 个字节
Attribute 变量赋值
在 JavaScript 中使用 gl.vertexAttrib3f函数对 attribute 变量赋值.
gl.vertexAttrib3f()函数拥有很多同族函数,比如 gl.vertexAttrib1f,gl.vertexAttrib2f,gl.vertexAttrib3f gl.vertexAttrib4f.webgl 对于相关函数的命名规范一般遵循以下规律
<基础函数名><参数个数><参数类型>
gl.vertexAttrib4f(location,v0,v1,v2,v3)
- vertexAttrib基础函数名
- 4 参数个数 f: 参数类型 f 代表浮点数,i 代表整数,后续的参数参数参数的个数 v1,v2 默认值为 0 ,v3 默认值为 1
uniform变量
uniform变量将颜色值传递给着色器,其步骤与 attribute 变量传递类似,不过不同仅仅是,这次数据传输的目标是片元着色器.对于 uniform 变量的命名一般使用 u_开头,uniform 变量数据格式为<存储限定符号><类型><变量名>
- 在片元着色器准备 uniform变量
- 用 uniform 变量想 gl_FragColor 赋值
- 将颜色数据从 JavaScript 传递给 uniform 变量
获取 uniform 变量的存储地址
gl.getUniformLocation(program,name)
- program:包含顶点着色器和片元着色器 的程序对象
- name:uniform变量的名称
uniform 变量赋值
gl.uniform4f(location,v1,v2,v3,v4)
- location:代表uniform 变量的地址
- v1,v2,v3,v4 代表 4 个参数
uniform4f函数的同族函数
- uniform代表函数名,
- 4 代表 4 个参数,f 代表数据类型为浮点,i 代表未整数,
对于uniform1f,uniform2f,uniform3f 这些同族函数,没有传递第四个参数,那么第四个参数默认为 1,其他参数如果不传递默认为了
实例代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body onload="main()">
<canvas id="webgl" width="400" height="400"></canvas>
</body>
<script id="vertextShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
void main () {
gl_Position = a_Position;
gl_PointSize = 20.0;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
// 全局设置浮点数的精确度,其他类型都有默认的精度类型,浮点数需要单独的设置
precision mediump float;
uniform vec4 u_FragColor;
void main () {
gl_FragColor = u_FragColor;
}
</script>
<script src="./jsm/util.js"></script>
<script>
function main () {
const canvas = document.getElementById('webgl')
const gl = canvas.getContext('webgl')
const vertextShader = document.getElementById('vertextShader').innerText
const fragmentShader = document.getElementById('fragmentShader').innerText
if (!initShaders(gl,vertextShader,fragmentShader)) return
if (!gl) return
const a_Position = gl.getAttribLocation(gl.program,'a_Position')
const u_FragColor = gl.getUniformLocation(gl.program,'u_FragColor')
if (a_Position < 0 && u_FragColor < 0) return
gl.vertexAttrib3f(a_Position,0.2,0.0,0.0)
gl.clearColor(0.0,0.0,0.0,1.0)
gl.clear(gl.COLOR_BUFFER_BIT)
/**
* 颜色缓冲区被 webgl 重置为(0,0,0, 0.0)
* 每次绘制的时候都需要重新调用 gl.clear()函数来指定 canvas 的背景色清空
* */
// gl.drawArrays(gl.POINTS,0,1)
canvas.onmousedown = function (e) {
click(e,gl,canvas,a_Position,u_FragColor)
}
}
let g_Points = []
let u_FragColors = []
function click(e,gl,canvas,a_Position,u_FragColor) {
const x = e.clientX
const y = e.clientY
let rect = canvas.getBoundingClientRect()
const xBase = (x-rect.left - canvas.width/2) / (canvas.width/2)
const yBase = (canvas.height/2 - (y-rect.top)) /(canvas.height/2)
g_Points.push(xBase)
g_Points.push(yBase)
if (xBase>0.0) {
u_FragColors.push([1.0,0.0,0.0,1.0])
}else {
u_FragColors.push([0.0,1.0,0.0,1])
}
gl.clear(gl.COLOR_BUFFER_BIT)
const len = g_Points.length
for(let index=0;index< len;index +=2) {
gl.vertexAttrib3f(a_Position,g_Points[index],g_Points[index+1],0.0)
gl.uniform4f(u_FragColor,u_FragColors[index/2][0],u_FragColors[index/2][1],u_FragColors[index/2][2],u_FragColors[index/2][3])
gl.drawArrays(gl.g_Points,0,1)
}
}
</script>
</html>
initShader 代码如下
function initShaders (gl,vsShader,fShader) {
const program = gl.createProgram();
const vertextShader = loaderShader(gl,gl.VERTEX_SHADER,vsShader)
const fragmentShader = loaderShader(gl,gl.FRAGMENT_SHADER,fShader)
gl.attachShader(program,vertextShader)
gl.attachShader(program,fragmentShader)
// 链接 webgl 上下文和程序对象
gl.linkProgram(program)
gl.useProgram(program)
gl.program = program
return true
}
// 加载着色器
function loaderShader (gl,type,source) {
const shader = gl.createShader(type)
gl.shaderSource(shader,source)
// 编译着色器
gl.compileShader(shader)
return shader
}
网友评论