WebGL初探

126 阅读3分钟

webGL可以在网页上渲染复杂的三维图形,换句话说,如果没有webGL我们就只能在网页上使用canvas渲染二维图形。我将使用最简单的语言,教会你如何使用webGL

万事开头难

现在需要一个趁手的工具来进行我们的学习,我选用了react框架进行项目的搭建,并使用react-router对每个知识点进行了模块化的隔离。项目使用TS进行编写。
万事开头难 话不多说先建立一个canvas。 我们使用useRef,以便在组件中引用canvasdom

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函数完成图像绘制。

image.png
你们的图跟我一样吗?如果一样,恭喜你创建了第一个webGL程序。

什么是着色器?

着色器有两种

  • 顶点着色器 (Vertex shader) :它是用来描述顶点的特性(位置、颜色等)的程序。顶点是指二维或三维空间中的一个点。
  • 片元着色器 (Fragment shader) :它是用来逐片元处理的程序,片元可以理解为像素(图像的单元)。
    如上面代码可见,我们写了两个字符串VSHADER_SOURCEFSHADER_SOURCE,这都是专用来写着色器的语言GLSL ES
    请记住,要使用webGL进行绘图,最重要的就是要学会使用着色器!

下一篇,我将详细的讲一讲着色器该如何使用,敬请期待~~