WebGL绘图应用案例

226 阅读1分钟
WebGL动态绘制正多边形和正多角形
将WebGL绘图底层逻辑进行封装,引入vue项目

glsl.config.js文件

// 使用webgl绘制三角形
// canvas是画布,pointArr绘制的点数据
export const webglFunction = (canvas, pointArr) => {
  // 1创建webgl上下文
  const webgl = canvas.getContext('webgl')
  // 2创建webgl程序
  // 创建顶点着色器和片元着色器
  // 声明变量,类型为vec2(二维向量) 变量名
  // GLSL编程语言
  // 通过 gl_Position 设置顶点
  // 顶点着色器
  const vertex = `attribute vec2 position;
                  varying vec3 color;
                  void main() {
                      gl_PointSize = 1.0;
                      color = vec3(0.5 + position * 0.5, 0.0);
                      gl_Position = vec4(position * 0.5, 1.0, 1.0);
                  }`
  // // 通过 gl_Position 设置顶点
  // // 片元着色器
  const fragment = `precision mediump float;
                    varying vec3 color;
                    void main() {
                        gl_FragColor = vec4(color, 1.0);
                    }`

  const vertexShader = webgl.createShader(webgl.VERTEX_SHADER)
  webgl.shaderSource(vertexShader, vertex)
  webgl.compileShader(vertexShader)

  const fragmentShader = webgl.createShader(webgl.FRAGMENT_SHADER)
  webgl.shaderSource(fragmentShader, fragment)
  webgl.compileShader(fragmentShader)

  // 创建 WebGLProgram 对象,并将vertexShader和fragmentShader关联到webgl程序上
  const program = webgl.createProgram()
  webgl.attachShader(program, vertexShader)
  webgl.attachShader(program, fragmentShader)
  // 并将WebGLProgram 对象链接到webgl上下文
  webgl.linkProgram(program)
  // 启用WebGLProgram对象,在绘制图形时,gpu会自动去执行WebGLProgram对象设定的两个shader
  webgl.useProgram(program)
  // 3将数据存入缓冲区
  const points = pointArr

  // 创建一个缓存对象
  const bufferId = webgl.createBuffer()
  webgl.bindBuffer(webgl.ARRAY_BUFFER, bufferId)
  // 把当前数据写入缓存对象
  webgl.bufferData(webgl.ARRAY_BUFFER, points, webgl.STATIC_DRAW)
  // 4将缓冲区数据读取到gpu上
  // 获取顶点着色器中的position变量的地址
  const vPosition = webgl.getAttribLocation(program, 'position')
  // 给变量设置长度和类型
  webgl.vertexAttribPointer(vPosition, 2, webgl.FLOAT, false, 0, 0)
  // 激活这个变量
  webgl.enableVertexAttribArray(vPosition)
  // 5执行着色器程序完成绘制
  // 将当前画布的内容清除
  webgl.clear(webgl.COLOR_BUFFER_BIT)
  // 传入绘制模式,以三角形为图元绘制,再传入绘制的顶点偏移量和顶点数量
  webgl.drawArrays(webgl.TRIANGLE_FAN, 0, points.length / 2)
}
一、实现正多边形绘制
实现思路

image

<template>
  <h4>WebGL绘图实现正多边形</h4>
          <a-form layout="inline" :form="form" class="form">
            <a-form-item label='正多边形的边数'>
              <a-input-number v-decorator="[
                  'count',
                  {
                    initialValue: count,
                    rules: [{ required: true, message: 'count不能为空' }]
                  }
                ]"
                :min="3"
                :step="1">
              </a-input-number>
            </a-form-item>
            <a-form-item  label='半径长度'>
              <a-input-number v-decorator="[
                  'length',
                  {
                    initialValue: length,
                    rules: [{ required: true, message: 'length不能为空' }]
                  },
                ]"
                :min="0.5"
                :max="2"
                :step="0.1">
              </a-input-number>
            </a-form-item>
            <a-form-item>
              <a-button type="primary" ghost @click="product"  html-type="submit">
                生成正多边形
              </a-button>
            </a-form-item>
          </a-form>
        <canvas width="400" height="400" class="webgl"></canvas>
</template>
	<script>
import { webglFunction } from './glsl.config'

export default {
  name: 'WebGL',
  props: {

  },
  components: {

  },
  data () {
    return {
      canvas: null,
      count: 3,
      length: 0.5,
      form: this.$form.createForm(this, { name: 'input' }),
    }
  },
  created () {

  },
  mounted () {
    // 1创建webgl上下文
    this.canvas = document.getElementsByClassName('webgl')[0]
    this.webglRender()
  },
  watch: {

  },
  methods: {
    // 使用webgl绘制三角形
    webglRender () {
      webglFunction(this.canvas, new Float32Array([-1, -1, 0, 1, 1, -1]))
    },
    // 生成指定规格的正多边形
    product () {
      const points = []
      const { count, length } = this.form.getFieldsValue()
      for (let i = 0; i < count; i++) {
        const deg = Math.PI * 2 * i / count
        const x = Math.cos(deg) * length
        const y = Math.sin(deg) * length
        points.push(x, y)
      }
      webglFunction(this.canvas, new Float32Array(points))
    }
  }
}
</script>

实现效果图

image

二、实现正多角形绘制
实现思路

image

<template>
   <h4>WebGL绘图实现正多角形</h4>
          <a-form layout="inline" :form="formStart" class="form">
            <a-form-item label='正多角形的角数'>
              <a-input-number v-decorator="[
                  'countStart',
                  {
                    initialValue: countStart,
                    rules: [{ required: true, message: 'countStart不能为空' }]
                  }
                ]"
                :min="5"
                :step="1">
              </a-input-number>
            </a-form-item>
            <a-form-item  label='正多角形半径'>
              <a-input-number v-decorator="[
                  'lengthStart',
                  {
                    initialValue: lengthStart,
                    rules: [{ required: true, message: 'lengthStart不能为空' }]
                  },
                ]"
                :min="0.5"
                :max="2"
                :step="0.1">
              </a-input-number>
            </a-form-item>
            <a-form-item>
              <a-button type="primary" ghost @click="productStart"  html-type="submit">
                生成正多角形
              </a-button>
            </a-form-item>
          </a-form>
        <canvas width="400" height="400" class="webglStart"></canvas>
</template>
<script>
import { webglFunction } from './glsl.config'

export default {
  name: 'WebGL',
  props: {

  },
  components: {

  },
  data () {
    return {
      webglStart: null,
      countStart: 5,
      lengthStart: 0.5,
      formStart: this.$form.createForm(this, { name: 'inputStart' })
    }
  },
  created () {

  },
  mounted () {
    // 1创建webgl上下文
    this.webglStart = document.getElementsByClassName('webglStart')[0]
    if (this.webglStart) {
       this.productStart()
    }
  },
  watch: {

  },
  methods: {
    // 绘制正多角形
    productStart () {
      const points = [0, 0]
      const { countStart, lengthStart } = this.formStart.getFieldsValue()
      let x, y
      for (let i = 0; i <= countStart * 2; i++) {
        const degBig = Math.PI * 2 * i / (countStart * 2)
        if (i % 2) {
          x = Math.cos(degBig) * lengthStart
          y = Math.sin(degBig) * lengthStart
        } else {
          x = Math.cos(degBig) * lengthStart / 2
          y = Math.sin(degBig) * lengthStart / 2
        }
        points.push(x, y)
      }
      webglFunction(this.webglStart, new Float32Array(points))
    }
  }
}
</script>

实现效果图

image