缓冲区对象(多个顶点数据的绘制问题)
缓冲区对象是webGl系统中的一块内存区域,可以一次性向缓冲区对象中填入大量顶点数据,将数据保存在其中供顶点着色器使用
//创建一组顶点数据
//Float32Array是类型化数组
const points = new Float32Array([
-0.5,-0.5,
0.5,-0.5,
0.0,0.5,
])
//创建一块内存区域
const buffer = gl.createBuffer()
//绑定缓存区对象
//bindBuffer(target,buffer) buffer是已经创建好的缓存区对象 target分为 gl.ARRAY_BUFFER:表示缓存区储存的顶点的数据 gl.ELEMENT_ARRAY_BUFFER:表示缓冲区存储的是顶点的索引值
gl.bindBuffer(gl.ARRAY_BUFFER,buffer)
//将顶点数据写入
//bufferData(target,data,type) data 写入缓冲区的顶点数据 type表示如何使用缓冲区对象中的数据,分为gl.STATIC_DRAW:写入一次,绘制多次,gl.STREAM_DRAW:写入一次,绘制若干次 ,gl.DYNAMIC_DRAW:写入多次,绘制多次
gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
//给attribute变量赋值
//vertexAttribPointer(location,size,type,narmalized,stride,offset)
//size:每个顶点使用的个数,
//type指定数据类型,要与顶点数据类型一致,分为gl.FLOAT 浮点型,gl.UNSIGNED_BYTE 无符号字节,gl.SHORT 短整型,gl.UNSIGNED_SHORT无符号短整型, gl.INT整形, gl.UNSIGN_INT无符号整型
// normalized 是否将数据归一化到[0,1][-1,1]这个区间
// stride两个相邻顶点间字节数 offset 数据偏移量
gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,0,0);
//激活attribute变量 disableVertexAttribArray禁用
gl.enableVertexAttribArray(aPosition)
gl.drawArrays(gl.POINTS,0,3);
缓冲区对象的执行流程
多缓冲区和数据偏移
const aPointSize = gl.getAttribLocation(program,'aPointSize')
const size = new Float32Array([
10.0,
20.0,
30.0,
40.0,
50.0
])
//创建一块内存区域
const sizebuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER,sizebuffer)
gl.bufferData(gl.ARRAY_BUFFER,size,gl.STATIC_DRAW)
//只要一个数据 size改为1
gl.vertexAttribPointer(aPointSize,1,gl.FLOAT,false,0,0);
gl.enableVertexAttribArray(aPointSize)
gl.drawArrays(gl.POINTS,0,5);
通过偏移量实现只使用一组数据完成以上操作
const aPosition = gl.getAttribLocation(program,'aPosition')
const points = new Float32Array([
-0.5,-0.5,10.0,
0.5,-0.5,20.0,
0.0,0.0,30.0,
0.0,0.5,40.0,
0.5,0.5,50.0
])
//创建一块内存区域
const buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER,buffer)
gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW)
const aPointSize = gl.getAttribLocation(program,'aPointSize')
const BYTES = points.BYTES_PER_ELEMENT
// 获取两个数据间间距字节数
// 需要用到三个数据,没两组数据的间距为BYTES*3
gl.vertexAttribPointer(aPosition,2,gl.FLOAT,false,BYTES*3,0);
gl.enableVertexAttribArray(aPosition)
// 每次使用需要略过前两个数据
gl.vertexAttribPointer(aPointSize,1,gl.FLOAT,false,BYTES*3,BYTES*2);
//激活attribute变量 disableVertexAttribArray禁用
gl.enableVertexAttribArray(aPointSize)
gl.drawArrays(gl.POINTS,0,5);
多种图形绘制
//gl.LINES如果顶点数是奇数个,最后一个参数会被忽略,如果三个点都需要被使用,可以用LINE_STRIP
//LINE_STRIP会绘制连续的线段,但是不会闭合起点和终点
//LINE_LOOP会闭合起点和终点
gl.drawArrays(gl.LINE_STRIP,0,5);
//TRIANGLES需要的顶点数至少为3或3的倍数
gl.drawArrays(gl.TRIANGLES,0,5);
gl.drawArrays(gl.TRIANGLE_FAN,0,5);
//gl.PointSize只有在绘制点时会生效,绘制图形不生效
图形平移
着色器中
attribute vec4 aPosition;
attribute float aTranslate;
void main(){
gl_Position = vec4(aPosition.x + aTranslate,aPosition.y,aPosition.z,1.0);
}
script中
let x = -1
setInterval(() => {
x += 0.01
if(x>1){
x = -1
}
gl.vertexAttrib1f(aTranslate,x);
gl.drawArrays(gl.TRIANGLES,0,3);
}, 60);
图形缩放
attribute vec4 aPosition;
attribute float aScale;
void main(){
gl_Position = vec4(aPosition.x * aScale,aPosition.y,aPosition.z,1.0);
}
与图形平移原理一致
图形旋转
与平移缩放类似,但是需要给xyzw单独赋值
const VERTEX_SHADER_SOURCE = `
//需要控制多个属性需要创建多个变量
attribute vec4 aPosition;
attribute float deg;
void main(){
gl_Position.x = aPosition.x*cos(deg)-aPosition.y*sin(deg);
gl_Position.y = aPosition.x*sin(deg)+aPosition.y*cos(deg);
gl_Position.z = aPosition.z
gl_Position.w = aPosition.w
}
` //顶点着色器
计时器实现动画比较卡顿,用requestAnimationFrame
let x = 1
function animation(){
x += 0.1
gl.vertexAttrib1f(deg,x);
gl.drawArrays(gl.TRIANGLES,0,3);
//用于实现动画效果
requestAnimationFrame(animation)
}
animation()
图形平移PLUS
矩阵用于表示点到点的转换关系
通过此法获得矩阵
1,0,0,x1, 此法获得的矩阵为行主序 1,0,0,0,
0,1,0,y1, webgl中矩阵为列主序,故转换为 0,1,0,0,
0,0,1,z1, 0,0,1,0,
0,0,0,1, x1,y1,z1,1,
着色器中
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
//使用uniform声明接受矩阵的变量,uniform对所有点生效,平移是平移所有点
uniform mat4 mat;
void main(){
gl_Position = mat * aPosition;
}
` //顶点着色器
const mat = gl.getUniformLocation(program,'mat')
//创建一个获取矩阵的函数
function getTranlateMatrix(x = 0,y = 0,z = 0){
return new Float32Array([
1.0,0.0,0.0,0.0,
0.0,1.0,0.0,0.0,
0.0,0.0,1.0,0.0,
x, y, z, 1.0,
])
}
...
let x = -1
function animation(){
x += 0.1
if(x>1){
x = -1
}
//获取矩阵
const matrix = getTranlateMatrix(x)
//给mat4变量赋值uniformMatrix4fv(location,transpose,array)location uniform变量,transpose恒为false,array矩阵
gl.uniformMatrix4fv(mat,false,matrix);
gl.drawArrays(gl.TRIANGLES,0,3);
//用于实现动画效果
requestAnimationFrame(animation)
}
animation()
图形缩放PLUS
只有获取矩阵的函数不同和设置x的范围不同
//创建一个获取矩阵的函数
function getScaleMatrix(x = 1,y = 1,z = 1){
return new Float32Array([
x,0.0,0.0,0.0,
0.0,y,0.0,0.0,
0.0,0.0,z,0.0,
0.0,0.0,0.0,1.0,
])
}
图形旋转PLUS
只有获取矩阵的函数不同和设置x的大小不同
function getRotateMatrix(deg){
return new Float32Array([
Math.cos(deg),Math.sin(deg),0.0,0.0,
-Math.sin(deg),Math.cos(deg),0.0,0.0,
0.0,0.0,1.0,0.0,
0.0,0.0,0.0,1.0,
])
}
图形的复合变换
方法1,声明多个变量多次赋值
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
//使用uniform声明接受矩阵的变量,uniform对所有点生效,平移是平移所有点
uniform mat4 translateMatrix;
uniform mat4 scaleMatrix;
uniform mat4 rotationMatrix;
void main(){
gl_Position = translateMatrix * scaleMatrix * rotationMatrix * aPosition;
}
` //顶点着色器
...
const aPosition = gl.getAttribLocation(program,'aPosition')
const translate = gl.getUniformLocation(program,'translateMatrix')
const scale = gl.getUniformLocation(program,'scaleMatrix')
const rotation = gl.getUniformLocation(program,'rotationMatrix')
...
let deg = 0
let translateX = -1
let scale1 = 0.1
function animation(){
deg += 0.01
translateX += 0.01
scale1 += 0.01
if (translateX > 1) {
translateX = -1
}
if (scale1 > 0.5) {
translateX = 0.1
}
//获取矩阵
const r = getRotateMatrix(deg)
const t = getTranlateMatrix(translateX)
const s = getScaleMatrix(scale1)
//给mat4变量赋值uniformMatrix4fv(location,transpose,array)location uniform变量,transpose恒为false,array矩阵
gl.uniformMatrix4fv(translate,false,t);
gl.uniformMatrix4fv(rotation,false,r);
gl.uniformMatrix4fv(scale,false,s);
gl.drawArrays(gl.TRIANGLES,0,3);
//用于实现动画效果
requestAnimationFrame(animation)
}
animation()
方法2:使用多个矩阵复合成为一个矩阵 矩阵a的列* 矩阵b的行,得到新矩阵的行
let deg = 0
let translateX = -1
let scale1 = 0.1
function animation(){
deg += 0.01
translateX += 0.01
scale1 += 0.01
if (translateX > 1) {
translateX = -1
}
if (scale1 > 1.5) {
scale1 = 0.1
}
//获取矩阵
const r = getRotateMatrix(deg)
const t = getTranlateMatrix(translateX,translateX)
const s = getScaleMatrix(scale1)
const m = mixMatrix(mixMatrix(r,t),s)
//给mat4变量赋值uniformMatrix4fv(location,transpose,array)location uniform变量,transpose恒为false,array矩阵
gl.uniformMatrix4fv(mat,false,m);
gl.drawArrays(gl.TRIANGLES,0,3);
//用于实现动画效果
requestAnimationFrame(animation)
}
animation()
//矩阵复合函数
function mixMatrix(a,b){
const result = new Float32Array(16)
for (let i = 0; i < 4; i++) {
result[i] = a[i]*b[0] +a[i+4]*b[1]+a[i+8]*b[2]+a[i+12]*b[3]
//列主序,故处理i+4
result[i +4] = a[i]*b[4] +a[i+4]*b[5]+a[i+8]*b[2]+a[i+12]*b[3]
result[i +8] = a[i]*b[8] +a[i+4]*b[9]+a[i+8]*b[10]+a[i+12]*b[11]
result[i +12] = a[i]*b[12] +a[i+4]*b[13]+a[i+8]*b[14]+a[i+12]*b[15]
}
return result
}