本文正在参加「金石计划」
以前通过echarts写过数据大屏。欢迎star~~~
一些数据可视化的类库和技术
Skia
Skia是Chrome和Android的底层2D绘图引擎,具体可参考百度百科,Skia采用C++编程,由于它位于浏览器的更底层,所以我们平常接触较少。
WebGl
WebGL(Web Graphics Library)是一种3D绘图协议,WebGL可以为HTML5 Canvas 提供硬件3D加速 渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。
three.js
对WebGL的封装,基于JavaScript,可直接运行 GPU 驱动游戏与图形驱动应用于浏览器。其库提供大量特性与API以绘制 3D 场景于浏览器。
zrender
zrender是二维绘图引擎,它提供Canvas、SVG、VML等多种渲染方式。ZRender也是ECharts的渲染器。
d3
D3(Data-Driven Documents)是一个Javascript图形库,基于Canvas、Svg和HTML。d3是数据驱动的矢量图绘制库。
矢量图是由一个个点链接在一起组成的,是根据几何特性来绘制的图像。请参考这里
Canvas API 主要聚焦于 2D 图形。他不像svg绘制成一个个dom,他是通过<canvas>
画布来完成绘制的。
Highcharts
Highchartst是一个用纯JavaScript编写的一个图表库,能够很简单便捷的在web网站或是web应用程序添加有交互性的图表,并且免费提供给个人学习、个人网站和非商业用途使用。Highcharts系列包含Highcharts JS,Highstock JS,Highmaps JS 共三款软件,均为纯JavaScript 编写的HTML5图表库。
-
Highcharts Highcharts是一个用纯JavaScript编写的一个图表库,能够很简单便捷的在Web 网站或是Web 应用程序添加有交互性的图表,Highcharts支持的图表类型有直线图、曲线图、区域图、柱状图、饼状图、散状点图、仪表图、气泡图、瀑布流图等多达20种图表,其中很多图表可以集成在同一个图形中形成混合图。
-
Highstock Highstock是用纯JavaScript编写的股票图表控件,可以开发股票走势或大数据量的时间轴图表。它包含多个高级导航组件:预设置数据时间范围,日期选择器、滚动条、平移、缩放功能。
-
Highmaps Highmaps是一款基于HTML5的优秀地图组件。Highmaps 继承了Highcharts 简单易用的特性,利用它 可以方便快捷的创建用于展现销售、选举结果等其他与地理位置关系密切的交互性地图图表。
AntV
AntV是蚂蚁金服全新一代数据可视化解决方案,致力于提供一套简单方便、专业可靠、无限可能的数据可视化最佳实践。
AntV 包括以下解决方案:
- G2:可视化引擎
- G2Plot:图表库
- G6:图可视化引擎
- Graphin:基于G6的图分析组件
- F2:移动可视化方案
- ChartCube:AntV 图表在线制作
- L7:地理空间数据可视化。
WebGl
webgl是一种3D绘图协议,衍生于OpenGL ES2.0,可以结合Html5和 JavaScript 在网页上绘制和渲染二/三维图形。
他和canvas api一样都需要canvas
标签作为渲染容器。
图形的绘制主要通过WebGLRenderingContext
,WebGL2RenderingContext
接口完成。
GLSL ES是以字符串的形式存在在js中的。
webgl可以做啥
webgl开源类库
1. Three.js: JavaScript 3D WebGL库
2.Babylon.js:Web3D图形引擎
3.KickJS: Web的开源图形和游戏引擎
4.ClayGL:构建可扩展的Web3D应用程序
5.PlayCanvas:网络游戏和3D图形引擎
6.WebGLStudio.js和Litescene.js:开源Web 3D图形编辑器和创建器
7.Luma:Uber的3D WebGL可视化库
8.A—Frame是用于构建VR(虚拟现实)体验的Web框架
着色器
着色器就是让开发者自己去编写一段程序,用来代替固定渲染管线,来处理图像的渲染。
- 顶点着色器
用来描述顶点的特性,通过计算获取位置信息,顶点是指二维三维空间中的一个点,可以理解为一个个坐标。
// 着色器
// 创建着色器源码
// gl_Position vec4(0.0,0.0,0.0,1.0) x, y, z, w齐次坐标 (x/w, y/w, z/w)
const VERTEX_SHADER_SOURCE=`
// 必须要存在 main 函数
void main() {
// 要绘制的点的坐标
gl_Position = vec4(1.0,0.0,0.0,1.0); // 超出canvas画布将会被剪切。
// 点的大小
gl_PointSize = 30.0;
}
`; // 顶点着色器
- 片元着色器
进行逐片元处理程序,通过计算获取颜色信息,片元可以理解为一个个像素。
// gl_FragColor vec4(1.0,0.0,0.0,1.0) r, g, b, a
const FRAGMENT_SHADER_SOURCE=`
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
坐标系
- canvas绘制的坐标系是canvas元素的左上角。
- webgl绘制原点是中心位置。因为它需要处理三维图形。
webgl绘制一个点
- 创建webgl上下文对象
const gl=ctx.getContext('webgl')
。 - 创建着色器源码,就是一个字符串,但是必须按规定编写,每条语句都需要加分号。
- vec4对象创建一个顶点坐标。
gl_Position vec4(0.0,0.0,0.0,1.0) x, y, z, w齐次坐标 (x/w, y/w, z/w)
。 - 创建片元着色器源码,
gl_FragColor vec4(1.0,0.0,0.0,1.0) r, g, b, a
。 - 创建着色器,并绑定一个程序对象。
gl.drawArrays(gl.POINTS,0,1)
绘制图形。【要绘制的图形是什么, 从哪个开始,使用几个顶点】。
function initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE) {
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)
return program;
}
const ctx=document.getElementById('canvas')
const gl=ctx.getContext('webgl')
// 着色器
// 创建着色器源码
const VERTEX_SHADER_SOURCE=`
// 必须要存在 main 函数
void main() {
// 要绘制的点的坐标
gl_Position = vec4(1.0,0.0,0.0,1.0); // 超出canvas画布将会被剪切。
// 点的大小
gl_PointSize = 30.0;
}
`; // 顶点着色器
// gl_Position vec4(0.0,0.0,0.0,1.0) x, y, z, w齐次坐标 (x/w, y/w, z/w)
// gl_FragColor vec4(1.0,0.0,0.0,1.0) r, g, b, a
const FRAGMENT_SHADER_SOURCE=`
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
// 创建着色器
// 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 program=initShader(gl,VERTEX_SHADER_SOURCE,FRAGMENT_SHADER_SOURCE)
// 执行绘制
// 要绘制的图形是什么,从哪个开始,使用几个顶点
gl.drawArrays(gl.POINTS,0,1);
gl.drawArrays(gl.LINES,0,1); // 最少需要有两个点,
gl.drawArrays(gl.TRIANGLES,0,1); // 3个点
// 3个顶点
// 0.0, 0.0, 0.0
// 0.2, 0.0, 0.0
// 0.4, 0.0, 0.0
gl.drawArrays(gl.POINTS,0,1);
gl.drawArrays(gl.LINES,1,2);
attribute 定义属性变量
作用: 动态传入顶点数据。
注意:attribute变量只能在顶点着色器中使用,不能在片元着色器中使用。
- 变量声明
- 顶点属性vec4的初始值是
0.0, 0.0, 0.0, 1.0
。 - 获取属性变量,
const aPosition = gl.getAttribLocation(program, 'aPosition');
。 - 设置属性变量值。
gl.vertexAttrib1f(aPosition, x)
。vertexAttrib[1|2|3|4]f
以设置vec4
对象的值,其他的值可以设置为默认值。
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
// 只传递顶点数据
attribute vec4 aPosition;
void main() {
gl_Position = aPosition; // vec4(0.0,0.0,0.0,1.0)
gl_PointSize = 30.0;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
// 可以省略默认值
// gl.vertexAttrib4f(aPosition, 0.5,0.5,0.0,1.0)
// gl.vertexAttrib3f(aPosition, 0.5,0.5,0.0)
// gl.vertexAttrib2f(aPosition, 0.5,0.5)
let x = 0;
setInterval(() => {
x += 0.1;
if (x > 1.0) {
x = 0;
}
gl.vertexAttrib1f(aPosition, x)
gl.drawArrays(gl.POINTS, 0, 1);
}, 200)
uniform 定义属性变量
- 在片元着色器中使用
uniform
必须设置精度,片元着色器中未设置精度,顶点着色器中默认设置了高精度。
precision mediump float; // 必须设置精度
// 还有高精度, 低精度
⾼精度:highp, 低精度:lowp
- 声明变量
uniform vec2 uColor;
这里的变量类型和下面赋值的时候是对应的。 gl.uniform2f(uColor,points[i].clickX,points[i].clickY)
,gl.vertexAttrib2f(aPosition,points[i].clickX,points[i].clickY)
。- 注意我们再设置坐标的范围时,必须是[-1, 1]之间的,所以在计算鼠标的移动位置时,需要做缩放处理。
注意着色器变量只能接收vce4
类型变量。所以对于片元着色器我们可以设置片元着色器为其他类型(float, vce2, vce3)但是我们可以这样动态设置vce4的值。
gl_FragColor = vec4(uColor.r, uColor.g, 0.0,1.0); // vec4
如果使用uniform1f()
赋值的话,我们只能通过float去定义变量类型。并且vec4中直接获取变量即可。
uniform float uColor; // 这里定义的vec和下面的赋值需要对应。
void main() {
gl_FragColor = vec4(uColor, 0.0, 0.0,1.0); // vec4
}
const ctx=document.getElementById('canvas')
const gl=ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE=`
uniform vec4 uPosition; // 虽然可以用在定点着色器中,但是他不能传递顶点数据。这个是对所有的顶点都生效的。但是对于顶点来说每个坐标都是不一样的。
// 只传递顶点数据
attribute vec4 aPosition; // 默认是高精度
void main() {
gl_Position = aPosition; // vec4(0.0,0.0,0.0,1.0)
gl_PointSize = 10.0;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE=`
precision mediump float; // 必须设置精度
uniform vec2 uColor; // 这里定义的vec和下面的赋值需要对应。
void main() {
gl_FragColor = vec4(uColor.r, uColor.g, 0.0,1.0); // vec4
}
`; // 片元着色器
const program=initShader(gl,VERTEX_SHADER_SOURCE,FRAGMENT_SHADER_SOURCE)
const aPosition=gl.getAttribLocation(program,'aPosition');
const uColor=gl.getUniformLocation(program,'uColor')
const points=[]
ctx.onclick=function(ev) {
// 坐标
const x=ev.clientX
const y=ev.clientY
const domPosition=ev.target.getBoundingClientRect();
const domx=x-domPosition.left
const domy=y-domPosition.top;
/*
0 200 400
-1 0 1
-200 0 200
-1 0 1
需要先 -200 (当前画布的宽度) 然后再 除以 200
1 0 -1
0 200 400
200 0 -200 / 200
需要先让 200 减这个数,然后再 / 200
* */
const halfWidth=ctx.offsetWidth/2
const halfHeight=ctx.offsetHeight/2
// [-1, 1]
const clickX=(domx-halfWidth)/halfWidth
// [1, -1]
const clickY=(halfHeight-domy)/halfHeight
points.push({
clickX,clickY
})
for(let i=0;i<points.length;i++) {
gl.vertexAttrib2f(aPosition,points[i].clickX,points[i].clickY)
gl.uniform2f(uColor,points[i].clickX,points[i].clickY)
gl.drawArrays(gl.POINTS,0,1);
}
}
图形移动
通过着色器让图形移动
我们可以定义一个attribute属性,让顶点各个轴的上值加上这个属性对应的值就行。间接去修改顶点属性。
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
// 定义一个属性
attribute float aTranslate;
void main() {
// 让对应位置的值加上偏移属性即可
gl_Position = vec4(aPosition.x + aTranslate, aPosition.y, aPosition.z, 1.0);
gl_PointSize = 10.0;
}
`; // 顶点着色器
// 不断改变aTranslate的值即可。
let x = -1;
setInterval(() => {
x += 0.01;
if (x > 1) {
x = -1;
}
gl.vertexAttrib1f(aTranslate, x);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}, 60)
完整代码
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
attribute float aTranslate;
void main() {
gl_Position = vec4(aPosition.x + aTranslate, aPosition.y, aPosition.z, 1.0);
gl_PointSize = 10.0;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
const aTranslate = gl.getAttribLocation(program, 'aTranslate');
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPosition)
let x = -1;
setInterval(() => {
x += 0.01;
if (x > 1) {
x = -1;
}
gl.vertexAttrib1f(aTranslate, x);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}, 60)
通过平移矩阵让图形移动
我们可以定义一个uniform属性,让顶点属性乘以该uniform属性即可。这里定义uniform的目的是让其作用于所有顶点。
定义一个平移矩阵函数
// 平移矩阵
function getTranslateMatrix(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,
])
}
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
uniform mat4 mat; // 平移时需要平移三角形的所有顶点,所以使用uniform属性
void main() {
gl_Position = mat * aPosition;
gl_PointSize = 10.0;
}
`; // 顶点着色器
let x = -1;
function animation() {
x += 0.01;
if (x > 1) {
x = -1;
}
// 获取平移矩阵数据
const matrix = getTranslateMatrix(x, x);
// 赋值uniform属性
gl.uniformMatrix4fv(mat, false, matrix);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(animation);
}
animation()
完整代码
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
uniform mat4 mat; // 平移时需要平移三角形的所有顶点,所以使用uniform属性
void main() {
gl_Position = mat * aPosition;
gl_PointSize = 10.0;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
const mat = gl.getUniformLocation(program, 'mat');
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPosition)
let x = -1;
function animation() {
x += 0.01;
if (x > 1) {
x = -1;
}
const matrix = getTranslateMatrix(x, x);
gl.uniformMatrix4fv(mat, false, matrix);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(animation);
}
animation()
图形缩放
通过着色器让图形缩放
我们依旧是定义一个attribute属性,让顶点各个轴的上值乘上这个属性对应的值就行。间接去修改顶点属性。
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
// 定义缩放属性
attribute float aScale;
void main() {
// 处理顶点数据
gl_Position = vec4(aPosition.x * aScale, aPosition.y * aScale, aPosition.z * aScale, 1.0);
gl_PointSize = 10.0;
}
`; // 顶点着色器
let x = 1;
setInterval(() => {
x += 0.1;
if (x > 2) {
x = 1;
}
// 修改缩放属性
gl.vertexAttrib1f(aScale, x);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}, 60)
完整代码
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
attribute float aScale;
void main() {
gl_Position = vec4(aPosition.x * aScale, aPosition.y * aScale, aPosition.z * aScale, 1.0);
gl_PointSize = 10.0;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
const aScale = gl.getAttribLocation(program, 'aScale');
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPosition)
let x = 1;
setInterval(() => {
x += 0.1;
if (x > 2) {
x = 1;
}
gl.vertexAttrib1f(aScale, x);
gl.drawArrays(gl.TRIANGLES, 0, 3);
}, 60)
通过缩放矩阵让图形缩放
就是需要定义一个缩放矩阵。方式同平移矩阵。
// 缩放矩阵
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,
])
}
完整代码
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
uniform mat4 mat; // 类型为mat4
void main() {
gl_Position = mat * aPosition;
gl_PointSize = 10.0;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
const mat = gl.getUniformLocation(program, 'mat');
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPosition)
// 缩放矩阵
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,
])
}
let x = 0.1;
function animation() {
x += 0.01;
if (x > 1.5) {
x = 0.1;
}
const matrix = getScaleMatrix(x, x);
/***
* gl.uniformMatrix4fv(location, transpose, array)
*
* - location: 指定 uniform 变量的存储位置
* - transpose: 在 webgl 中恒为false
* - array: 矩阵数组
*
**/
gl.uniformMatrix4fv(mat, false, matrix);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(animation);
}
animation()
图形旋转
通过着色器让图形旋转
通过对顶点各个分量乘以对应的三角函数,就可以实现。
// 创建着色器源码
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;
}
`; // 顶点着色器
let x = 1;
function animation() {
x += -0.01;
gl.vertexAttrib1f(deg, x);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(animation)
}
animation();
完整代码
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
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;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
const deg = gl.getAttribLocation(program, 'deg');
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPosition)
let x = 1;
function animation() {
x += -0.01;
gl.vertexAttrib1f(deg, x);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(animation)
}
animation();
通过旋转矩阵让图形旋转
首先需要定义一个旋转矩阵
// 绕z轴旋转的旋转矩阵
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,
])
}
完整代码
const ctx = document.getElementById('canvas')
const gl = ctx.getContext('webgl')
// 创建着色器源码
const VERTEX_SHADER_SOURCE = `
attribute vec4 aPosition;
uniform mat4 mat;
void main() {
gl_Position = mat * aPosition;
gl_PointSize = 10.0;
}
`; // 顶点着色器
const FRAGMENT_SHADER_SOURCE = `
void main() {
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
`; // 片元着色器
const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)
const aPosition = gl.getAttribLocation(program, 'aPosition');
const mat = gl.getUniformLocation(program, 'mat');
const points = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5,
])
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(aPosition)
// 绕z轴旋转的旋转矩阵
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,
])
}
let x = 0;
function animation() {
x += 0.01;
const matrix = getRotateMatrix(x);
// gl.vertexAttrib1f(aTranslate, x);
gl.uniformMatrix4fv(mat, false, matrix);
gl.drawArrays(gl.TRIANGLES, 0, 3);
requestAnimationFrame(animation);
}
animation()