8、webgl 基本概念 + 图像变换(平移 + 旋转 + 缩放)
基本概念
平移
1、普通坐标进行单一的变换
2、利用向量进行平移
3、在webgl中:
(1)用vec2分量表示平移矢量(-0.5,0.5),如果是三维的就使用 vec4 来定义变量
(2)在三维坐标系上 A(X,Y,Z)
在齐次坐标系中我们会使用(X, Y, Z, W)来表示这个顶点
(X, Y, Z, 0)来表示向量
沿 Z 轴旋转
三角函数的和差公式

图像变换
常规方式实现平移
利用参数Tx 的传参方式,向x 轴进行平移。
劣势:沿着 Y 轴平移也需要定义变量,获取变量名的位置,再进行赋值计算,比较麻烦,比如下面的平移方式
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><canvas width="500" height="500" id="myCanvas"></canvas><script type="vertex" id="vertex">attribute vec2 a_position;attribute vec4 a_color;uniform float Tx;varying vec4 v_color;void main() {gl_Position = vec4(a_position.x + Tx, a_position.y, 0, 1);gl_PointSize = 10.0;v_color = a_color;}</script><script type="fragment" id="fragment">precision mediump float;varying vec4 v_color;void main() {gl_FragColor = v_color;}</script><script>let myCanvas = document.getElementById("myCanvas");let gl = myCanvas.getContext("webgl");// IE8 之前的浏览器不兼容if(!gl) {alert("浏览器不支持 webgl!")}// 创建着色器function createShader(gl, type, source) {const shader = gl.createShader(type);gl.shaderSource(shader, source);gl.compileShader(shader);let isSuccess = gl.getShaderParameter(shader, gl.COMPILE_STATUS);return isSuccess ? shader : console.log(gl.getShaderInfoLog(shader))}// 获取着色器中的文本内容字符串function getInnerText(id) {return document.getElementById(id).innerText;}const vertexStr = getInnerText("vertex");const fragmentStr = getInnerText("fragment");const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexStr)const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentStr);// 创建程序function createProgram(gl, vertexShader, fragmentShader) {let program = gl.createProgram();gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);let isSuccess = gl.getProgramParameter(program, gl.LINK_STATUS);return isSuccess ? program : console.log(gl.getProgramInfoLog(program));}let program = createProgram(gl, vertexShader, fragmentShader);gl.useProgram(program);// 获取顶点着色器中变量let a_position = gl.getAttribLocation(program, 'a_position');let screenSize = gl.getUniformLocation(program, 'screenSize');let Tx = gl.getUniformLocation(program, 'Tx');let a_color = gl.getAttribLocation(program, 'a_color');// 获取画布的宽高,因为顶点着色器中已经gl.uniform2f(screenSize, myCanvas.width, myCanvas.height);gl.uniform1f(Tx, 0.5)let positionBuffer = gl.createBuffer();let indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); // 绑定索引缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// 矩形的正面,要逆时针的顶点进行写, 矩形就是两个三角形,也就是需要写 6个 顶点, gl.ARRAY_BUFFER 这个缓冲区需要把所有的顶点都写上,但其实例如矩形的时候有些顶点是重复的,当面越来越多就会造成严重的性能问题,此时我们可以使用 gl.ELEMENT_ARRAY_BUFFER(也就是顶点索引)缓冲区来进行优化-只需要传不重复的点gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 1, 0, -0.5, 0.5, 1, 0, 0, 0.5, 0.5, 0, 1, 0, 0.5, -0.5, 0, 0, 1, -0.5, -0.5, 1, 1, 0,-0.5, 0.5, 1, 0, 0]), gl.STATIC_DRAW);// gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([// 0, 1, 2,// 2, 3, 0// ]), gl.STATIC_DRAW);gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 4 * 5, 0);gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, 4 * 5, 4* 2);// 启用这个位置数据gl.enableVertexAttribArray(a_position);gl.enableVertexAttribArray(a_color);// 绘制三角形 drawArrays 直接从数据的缓冲区取数据// gl.drawElements(mode, count, type, offset) // mode: 制定绘制图元的类型, gl.POINTS, gl.TRIANGLES, gl.LINES...// count: 指定绘制图形的顶点个数// type:指定索引缓冲区的值的类型,常用的值有两个 gl.UNSINGED_TYPE(无符号8位整数值) 和 gl.UNSINGED_SHORT(无符号短整型16位)// offset:指定索引数组中开始绘制的位置,以字节为单位// gl.drawElements(gl.TRIANGLES_FAN, 6, gl.UNSIGNED_SHORT, 0);gl.drawArrays(gl.TRIANGLE_FAN, 0, 6);</script>
</body>
</html>
向量的方式进行平移
在三维坐标系上A(X,Y,Z)
在齐次坐标系中我们会使用(X, Y,Z,W)来表示这个顶点
(X, Y, Z, 0)来表示向量
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><canvas width="500" height="500" id="myCanvas"></canvas><script type="vertex" id="vertex">/*在三维坐标系上A(X,Y,Z)在齐次坐标系中我们会使用(X, Y,Z,W)来表示这个顶点(X, Y, Z, 0)来表示向量*/attribute vec4 a_position;attribute vec4 a_color;// 用vec2分量表示平移矢量(-0.5,0.5),如果是三维的就使用 vec4 来定义变量uniform vec4 a_Translate;varying vec4 v_color;void main() {gl_Position = vec4(a_position + a_Translate);gl_PointSize = 10.0;v_color = a_color;}</script><script type="fragment" id="fragment">precision mediump float;varying vec4 v_color;void main() {gl_FragColor = v_color;}</script><script>let myCanvas = document.getElementById("myCanvas");let gl = myCanvas.getContext("webgl");// IE8 之前的浏览器不兼容if(!gl) {alert("浏览器不支持 webgl!")}// 创建着色器function createShader(gl, type, source) {const shader = gl.createShader(type);gl.shaderSource(shader, source);gl.compileShader(shader);let isSuccess = gl.getShaderParameter(shader, gl.COMPILE_STATUS);return isSuccess ? shader : console.log(gl.getShaderInfoLog(shader))}// 获取着色器中的文本内容字符串function getInnerText(id) {return document.getElementById(id).innerText;}const vertexStr = getInnerText("vertex");const fragmentStr = getInnerText("fragment");const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexStr)const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentStr);// 创建程序function createProgram(gl, vertexShader, fragmentShader) {let program = gl.createProgram();gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);let isSuccess = gl.getProgramParameter(program, gl.LINK_STATUS);return isSuccess ? program : console.log(gl.getProgramInfoLog(program));}let program = createProgram(gl, vertexShader, fragmentShader);gl.useProgram(program);// 获取顶点着色器中变量let a_position = gl.getAttribLocation(program, 'a_position');let screenSize = gl.getUniformLocation(program, 'screenSize');let a_Translate = gl.getUniformLocation(program, 'a_Translate');let a_color = gl.getAttribLocation(program, 'a_color');// 获取画布的宽高,因为顶点着色器中已经gl.uniform2f(screenSize, myCanvas.width, myCanvas.height);gl.uniform4f(a_Translate, 0.5, -0.5, 0, 0)let positionBuffer = gl.createBuffer();let indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); // 绑定索引缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// 矩形的正面,要逆时针的顶点进行写, 矩形就是两个三角形,也就是需要写 6个 顶点, gl.ARRAY_BUFFER 这个缓冲区需要把所有的顶点都写上,但其实例如矩形的时候有些顶点是重复的,当面越来越多就会造成严重的性能问题,此时我们可以使用 gl.ELEMENT_ARRAY_BUFFER(也就是顶点索引)缓冲区来进行优化-只需要传不重复的点gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 1, 0, -0.5, 0.5, 1, 0, 0, 0.5, 0.5, 0, 1, 0, 0.5, -0.5, 0, 0, 1, -0.5, -0.5, 1, 1, 0,-0.5, 0.5, 1, 0, 0]), gl.STATIC_DRAW);// gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([// 0, 1, 2,// 2, 3, 0// ]), gl.STATIC_DRAW);gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 4 * 5, 0);gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, 4 * 5, 4* 2);// 启用这个位置数据gl.enableVertexAttribArray(a_position);gl.enableVertexAttribArray(a_color);// 绘制三角形 drawArrays 直接从数据的缓冲区取数据// gl.drawElements(mode, count, type, offset) // mode: 制定绘制图元的类型, gl.POINTS, gl.TRIANGLES, gl.LINES...// count: 指定绘制图形的顶点个数// type:指定索引缓冲区的值的类型,常用的值有两个 gl.UNSINGED_TYPE(无符号8位整数值) 和 gl.UNSINGED_SHORT(无符号短整型16位)// offset:指定索引数组中开始绘制的位置,以字节为单位// gl.drawElements(gl.TRIANGLES_FAN, 6, gl.UNSIGNED_SHORT, 0);gl.drawArrays(gl.TRIANGLE_FAN, 0, 6);</script>
</body>
</html>
常规实现图像旋转
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><canvas width="500" height="500" id="myCanvas"></canvas><script type="vertex" id="vertex">/*在三维坐标系上A(X,Y,Z)在齐次坐标系中我们会使用(X, Y,Z,W)来表示这个顶点(X, Y, Z, 0)来表示向量*/attribute vec4 a_position;attribute vec4 a_color;// 用vec2分量表示平移矢量(-0.5,0.5),如果是三维的就使用 vec4 来定义变量uniform vec4 a_Translate;uniform float cosb, sinb;varying vec4 v_color;void main() {gl_Position.x = a_position.x * cosb - a_position.y * sinb;gl_Position.y = a_position.x * sinb + a_position.y * cosb;gl_Position.z = a_position.z;gl_Position.w = 1.0;gl_PointSize = 10.0;v_color = a_color;}</script><script type="fragment" id="fragment">precision mediump float;varying vec4 v_color;void main() {gl_FragColor = v_color;}</script><script>let myCanvas = document.getElementById("myCanvas");let gl = myCanvas.getContext("webgl");// IE8 之前的浏览器不兼容if(!gl) {alert("浏览器不支持 webgl!")}// 创建着色器function createShader(gl, type, source) {const shader = gl.createShader(type);gl.shaderSource(shader, source);gl.compileShader(shader);let isSuccess = gl.getShaderParameter(shader, gl.COMPILE_STATUS);return isSuccess ? shader : console.log(gl.getShaderInfoLog(shader))}// 获取着色器中的文本内容字符串function getInnerText(id) {return document.getElementById(id).innerText;}const vertexStr = getInnerText("vertex");const fragmentStr = getInnerText("fragment");const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexStr)const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentStr);// 创建程序function createProgram(gl, vertexShader, fragmentShader) {let program = gl.createProgram();gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);let isSuccess = gl.getProgramParameter(program, gl.LINK_STATUS);return isSuccess ? program : console.log(gl.getProgramInfoLog(program));}let program = createProgram(gl, vertexShader, fragmentShader);gl.useProgram(program);// 获取顶点着色器中变量let a_position = gl.getAttribLocation(program, 'a_position');let screenSize = gl.getUniformLocation(program, 'screenSize');let a_Translate = gl.getUniformLocation(program, 'a_Translate');let u_cosb = gl.getUniformLocation(program, 'cosb');let u_sinb = gl.getUniformLocation(program, 'sinb');let a_color = gl.getAttribLocation(program, 'a_color');let deg = 45;let cosb = Math.cos(deg * Math.PI /180);let sinb = Math.sin(deg * Math.PI /180);gl.uniform1f(u_cosb, cosb);gl.uniform1f(u_sinb, sinb);// 获取画布的宽高,因为顶点着色器中已经gl.uniform2f(screenSize, myCanvas.width, myCanvas.height);gl.uniform4f(a_Translate, 0.5, -0.5, 0, 0)let positionBuffer = gl.createBuffer();let indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); // 绑定索引缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// 矩形的正面,要逆时针的顶点进行写, 矩形就是两个三角形,也就是需要写 6个 顶点, gl.ARRAY_BUFFER 这个缓冲区需要把所有的顶点都写上,但其实例如矩形的时候有些顶点是重复的,当面越来越多就会造成严重的性能问题,此时我们可以使用 gl.ELEMENT_ARRAY_BUFFER(也就是顶点索引)缓冲区来进行优化-只需要传不重复的点gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 0, 1, 0, -0.5, 0.5, 0, 1, 0, 0, 0.5, 0.5, 0, 0, 1, 0, 0.5, -0.5, 0, 0, 0, 1, -0.5, -0.5, 0, 1, 1, 0,-0.5, 0.5, 1, 0, 0, 0]), gl.STATIC_DRAW);// gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([// 0, 1, 2,// 2, 3, 0// ]), gl.STATIC_DRAW);gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 4 * 6, 0);gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, 4 * 6, 4* 3);// 启用这个位置数据gl.enableVertexAttribArray(a_position);gl.enableVertexAttribArray(a_color);// 绘制三角形 drawArrays 直接从数据的缓冲区取数据// gl.drawElements(mode, count, type, offset) // mode: 制定绘制图元的类型, gl.POINTS, gl.TRIANGLES, gl.LINES...// count: 指定绘制图形的顶点个数// type:指定索引缓冲区的值的类型,常用的值有两个 gl.UNSINGED_TYPE(无符号8位整数值) 和 gl.UNSINGED_SHORT(无符号短整型16位)// offset:指定索引数组中开始绘制的位置,以字节为单位// gl.drawElements(gl.TRIANGLES_FAN, 6, gl.UNSIGNED_SHORT, 0);gl.drawArrays(gl.TRIANGLE_FAN, 0, 6);</script>
</body>
</html>
传递矩阵进行图像旋转
矩阵传值要按照列为主序,也就是 转置矩阵. 左矩阵的列数是右边矩阵的行数才可以先乘
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><canvas width="500" height="500" id="myCanvas"></canvas><script type="vertex" id="vertex">// 3个点的传值// attribute vec3 a_position;// 4 个点的传值attribute vec4 a_position;attribute vec4 a_color;uniform vec4 a_Translate;// uniform float cosb, sinb;/*用矩阵的方式 声明旋转矩阵*/// 3 行3列的参数定义// uniform mat3 rotateMatrix;// 4行4列的参数定义uniform mat4 rotateMatrix;varying vec4 v_color;void main() {/*gl_Position.x = a_position.x * cosb - a_position.y * sinb;gl_Position.y = a_position.x * sinb + a_position.y * cosb;gl_Position.z = a_position.z;gl_Position.w = 1.0;*/// 三个点的时候,需要转换一下// gl_Position = vec4(rotateMatrix * a_position, 1);// 四个点的时候,直接计算就行gl_Position = rotateMatrix * a_position;gl_PointSize = 10.0;v_color = a_color;}</script><script type="fragment" id="fragment">precision mediump float;varying vec4 v_color;void main() {gl_FragColor = v_color;}</script><script>let myCanvas = document.getElementById("myCanvas");let gl = myCanvas.getContext("webgl");// IE8 之前的浏览器不兼容if(!gl) {alert("浏览器不支持 webgl!")}// 创建着色器function createShader(gl, type, source) {const shader = gl.createShader(type);gl.shaderSource(shader, source);gl.compileShader(shader);let isSuccess = gl.getShaderParameter(shader, gl.COMPILE_STATUS);return isSuccess ? shader : console.log(gl.getShaderInfoLog(shader))}// 获取着色器中的文本内容字符串function getInnerText(id) {return document.getElementById(id).innerText;}const vertexStr = getInnerText("vertex");const fragmentStr = getInnerText("fragment");const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexStr)const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentStr);// 创建程序function createProgram(gl, vertexShader, fragmentShader) {let program = gl.createProgram();gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);let isSuccess = gl.getProgramParameter(program, gl.LINK_STATUS);return isSuccess ? program : console.log(gl.getProgramInfoLog(program));}let program = createProgram(gl, vertexShader, fragmentShader);gl.useProgram(program);// 获取顶点着色器中变量let a_position = gl.getAttribLocation(program, 'a_position');let screenSize = gl.getUniformLocation(program, 'screenSize');let a_Translate = gl.getUniformLocation(program, 'a_Translate');let rotateMatrix = gl.getUniformLocation(program, 'rotateMatrix');let a_color = gl.getAttribLocation(program, 'a_color');let deg = 40;let cosb = Math.cos(deg * Math.PI /180);let sinb = Math.sin(deg * Math.PI /180);// 矩阵传值要按照列为主序,也就是 转置矩阵. 左矩阵的列数是右边矩阵的行数才可以先乘// gl.uniformMatrix3fv(rotateMatrix, false, new Float32Array([// cosb, sinb, 0,// -sinb, cosb, 0,// 0, 0, 1// ]));// 四个分量的时候矩阵传值gl.uniformMatrix4fv(rotateMatrix, false, new Float32Array([cosb, sinb, 0, 0,-sinb, cosb, 0, 0,0, 0, 1, 0,0, 0, 0, 1]));let positionBuffer = gl.createBuffer();let indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); // 绑定索引缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// 矩形的正面,要逆时针的顶点进行写, 矩形就是两个三角形,也就是需要写 6个 顶点, gl.ARRAY_BUFFER 这个缓冲区需要把所有的顶点都写上,但其实例如矩形的时候有些顶点是重复的,当面越来越多就会造成严重的性能问题,此时我们可以使用 gl.ELEMENT_ARRAY_BUFFER(也就是顶点索引)缓冲区来进行优化-只需要传不重复的点gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 0, 1, 0, -0.5, 0.5, 0, 1, 0, 0, 0.5, 0.5, 0, 0, 1, 0, 0.5, -0.5, 0, 0, 0, 1, -0.5, -0.5, 0, 1, 1, 0,-0.5, 0.5, 1, 0, 0, 0]), gl.STATIC_DRAW);// gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([// 0, 1, 2,// 2, 3, 0// ]), gl.STATIC_DRAW);gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 4 * 6, 0);gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, 4 * 6, 4* 3);// 启用这个位置数据gl.enableVertexAttribArray(a_position);gl.enableVertexAttribArray(a_color);// 绘制三角形 drawArrays 直接从数据的缓冲区取数据// gl.drawElements(mode, count, type, offset) // mode: 制定绘制图元的类型, gl.POINTS, gl.TRIANGLES, gl.LINES...// count: 指定绘制图形的顶点个数// type:指定索引缓冲区的值的类型,常用的值有两个 gl.UNSINGED_TYPE(无符号8位整数值) 和 gl.UNSINGED_SHORT(无符号短整型16位)// offset:指定索引数组中开始绘制的位置,以字节为单位// gl.drawElements(gl.TRIANGLES_FAN, 6, gl.UNSIGNED_SHORT, 0);gl.drawArrays(gl.TRIANGLE_FAN, 0, 6);</script>
</body>
</html>
传入矩阵进行图像缩放
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><canvas width="500" height="500" id="myCanvas"></canvas><script type="vertex" id="vertex">attribute vec4 a_position;attribute vec4 a_color;uniform vec4 a_Translate;uniform mat4 scaleMatrix;varying vec4 v_color;void main() {// 缩放gl_Position = scaleMatrix * a_position;gl_PointSize = 10.0;v_color = a_color;}</script><script type="fragment" id="fragment">precision mediump float;varying vec4 v_color;void main() {gl_FragColor = v_color;}</script><script>let myCanvas = document.getElementById("myCanvas");let gl = myCanvas.getContext("webgl");// IE8 之前的浏览器不兼容if(!gl) {alert("浏览器不支持 webgl!")}// 创建着色器function createShader(gl, type, source) {const shader = gl.createShader(type);gl.shaderSource(shader, source);gl.compileShader(shader);let isSuccess = gl.getShaderParameter(shader, gl.COMPILE_STATUS);return isSuccess ? shader : console.log(gl.getShaderInfoLog(shader))}// 获取着色器中的文本内容字符串function getInnerText(id) {return document.getElementById(id).innerText;}const vertexStr = getInnerText("vertex");const fragmentStr = getInnerText("fragment");const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexStr)const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentStr);// 创建程序function createProgram(gl, vertexShader, fragmentShader) {let program = gl.createProgram();gl.attachShader(program, vertexShader);gl.attachShader(program, fragmentShader);gl.linkProgram(program);let isSuccess = gl.getProgramParameter(program, gl.LINK_STATUS);return isSuccess ? program : console.log(gl.getProgramInfoLog(program));}let program = createProgram(gl, vertexShader, fragmentShader);gl.useProgram(program);// 获取顶点着色器中变量let a_position = gl.getAttribLocation(program, 'a_position');let screenSize = gl.getUniformLocation(program, 'screenSize');let a_Translate = gl.getUniformLocation(program, 'a_Translate');let rotateMatrix = gl.getUniformLocation(program, 'rotateMatrix');let scaleMatrix = gl.getUniformLocation(program, 'scaleMatrix');let a_color = gl.getAttribLocation(program, 'a_color');let Sx = 1.5, Sy = 0.5, Sz = 1;let deg = 40;let cosb = Math.cos(deg * Math.PI /180);let sinb = Math.sin(deg * Math.PI /180);gl.uniformMatrix4fv(scaleMatrix, false, new Float32Array([Sx, 0, 0, 0,0, Sy, 0, 0,0, 0, Sz, 0,0, 0, 0, 1]))// 矩阵传值要按照列为主序,也就是 转置矩阵. 左矩阵的列数是右边矩阵的行数才可以先乘// gl.uniformMatrix3fv(rotateMatrix, false, new Float32Array([// cosb, sinb, 0,// -sinb, cosb, 0,// 0, 0, 1// ]));// 四个分量的时候矩阵传值gl.uniformMatrix4fv(rotateMatrix, false, new Float32Array([cosb, sinb, 0, 0,-sinb, cosb, 0, 0,0, 0, 1, 0,0, 0, 0, 1]));let positionBuffer = gl.createBuffer();let indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); // 绑定索引缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// 矩形的正面,要逆时针的顶点进行写, 矩形就是两个三角形,也就是需要写 6个 顶点, gl.ARRAY_BUFFER 这个缓冲区需要把所有的顶点都写上,但其实例如矩形的时候有些顶点是重复的,当面越来越多就会造成严重的性能问题,此时我们可以使用 gl.ELEMENT_ARRAY_BUFFER(也就是顶点索引)缓冲区来进行优化-只需要传不重复的点gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 0, 1, 0, -0.5, 0.5, 0, 1, 0, 0, 0.5, 0.5, 0, 0, 1, 0, 0.5, -0.5, 0, 0, 0, 1, -0.5, -0.5, 0, 1, 1, 0,-0.5, 0.5, 1, 0, 0, 0]), gl.STATIC_DRAW);// gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([// 0, 1, 2,// 2, 3, 0// ]), gl.STATIC_DRAW);gl.vertexAttribPointer(a_position, 3, gl.FLOAT, false, 4 * 6, 0);gl.vertexAttribPointer(a_color, 3, gl.FLOAT, false, 4 * 6, 4* 3);// 启用这个位置数据gl.enableVertexAttribArray(a_position);gl.enableVertexAttribArray(a_color);// 绘制三角形 drawArrays 直接从数据的缓冲区取数据// gl.drawElements(mode, count, type, offset) // mode: 制定绘制图元的类型, gl.POINTS, gl.TRIANGLES, gl.LINES...// count: 指定绘制图形的顶点个数// type:指定索引缓冲区的值的类型,常用的值有两个 gl.UNSINGED_TYPE(无符号8位整数值) 和 gl.UNSINGED_SHORT(无符号短整型16位)// offset:指定索引数组中开始绘制的位置,以字节为单位// gl.drawElements(gl.TRIANGLES_FAN, 6, gl.UNSIGNED_SHORT, 0);gl.drawArrays(gl.TRIANGLE_FAN, 0, 6);</script>
</body>
</html>
