webgl创建最基础的三种图元点,线,三角(vue3)

bx2eq6ulg18.feishu.cn/docx/I4hTdO...(青牛老师的入门教程文档)

基础封装:

scss 复制代码
const initShader = (gl, vShader, fShader) => {
  /**
   * gl:webgl上下文对象
   * vShader:顶点着色器源码
   * fShader:片元着色器源码
   */
  // 创建着色器对象
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
  // 为着色器对象赋值
  gl.shaderSource(vertexShader, vShader);
  gl.shaderSource(fragmentShader, fShader);
  // 编译着色器
  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;
​
}
export default initShader;
图元--点:
ini 复制代码
<template>
  <div>
    <canvas class="canvas" width="500" height="500"></canvas>
  </div>
</template>
​
<script setup>
import { onMounted } from "vue";
import initShader from "@/hooks/initShader";
const initCnavas = () => {
  const canvas = document.querySelector(".canvas");
  //获取webgl三维上下文对象
  const gl = canvas.getContext("webgl");
  //定义顶点着色器
  const vertexShader = `
    attribute vec4 a_Position;
    void main()   {
       gl_Position =a_Position;
       gl_PointSize = 10.0;
    }`;
  //定义片元着色器
  const fragmentShader = `
    void main(){
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }`;
  //创建程序对象
  const program = initShader(gl, vertexShader, fragmentShader);
  //创建缓冲区对象
  const buffer = gl.createBuffer();
  //绑定缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  //定义顶点数据
  const points = new Float32Array([0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5]);
  //向缓冲区对象写入数据
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
  //查询a_Position变量的索引位置
  const a_Position = gl.getAttribLocation(program, "a_Position");
  //将缓冲区对象分配给a_Position变量
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  //启用a_Position变量
  gl.enableVertexAttribArray(a_Position);
  //绘制图元--点
  gl.drawArrays(gl.POINTS, 0, 4);
};
onMounted(() => {
  initCnavas();
});
</script>
​
<style scoped>
.canvas {
  border: 1px solid #000;
}
</style>
图元--线:
xml 复制代码
<template>
  <div>
    <canvas class="canvas" width="500" height="500"></canvas>
  </div>
</template>
​
<script setup>
import { onMounted } from "vue";
import initShader from "@/hooks/initShader";
const initCnavas = () => {
  const canvas = document.querySelector(".canvas");
  //获取webgl三维上下文对象
  const gl = canvas.getContext("webgl");
  //定义顶点着色器
  const vertexShader = `
    attribute vec4 a_Position;
    void main()   {
       gl_Position =a_Position;
       gl_PointSize = 10.0;
    }`;
  //定义片元着色器
  const fragmentShader = `
    void main(){
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }`;
  //创建程序对象
  const program = initShader(gl, vertexShader, fragmentShader);
  //创建缓冲区对象
  const buffer = gl.createBuffer();
  //绑定缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  //定义顶点数据
  const points = new Float32Array([0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5]);
  //向缓冲区对象写入数据
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
  //查询a_Position变量的索引位置
  const a_Position = gl.getAttribLocation(program, "a_Position");
  //将缓冲区对象分配给a_Position变量
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  //启用a_Position变量
  gl.enableVertexAttribArray(a_Position);
  //绘制图元--不连接的线段
  gl.drawArrays(gl.LINES, 0, 4);
  //绘制图元--连接的线段
  // gl.drawArrays(gl.LINE_STRIP, 0, 4);
  //绘制图元--闭环线段
  // gl.drawArrays(gl.LINE_LOOP, 0, 4);
};
onMounted(() => {
  initCnavas();
});
</script>
​
<style scoped>
.canvas {
  border: 1px solid #000;
}
</style>
图元--三角
ini 复制代码
<template>
  <div>
    <canvas class="canvas" width="500" height="500"></canvas>
  </div>
