WebGL利用缓冲区绘制三角和矩形(后附three.js写法)

本文介绍了WebGL中的三角形绘制方法,包括TRIANGLE_STRIP和TRIANGLE_FAN,以及如何使用attribute变量在顶点着色器中传输数据。同时,通过JavaScript代码展示了如何使用WebGLAPI和three.js库来创建和渲染几何图形。
摘要由CSDN通过智能技术生成

在这里插入图片描述

TRIANGLE_STRIP 三角带

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

TRIANGLE_FAN 三角扇

在这里插入图片描述
在这里插入图片描述
以上四个面得绘制顺序是:
v0>v1>v2
以上一个三角形的第三条边+下一个点为基础,按照和第三条边相反的顺序,绘制三角形
v0>v2>v3
同上
v0>v3>v4
同上
v0>v4>v5
同上

绘制矩形面

webgl可绘制的面只有三角面,要绘制矩形的话,只能用两个三角形去拼

在这里插入图片描述

什么是attribute 变量

它是一种存储限定符,表示定义一个attribute的全局变量,这种变量的数据将由外部向顶点着色器内传输,并保存顶点相关的数据,只有顶点着色器才能使用它
在这里插入图片描述

webgl 写法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas')
        canvas.width = window.innerWidth
        canvas.height = window.innerHeight
        const gl = canvas.getContext('webgl')
        // 第一次创建webgl绘图上下文,需要设置视口大小
        gl.viewport(0, 0, canvas.width, canvas.height)
        
        // 创建着色器
        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 vertices = new Float32Array([
        	//x, y
	        0.0, 0.5,
	        -0.5, -0.5,
	        0.5, -0.5
        ])
        // 创建缓冲区
        const vertexBuffer = gl.createBuffer()
        // 绑定缓冲区 
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
        // 写入数据(gl.STATIC_DRAW表示数据不会改变,gl.DYNAMIC_DRAW表示数据会改变)
        gl.bufferData(gl.ARRAY_BUFFER, vertices, 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, 3)
        // 闭合线条
       	// gl.drawArrays(gl.LINE_LOOP, 0, 3)
        // 单独三角形 (如果是正面,逆时针绘制, 实际引擎开发中用的最多,就是比较费点)
       	gl.drawArrays(gl.TRIANGLES, 0, 3) // gl.drawArrays(mode, first, count)
    </script>
</body>

</html>

LINES 单独线段(每2组一条线)

LINE_STRIP 线条 (线条相连,但首尾不相连)

在这里插入图片描述

three.js 写法

<template>
  <div></div>
</template>

<script setup>
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const scene = new THREE.Scene();

const geometry = new THREE.BufferGeometry()
const vertices = new Float32Array([
  //x, y
  -1.0, -1.0, 1.0,
  1.0, -1.0, 1.0,
  1.0, 1.0, 1.0,
  1.0, 1.0, 1.0,
  -1.0, 1.0, 1.0,
  -1.0, -1.0, 1.0,
])
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const mesh = new THREE.Mesh(geometry, cubeMaterial);
scene.add(mesh);

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 10);
// scene.add(camera);

const axesHelper = new THREE.AxesHelper(5); // 长度
scene.add(axesHelper);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight); //设置three.js渲染区域的尺寸(像素px)
document.body.appendChild(renderer.domElement);
renderer.render(scene, camera);

// 相机围绕目标进行轨道运动
const controls = new OrbitControls(camera, renderer.domElement);

function render(time) {
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
render()
</script>

随机生成三角形(50个)

在这里插入图片描述

<template>
  <div id="webgl"></div>
</template>

<script setup>
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const scene = new THREE.Scene();

for (let i = 0; i < 50; i++) {
  // 每一个三角形,需要3个顶点,每个顶点需要3个值
  const geometry = new THREE.BufferGeometry()
  const vertices = new Float32Array(9)
  for (let j = 0; j < 9; j++) {
    vertices[j] = Math.random() * 10 - 5 // -5到5之间的数
  }
  geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))
  const color = new THREE.Color(Math.random(), Math.random(), Math.random())
  const cubeMaterial = new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.8 });
  const mesh = new THREE.Mesh(geometry, cubeMaterial);
  scene.add(mesh);
}

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 10);
// scene.add(camera);

