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>
相关推荐
esmap8 小时前
技术深度解析:ESMap引擎VS主流数字孪生竞品
人工智能·物联网·3d·编辑器·智慧城市·webgl
GISer_Jing2 天前
WebGL跨端兼容实战:移动端适配全攻略
前端·aigc·webgl
Aurora@Hui4 天前
WebGL & Three.js
webgl
CC码码7 天前
基于WebGPU实现canvas高级滤镜
前端·javascript·webgl·fabric
ct9787 天前
WebGL 图像处理核心API
图像处理·webgl
ct9789 天前
Cesium 矩阵系统详解
前端·线性代数·矩阵·gis·webgl
ct97811 天前
WebGL Shader性能优化
性能优化·webgl
棋鬼王12 天前
Cesium(一) 动态立体墙电子围栏,Wall墙体瀑布滚动高亮动效,基于Vue3
3d·信息可视化·智慧城市·webgl
Longyugxq14 天前
Untiy的Webgl端网页端视频播放,又不想直接mp4格式等格式的。
unity·音视频·webgl
花姐夫Jun15 天前
cesium基础学习-坐标系统相互转换及相应的场景
学习·webgl