上一节绘制了圆点,调用的绘制方法如下:gl.drawArrays(gl.POINTS, 0, 1); 第一个参数明显是个枚举类型,肯定还有其他值,如下所示:
- POINTS 可视的点
- LINES 单独线段
- LINE_STRIP 线条
- LINE_LOOP 闭合线条
- TRIANGLES 单独三角形
- TRIANGLE_STRIP 三角带
- TRIANGLE_FAN 三角扇
这小节尝试一下 绘制单独线段、线条、闭合线条、三角带(可构成矩形)
代码如下所示:
<template>
<div class="wrapper">
<div class="point-wrapper">
<div style="margin-bottom: 20px">绘制点</div>
<canvas id="point" width="280" height="250"></canvas>
</div>
<div class="point-mouse">
<div style="margin-bottom: 20px">鼠标绘制点</div>
<canvas id="pointByMouse" width="280" height="250"></canvas>
</div>
</div>
</template>
<script>
export default {
name: "point",
};
</script>
<script setup>
import { onMounted } from "vue";
import { initShaders } from "@/utils/myGL.js";
const vertexShaderSrc = `
attribute vec4 a_Position;
attribute float a_PointSize;
void main() {
gl_Position = a_Position;
gl_PointSize = a_PointSize;
}
`;
const fragmentShaderSrc = `
precision mediump float;
uniform vec4 u_FragColor;
void main() {
gl_FragColor = u_FragColor;
}
`;
const fragmentShaderSrcCircle = `
precision mediump float;
void main() {
float d = distance(gl_PointCoord, vec2(0.5, 0.5));
if(d < 0.5) {
gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
} else {
discard;
}
}
`;
const drawPointStatic = () => {
const canvas = document.getElementById("point");
// webgl画笔
const gl = canvas.getContext("webgl");
// 初始化着色器
initShaders(gl, vertexShaderSrc, fragmentShaderSrc);
const a_position = gl.getAttribLocation(gl.program, "a_Position");
const a_pointSize = gl.getAttribLocation(gl.program, "a_PointSize");
const u_FragColor = gl.getUniformLocation(gl.program, "u_FragColor");
gl.vertexAttrib3f(a_position, 0, 0.0, 0.0);
gl.vertexAttrib1f(a_pointSize, 20.0);
gl.uniform4f(u_FragColor, 1.0, 0.0, 0.0, 1.0);
// 指定将要用来清理绘图区的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 清理绘图区
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制顶点
gl.drawArrays(gl.POINTS, 0, 1);
setTimeout(() => {
initShaders(gl, vertexShaderSrc, fragmentShaderSrcCircle);
// 指定将要用来清理绘图区的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// 清理绘图区
gl.clear(gl.COLOR_BUFFER_BIT);
// 绘制顶点
gl.drawArrays(gl.POINTS, 0, 1);
}, 2000);
};
const drawPointByMouse = () => {
const canvas = document.getElementById("pointByMouse");
// webgl画笔
const gl = canvas.getContext("webgl");
// 初始化着色器
initShaders(gl, vertexShaderSrc, fragmentShaderSrc);
// // 指定将要用来清理绘图区的颜色
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// // 清理绘图区
gl.clear(gl.COLOR_BUFFER_BIT);
let pointArrs = [];
document.addEventListener("click", (event) => {
const { clientX, clientY } = event;
const { left, top, width, height } = canvas.getBoundingClientRect();
const [cssX, cssY] = [clientX - left, clientY - top];
const [halfWidth, halfHeight] = [width / 2, height / 2];
const [xBaseCenter, yBaseCenter] = [cssX - halfWidth, cssY - halfHeight];
const yBaseCenterTop = -yBaseCenter;
const [x, y] = [xBaseCenter / halfWidth, yBaseCenterTop / halfHeight];
const a_Position = gl.getAttribLocation(gl.program, "a_Position");
const a_pointSize = gl.getAttribLocation(gl.program, "a_PointSize");
const u_FragColor = gl.getUniformLocation(gl.program, "u_FragColor");
pointArrs.push({
x,
y,
z: Math.random() * 50,
color: {
r: Math.random() * 1,
g: Math.random() * 1,
b: Math.random() * 1,
},
});
gl.clear(gl.COLOR_BUFFER_BIT);
pointArrs.forEach((item) => {
gl.vertexAttrib2f(a_Position, item.x, item.y);
gl.vertexAttrib1f(a_pointSize, item.z);
gl.uniform4f(u_FragColor, item.color.r, item.color.g, item.color.b, 1.0);
gl.drawArrays(gl.POINTS, 0, 1);
});
});
};
onMounted(() => {
drawPointStatic();
drawPointByMouse();
});
</script>
<style lang="scss" scoped>
.wrapper {
display: flex;
}
.point-wrapper {
width: 300px;
height: 300px;
background-color: gray;
}
.point-mouse {
margin-left: 20px;
width: 300px;
height: 300px;
background-color: gray;
}
</style>
绘制图形如下所示:
注意在代码中引入了initShaders 方法,如下:
function loadShader(gl, type, source) {
//根据着色类型,建立着色器对象
const shader = gl.createShader(type);
//将着色器源文件传入着色器对象中
gl.shaderSource(shader, source);
//编译着色器对象
gl.compileShader(shader);
//返回着色器对象
return shader;
}
export function initShaders(gl, vsSource, fsSource) {
//创建程序对象
const program = gl.createProgram();
//建立着色对象
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
//把顶点着色对象装进程序对象中
gl.attachShader(program, vertexShader);
//把片元着色对象装进程序对象中
gl.attachShader(program, fragmentShader);
//连接webgl上下文对象和程序对象
gl.linkProgram(program);
//启动程序对象
gl.useProgram(program);
//将程序对象挂到上下文对象上
gl.program = program;
}