</template>
​
<script setup>
import { onMounted } from "vue";
import initShader from "@/hooks/initShader";
const initCnavas = () => {
  const canvas = document.querySelector(".canvas");
  //获取webgl三维上下文对象
  const gl = canvas.getContext("webgl");
  //定义顶点着色器
  const vertexShader = `
    attribute vec4 a_Position;
    void main()   {
       gl_Position =a_Position;
       gl_PointSize = 10.0;
    }`;
  //定义片元着色器
  const fragmentShader = `
    void main(){
      gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    }`;
  //创建程序对象
  const program = initShader(gl, vertexShader, fragmentShader);
  //创建缓冲区对象
  const buffer = gl.createBuffer();
  //绑定缓冲区对象
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  //定义顶点数据
  const points = new Float32Array([
    0.5, 0.5, 0.5, -0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5,
  ]);
  //向缓冲区对象写入数据
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
  //查询a_Position变量的索引位置
  const a_Position = gl.getAttribLocation(program, "a_Position");
  //将缓冲区对象分配给a_Position变量
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  //启用a_Position变量
  gl.enableVertexAttribArray(a_Position);
  //绘制图元--三角
  gl.drawArrays(gl.TRIANGLES, 0, 3);
};
onMounted(() => {
  initCnavas();
});
</script>
​
<style scoped>
.canvas {
  border: 1px solid #000;
}
</style>
衍生:
镂空立方体:

由图元线--段衍生,两个闭合线段搭配四个不连接线段拼接形成

ini 复制代码
<template>
  <div><canvas width="500" height="500" class="canvas"></canvas></div>
</template>
​
<script setup>
import { onMounted } from "vue";
import initShader from "@/hooks/initShader";
const initCanvas = () => {
  const canvas = document.querySelector(".canvas");
  const gl = canvas.getContext("webgl");
  /**
   * radin:旋转角度
   * cos:旋转角度的余弦值
   * sin:旋转角度的正弦值
   * mx:绕X轴旋转矩阵
   * my:绕Y轴旋转矩阵
   */
  const vertexShader = `
  attribute vec4 a_Position;
  void main(){
     float radin = radians(10.0);
     float cos = cos(radin);
     float sin = sin(radin);
     mat4 mx = mat4(
      1.0,0.0,0.0,0.0,
      0.0,cos,sin,0.0,
      0.0,-sin,cos,0.0,
      0.0,0.0,0.0,1.0);
      mat4 my = mat4(
       cos,0.0,-sin,0.0,
       0.0,1.0,0.0,0.0,
       sin,0.0,cos,0.0,
       0.0,0.0,0.0,1.0);
    gl_Position = my*mx*a_Position;
    gl_PointSize = 10.0;
  }
  `;
  const fragmentShader = `
  void main(){
    gl_FragColor = vec4(1.0,0.0,0.0,1.0);
  }`;
  const program = initShader(gl, vertexShader, fragmentShader);
  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  const points = new Float32Array([
    //第一面的四个点
    0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5,
    //第二面的四个点
    0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5,
    //连接两个面的八个点
    0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, -0.5, -0.5,
    0.5, -0.5, -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,
  ]);
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(program, "a_Position");
  gl.vertexAttribPointer(
    a_Position,
    3,
    gl.FLOAT,
    false,
    3 * Float32Array.BYTES_PER_ELEMENT,
    0
  );
  gl.enableVertexAttribArray(a_Position);
  //绘制第一个面的四个点和连线
  gl.drawArrays(gl.POINTS, 0, 4);
  gl.drawArrays(gl.LINE_LOOP, 0, 4);
  //绘制第二个面的四个点和连线
  gl.drawArrays(gl.POINTS, 4, 4);
  gl.drawArrays(gl.LINE_LOOP, 4, 4);
  //绘制两个面的连接线
  gl.drawArrays(gl.LINES, 8, 8);
};
onMounted(() => {
  initCanvas();
});
</script>
带颜色立方体:

由图元线--三角衍生,12个三角拼接而成

ini 复制代码
<template>
  <div>
    <canvas class="canvas" width="500" height="500"></canvas>
  </div>
