异步绘制线段
1.先画一个点
2.一秒钟后,在左下角画一个点
3.两秒钟后,我再画一条线段
<!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 id="webgl" width="200" height="200"></canvas><script>const webgl = document.getElementById('webgl')const gl = webgl.getContext('webgl')// 创建着色器const vertexShader = gl.createShader(gl.VERTEX_SHADER)const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)// 绑定数据源// 声明顶点着色器 attribute 变量gl.shaderSource(vertexShader, `attribute vec4 a_Position;void main(){gl_Position = a_Position;gl_PointSize = 20.0;}`)gl.shaderSource(fragmentShader, `void main(){gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}`)// 编译着色器gl.compileShader(vertexShader)gl.compileShader(fragmentShader)// 创建着色器程序const program = gl.createProgram()// 绑定着色器gl.attachShader(program, vertexShader)gl.attachShader(program, fragmentShader)// 连接着色器gl.linkProgram(program)// 使用着色器gl.useProgram(program)// 顶点数据let points = [0, 0.2]// 创建缓冲区const vertexBuffer = gl.createBuffer()// 绑定缓冲区 // target 要把缓冲区放在webgl系统中的什么位置, buffer 缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)// 写入数据gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW)// 获取到顶点着色器中变量const a_Position = gl.getAttribLocation(program, 'a_Position')// 从当前绑定的缓冲区中读取顶点数据(index, size, type, normalized是否顶点数据归一, stride相邻两个顶点间的字节数, offset从缓冲区的什么位置开始存储变量)gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)// 开启顶点数据的批处理功能gl.enableVertexAttribArray(a_Position)gl.drawArrays(gl.POINTS, 0, 1);// 一秒钟后,向顶点数据中再添加的一个顶点,修改缓冲区数据,然后清理画布,绘制顶点setTimeout(() => {points.push(-0.2, -0.1)gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(points), gl.STATIC_DRAW)gl.drawArrays(gl.POINTS, 0, 2);}, 1000)// 两秒钟后,清理画布,绘制顶点,绘制线条setTimeout(() => {gl.drawArrays(gl.POINTS, 0, 2);gl.drawArrays(gl.LINE_STRIP, 0, 2);}, 2000)</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 id="webgl" width="200" height="200"></canvas><script>const webgl = document.getElementById('webgl')const gl = webgl.getContext('webgl')// 创建着色器const vertexShader = gl.createShader(gl.VERTEX_SHADER)const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)// 绑定数据源// 声明顶点着色器 attribute 变量gl.shaderSource(vertexShader, `attribute vec4 a_Position;void main(){gl_Position = a_Position;gl_PointSize = 20.0;}`)gl.shaderSource(fragmentShader, `void main(){gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}`)// 编译着色器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 defAttr = () => ({gl: null,vertices: [],geoData: [],size: 2,attrName: 'a_Position',count: 0,types: ['POINTS'],})class Poly {constructor(attr) {Object.assign(this, defAttr(), attr)this.init()}init() {const { attrName, size, gl } = thisif (!gl) { return }const vertexBuffer = gl.createBuffer()gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)this.updateBuffer()const a_Position = gl.getAttribLocation(program, attrName)gl.vertexAttribPointer(a_Position, size, gl.FLOAT, false, 0, 0)gl.enableVertexAttribArray(a_Position)}addVertice(...params) {this.vertices.push(...params)this.updateBuffer()}popVertice() {const { vertices, size } = thisconst len = vertices.lengthvertices.splice(len - size, len)this.updateCount()}setVertice(ind, ...params) {const { vertices, size } = thisconst i = ind * sizeparams.forEach((param, paramInd) => {vertices[i + paramInd] = param})}updateBuffer() {const { gl, vertices } = thisthis.updateCount()gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)}updateCount() {this.count = this.vertices.length / this.size}updateVertices(params) {const { geoData } = thisconst vertices = []geoData.forEach(data => {params.forEach(key => {vertices.push(data[key])})})this.vertices = vertices}draw(types = this.types) {const { gl, count } = thisfor (let type of types) {gl.drawArrays(gl[type], 0, count);}}}const poly = new Poly({gl,vertices: [0, 0.2]})poly.draw(['POINTS'])setTimeout(() => {poly.addVertice(-0.2, -0.1)poly.draw(['POINTS'])}, 1000)setTimeout(() => {poly.draw(['POINTS', 'LINE_STRIP'])}, 2000)</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 id="webgl"></canvas><script>const webgl = document.getElementById('webgl')webgl.width = window.innerWidthwebgl.height = window.innerHeightconst gl = webgl.getContext('webgl')// 创建着色器const vertexShader = gl.createShader(gl.VERTEX_SHADER)const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)// 绑定数据源// 声明顶点着色器 attribute 变量gl.shaderSource(vertexShader, `attribute vec4 a_Position;void main(){gl_Position = a_Position;gl_PointSize = 20.0;}`)gl.shaderSource(fragmentShader, `void main(){gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);}`)// 编译着色器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 defAttr = () => ({gl: null,vertices: [],geoData: [],size: 2,attrName: 'a_Position',count: 0,types: ['POINTS'],})class Poly {constructor(attr) {Object.assign(this, defAttr(), attr)this.init()}init() {const { attrName, size, gl } = thisif (!gl) { return }const vertexBuffer = gl.createBuffer()gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)this.updateBuffer()const a_Position = gl.getAttribLocation(program, attrName)gl.vertexAttribPointer(a_Position, size, gl.FLOAT, false, 0, 0)gl.enableVertexAttribArray(a_Position)}addVertice(...params) {this.vertices.push(...params)this.updateBuffer()}popVertice() {const { vertices, size } = thisconst len = vertices.lengthvertices.splice(len - size, len)this.updateCount()}setVertice(ind, ...params) {const { vertices, size } = thisconst i = ind * sizeparams.forEach((param, paramInd) => {vertices[i + paramInd] = param})}updateBuffer() {const { gl, vertices } = thisthis.updateCount()gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW)}updateCount() {this.count = this.vertices.length / this.size}updateVertices(params) {const { geoData } = thisconst vertices = []geoData.forEach(data => {params.forEach(key => {vertices.push(data[key])})})this.vertices = vertices}draw(types = this.types) {const { gl, count } = thisfor (let type of types) {gl.drawArrays(gl[type], 0, count);}}}const poly = new Poly({gl,types: ['POINTS', 'LINE_STRIP']})webgl.addEventListener('click', (e) => {// 获取鼠标距离视口尺寸的距离const { clientX, clientY } = e// 获取cavans坐标宽高,距离视口尺寸的距离const { left, top, width, height } = webgl.getBoundingClientRect()// 鼠标在canvas中的位置const [cssX, cssY] = [clientX - left, clientY - top]// canvas坐标转webgl坐标// canvas画布的中心位置const [halfWidth, halfHeight] = [width / 2, height / 2]// 鼠标基于webgl坐标的中心位置const [xBaseCenter, yBaseCenter] = [cssX - halfWidth, cssY - halfHeight]// 解决y方向的差异const yBaseCenterTop = -yBaseCenter// 解决坐标基底的差异const [x, y] = [xBaseCenter / halfWidth, yBaseCenterTop / halfHeight]poly.addVertice(x, y)poly.draw()})</script>
</body></html>