const axesHelper = new THREE.AxesHelper(5); // 长度
scene.add(axesHelper);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight); //设置three.js渲染区域的尺寸(像素px)
document.body.appendChild(renderer.domElement);
renderer.render(scene, camera);

// 相机围绕目标进行轨道运动
const controls = new OrbitControls(camera, renderer.domElement);

function render(time) {
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
render()
</script>

矩阵(缩放、旋转、平移)

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
    <script>
        const canvas = document.getElementById('canvas')
        canvas.width = window.innerWidth
        canvas.height = window.innerHeight
        const gl = canvas.getContext('webgl')
        // 第一次创建webgl绘图上下文,需要设置视口大小
        gl.viewport(0, 0, canvas.width, canvas.height)

        // 创建着色器
        const vertexShader = gl.createShader(gl.VERTEX_SHADER)
        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER)
        // 绑定数据源
        // 声明顶点着色器 attribute 变量
		// varying将顶点着色器的变量传给片元着色器
        gl.shaderSource(vertexShader, `
            attribute vec4 a_Position;
            uniform mat4 u_Mat;
            varying vec4 v_Color;
            void main(){
               gl_Position = u_Mat * a_Position;
               gl_PointSize = 20.0;
               v_Color = gl_Position;
            }
        `)
        gl.shaderSource(fragmentShader, `
            precision mediump float;
            varying vec4 v_Color;
            void main(){
                gl_FragColor = v_Color;
            }
        `)
        // 编译着色器
        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 vertices = new Float32Array([
            //x, y
            0.0, 0.5,
            -0.5, -0.5,
            0.5, -0.5
        ])
        // 创建缓冲区
        const vertexBuffer = gl.createBuffer()
        // 绑定缓冲区 
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
        // 写入数据(gl.STATIC_DRAW表示数据不会改变,gl.DYNAMIC_DRAW表示数据会改变)
        gl.bufferData(gl.ARRAY_BUFFER, vertices, 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)


        // 缩放矩阵
        const scale = { x: 0.5, y: 0.5, z: 0.5 }
        const mat = new Float32Array([
            scale.x, 0.0, 0.0, 0.0,
            0.0, scale.y, 0.0, 0.0,
            0.0, 0.0, scale.z, 0.0,
            0.0, 0.0, 0.0, 1.0
        ])
        const u_Mat = gl.getUniformLocation(program, 'u_Mat')
        // 传递一个4x4的浮点矩阵(缩放、旋转、平移)
        gl.uniformMatrix4fv(u_Mat, false, mat)

        // 清空canvas
        gl.clearColor(0.0, 0.0, 0.0, 0.0)
        gl.clear(gl.COLOR_BUFFER_BIT)

        // 绘制指定位置的三角
        // 点 
        // gl.drawArrays(gl.POINTS, 0, 3)
        // 闭合线条
        // gl.drawArrays(gl.LINE_LOOP, 0, 3)
        // 单独三角形 (如果是正面,逆时针绘制, 实际引擎开发中用的最多,就是比较费点)
        gl.drawArrays(gl.TRIANGLES, 0, 3) // gl.drawArrays(mode, first, count)
        // LINES 单独线段(每2组一条线)
        // LINE_STRIP 线条 (线条相连,但首尾不相连)

        function animate() {
            scale.x -= 0.01
            const mat = new Float32Array([
                scale.x, 0.0, 0.0, 0.0,
                0.0, scale.x, 0.0, 0.0,
                0.0, 0.0, scale.x, 0.0,
                0.0, 0.0, 0.0, 1.0

            ])
            const u_Mat = gl.getUniformLocation(program, 'u_Mat')
            // 传递一个4x4的浮点矩阵(缩放、旋转、平移)
            gl.uniformMatrix4fv(u_Mat, false, mat)
            gl.drawArrays(gl.TRIANGLES, 0, 3) // gl.drawArrays(mode, first, count)
            requestAnimationFrame(animate)
        }
        animate()
    </script>
</body>

</html>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值