</template>
​
<script setup>
import { onMounted } from "vue";
import initShader from "@/hooks/initShader";
//搭建一个每个面不同颜色的立方体
const initCanvas = () => {
  const canvas = document.querySelector(".canvas");
  const gl = canvas.getContext("webgl");
  const vertexShader = `
    attribute vec4 a_Position;
    uniform mat4 u_x_ModelMatrix;
    uniform mat4 u_y_ModelMatrix;
    void main(){
      gl_Position = u_y_ModelMatrix*u_x_ModelMatrix*a_Position;
      gl_PointSize = 10.0;
    }`;
  const fragmentShader = `
    precision mediump float;
    uniform vec4 u_FragColor;
    void main(){
      gl_FragColor = u_FragColor;
    }`;
  const program = initShader(gl, vertexShader, fragmentShader);
  const u_FragColor = gl.getUniformLocation(program, "u_FragColor");
  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  //每个面的四个点
  const points = new Float32Array([
    0.5, 0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5,
    -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5,
  ]);
  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(program, "a_Position");
  gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);
  //每个面的两个三角形(索引缓冲区)
  const indexData = new Uint16Array([
    0, 1, 2, 0, 3, 2, 4, 5, 6, 4, 7, 6, 0, 1, 5, 0, 4, 5, 3, 2, 6, 3, 7, 6, 0,
    3, 7, 0, 4, 7, 1, 2, 6, 1, 5, 6,
  ]);
  const indexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indexData, gl.STATIC_DRAW);
  gl.enable(gl.DEPTH_TEST); //开启深度测试
  /**
   * deg:旋转角度
   * radin:旋转角度的弧度值
   * cos:旋转角度的余弦值
   * sin:旋转角度的正弦值
   * x_ModelMatrixValue:绕X轴旋转矩阵
   * y_ModelMatrixValue:绕Y轴旋转矩阵
   * requestAnimationFrame:请求动画帧
   * 为了能更好的看到每个面的颜色,使用requestAnimationFrame来实现旋转动画效果
   */
  let deg = 30.0;
  function render() {
    deg += 0.1;
    const radin = (Math.PI / 180) * deg;
    const cos = Math.cos(radin);
    const sin = Math.sin(radin);
    const u_x_ModelMatrix = gl.getUniformLocation(program, "u_x_ModelMatrix");
    const u_y_ModelMatrix = gl.getUniformLocation(program, "u_y_ModelMatrix");
    const x_ModelMatrixValue = new Float32Array([
      1.0,
      0.0,
      0.0,
      0.0,
      0.0,
      cos,
      -sin,
      0.0,
      0.0,
      sin,
      cos,
      0.0,
      0.0,
      0.0,
      0.0,
      1.0,
    ]);
    const y_ModelMatrixValue = new Float32Array([
      cos,
      0.0,
      -sin,
      0.0,
      0.0,
      1.0,
      0.0,
      0.0,
      sin,
      0.0,
      cos,
      0.0,
      0.0,
      0.0,
      0.0,
      1.0,
    ]);
    gl.uniformMatrix4fv(u_x_ModelMatrix, false, x_ModelMatrixValue);
    gl.uniformMatrix4fv(u_y_ModelMatrix, false, y_ModelMatrixValue);
    //fragmentListColor:每个面的颜色
    const fragmentListColor = [
      [0.0, 0.0, 0.0, 1.0],
      [0.0, 0.0, 1.0, 1.0],
      [1.0, 0.0, 0.0, 1.0],
      [1.0, 1.0, 0.0, 1.0],
      [1.0, 0.5, 0.0, 1.0],
      [1.0, 0.0, 0.5, 1.0],
    ];
    for (let i = 0; i < 6; i++) {
      gl.uniform4fv(u_FragColor, new Float32Array(fragmentListColor[i]));
      gl.drawElements(
        gl.TRIANGLES,
        6,
        gl.UNSIGNED_SHORT,
        i * 6 * Uint16Array.BYTES_PER_ELEMENT
      );
    }
    window.requestAnimationFrame(render);
  }
  window.requestAnimationFrame(render);
};
​
onMounted(() => {
  initCanvas();
});
</script>
​
<style lang="scss" scoped>
</style>
相关推荐
光影少年13 小时前
WebGIS 和GIS学习路线图
学习·前端框架·webgl
DBBH16 小时前
Cesium源码分析之渲染3DTile的一点思考
图形渲染·webgl·cesium.js
Robet1 天前
TS2d渲染引擎
webgl
Robet2 天前
WebGL2D渲染引擎
webgl
goodName3 天前
如何实现精准操控?Cesium模型移动旋转控件实现
webgl·cesium
丫丫7237345 天前
Three.js 模型树结构与节点查询学习笔记
javascript·webgl
allenjiao7 天前
WebGPU vs WebGL:WebGPU什么时候能完全替代WebGL?Web 图形渲染的迭代与未来
前端·图形渲染·webgl·threejs·cesium·webgpu·babylonjs
mapvthree8 天前
mapvthree Engine 设计分析——二三维一体化的架构设计
webgl·数字孪生·mapvthree·jsapi2d·jsapigl·引擎对比
GISer_Jing9 天前
3D Cesium渲染架剖析
javascript·3d·webgl
Swift社区9 天前
用 Chrome DevTools 深度分析 Vue WebGL 内存泄漏(进阶篇)
vue.js·webgl·chrome devtools