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>