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>
相关推荐
Mapmost19 小时前
【从零打造视觉盛宴・风格篇】私藏技巧:如何把普通场景做成高级感爆棚的创意作品?
webgl·数据可视化·虚拟现实
伶俜monster21 小时前
Threejs 奇幻几何体:边缘、线框、包围盒大冒险
前端·webgl·three.js
伶俜monster5 天前
破解旋转死锁:Threejs 四元数魔法对抗欧拉角困局
前端·webgl·three.js
猿儿本无心7 天前
WebGL数学手记:矩阵基础
线性代数·矩阵·webgl
爱看书的小沐8 天前
【小沐学Web3D】three.js 加载三维模型(Angular)
前端·javascript·vue·webgl·three.js·angular.js·opengl
伶俜monster8 天前
向量密码本:Threejs 用加减乘除驯服 3D 空间
webgl·three.js
爱看书的小沐9 天前
【小沐学Web3D】three.js 加载三维模型(React Three Fiber)
javascript·react.js·webgl·three.js·opengl·web3d·reactthreefiber