webGL可以在网页上渲染复杂的三维图形,换句话说,如果没有webGL我们就只能在网页上使用canvas渲染二维图形。我将使用最简单的语言,教会你如何使用webGL
万事开头难
现在需要一个趁手的工具来进行我们的学习,我选用了react框架进行项目的搭建,并使用react-router对每个知识点进行了模块化的隔离。项目使用TS进行编写。
万事开头难 话不多说先建立一个canvas。
我们使用useRef,以便在组件中引用canvas的dom。
function DrawPoint() {
const canvasRef = useRef<HTMLCanvasElement>();
return (
<canvas ref={canvasRef} id="example" width="400" height="400"></canvas>
);
}
使用一个工具函数来初始化webGL
然后在项目中建立一个utils文件夹,在index.ts中粘贴如下代码:
// ./utils/index.ts
export function initShaders(
gl: WebGLRenderingContext, // webGL绘图上下文
vshader: string, // 顶点着色器
fshader: string // 片元着色器
) {
const program = createProgram(gl, vshader, fshader);
if (!program) {
console.log("Failed to create program");
return false;
}
gl.useProgram(program);
Object.defineProperty(gl, "program", {
configurable: true,
enumerable: true,
value: program,
writable: true,
});
return true;
}
export function createProgram(
gl: WebGLRenderingContext,
vshader: string,
fshader: string
) {
// 创建着色器对象
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
if (!vertexShader || !fragmentShader) {
return null;
}
// 创建webGL应用程序
var program = gl.createProgram();
if (!program) {
return null;
}
// 为应用程序分配着色器对象
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// 把着色器与应用程序对象链接
gl.linkProgram(program);
// 检查着色器与应用程序是否链接成功
const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
const error = gl.getProgramInfoLog(program);
console.log("Failed to link program: " + error);
gl.deleteProgram(program);
gl.deleteShader(fragmentShader);
gl.deleteShader(vertexShader);
return null;
}
return program;
}
export function loadShader(
gl: WebGLRenderingContext,
type: number,
source: string
) {
// 创建着色器
const shader = gl.createShader(type);
if (shader == null) {
console.log("unable to create shader");
return null;
}
// 向着色器中填加GLSL ES程序代码
gl.shaderSource(shader, source);
// 编译着色器
gl.compileShader(shader);
// 检查编译是否成功
const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
const error = gl.getShaderInfoLog(shader);
console.log("Failed to compile shader: " + error);
gl.deleteShader(shader);
return null;
}
return shader;
}
上面的代码在webGL中非常专业的存在,我们先不用理解理解里面的工作原理,我们的目标是要行跑起来。
第一个应用程序
下面上我们使用webGL网页中画一个点吧!:
import React, { useEffect, useRef } from "react";
import { initShaders } from "../../utils/index";
function DrawPoint() {
const canvasRef = useRef<HTMLCanvasElement>();
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) {
console.log("Failed to retrieve the canvas element");
}
const gl = canvas.getContext("webgl");
if (!gl) {
console.log("Failed to get the rendering context for WebGL");
return;
}
drawPoint1(gl);
}, []);
const clearCanvas = (gl: WebGLRenderingContext) => {
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
};
// 顶点着色器
const VSHADER_SOURCE = `
void main() {
gl_Position = vec4(0.5, 0.0, 0.0, 1.0);
gl_PointSize = 10.0;
}
`;
// 片元着色器
const FSHADER_SOURCE = `
void main() {
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
`;
const drawPoint1 = (gl: WebGLRenderingContext) => {
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log("Failed to initialize shaders");
return;
}
clearCanvas(gl);
gl.drawArrays(gl.POINTS, 0, 1);
};
return (
<canvas ref={canvasRef} id="example" width="400" height="400"></canvas>
);
}
export default DrawPoint;
上面的组件在进行挂载时会首先调用useEffect函数中回调,在回调函数中我们使用canvasRef.current获取canvas的实例,并使用canvas.getContext('webgl')API创建了一个webGL绘图上下文对象。
最后使用drawPoint1函数完成图像绘制。
你们的图跟我一样吗?如果一样,恭喜你创建了第一个webGL程序。
什么是着色器?
着色器有两种
- 顶点着色器 (Vertex shader) :它是用来描述顶点的特性(位置、颜色等)的程序。顶点是指二维或三维空间中的一个点。
- 片元着色器 (Fragment shader) :它是用来逐片元处理的程序,片元可以理解为像素(图像的单元)。
如上面代码可见,我们写了两个字符串VSHADER_SOURCE和FSHADER_SOURCE,这都是专用来写着色器的语言GLSL ES。
请记住,要使用webGL进行绘图,最重要的就是要学会使用着色器!
下一篇,我将详细的讲一讲着色器该如何使用,敬请期待~~