WebGL绘制三角形

94 阅读2分钟

WebGL(OpenGL ES2.0)

绘制红色的三角形

import { Button, Container } from "@mui/material";
import { useRef } from "react";

let vs_src = `
attribute vec2 pos;
void main() {
  gl_Position = vec4(pos, 1.0, 1.0);
}
`

let fs_src = `
void main() {
  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`

// 创建渲染流水线
function createProgram(gl: WebGLRenderingContext) {
  let prog = gl.createProgram()!
  // 创建并编译Vertex Shader
  let vs = gl.createShader(gl.VERTEX_SHADER)!
  gl.shaderSource(vs, vs_src)
  gl.compileShader(vs)
  if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
    console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(vs))
    gl.deleteShader(vs)
  }
  gl.attachShader(prog, vs)
  // 创建并编译Fragment Shader
  let fs = gl.createShader(gl.FRAGMENT_SHADER)!
  gl.shaderSource(fs, fs_src)
  gl.compileShader(fs)
  if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
    console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(fs))
    gl.deleteShader(fs)
  }
  gl.attachShader(prog, fs)
  // 链接Program
  gl.linkProgram(prog)
  if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
    console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(prog))
  }
  gl.useProgram(prog)
  return prog
}

export default function () {
  let canvas_ref = useRef<HTMLCanvasElement>(null)
  return (
    <Container>
      <canvas ref={canvas_ref} width={400} height={400} />
      <Button onClick={() => {
        let elt = canvas_ref.current!
        let gl = elt.getContext('webgl')!
        let prog = createProgram(gl)
        // 创建Vertex Buffer Object
        let buf = gl.createBuffer()!
        gl.bindBuffer(gl.ARRAY_BUFFER, buf)
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1]), gl.STATIC_DRAW)
        // 描述VBO的数据排列
        let loc = gl.getAttribLocation(prog, 'pos')
        gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0)
        gl.enableVertexAttribArray(loc)
        // 清除背景色
        gl.clearColor(0, 0, 0, 1)
        gl.clear(gl.COLOR_BUFFER_BIT)
        // 设置视窗
        gl.viewport(0, 0, elt.width, elt.height)
        // 绘制三角形
        gl.drawArrays(gl.TRIANGLES, 0, 3)
      }}>Render</Button>
    </Container>
  )
}

WebGL2(OpenGL ES3.0)

绘制顶点颜色不同的三角形

import { Button, Container } from "@mui/material";
import { useRef } from "react";

let vs_src = `#version 300 es
precision mediump float;
layout(location = 0) in vec2 pos;
layout(location = 1) in vec3 color;
out vec3 _color;
void main() {
  gl_Position = vec4(pos, 1.0, 1.0);
  _color = color;
}
`

let fs_src = `#version 300 es
precision mediump float;
in vec3 _color;
out vec4 fragColor;
void main() {
  fragColor = vec4(_color, 1.0);
}
`

let gl: WebGL2RenderingContext
let vbo: WebGLBuffer
let vbo2: WebGLBuffer
let vao: WebGLVertexArrayObject

// 创建渲染流水线
function createProgram(gl: WebGLRenderingContext) {
  let prog = gl.createProgram()!
  // 创建并编译Vertex Shader
  let vs = gl.createShader(gl.VERTEX_SHADER)!
  gl.shaderSource(vs, vs_src)
  gl.compileShader(vs)
  if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
    console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(vs))
    gl.deleteShader(vs)
  }
  gl.attachShader(prog, vs)
  // 创建并编译Fragment Shader
  let fs = gl.createShader(gl.FRAGMENT_SHADER)!
  gl.shaderSource(fs, fs_src)
  gl.compileShader(fs)
  if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
    console.error('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(fs))
    gl.deleteShader(fs)
  }
  gl.attachShader(prog, fs)
  // 链接Program
  gl.linkProgram(prog)
  if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
    console.error('Unable to initialize the shader program: ' + gl.getProgramInfoLog(prog))
  }
  gl.useProgram(prog)
  return prog
}

export default function () {
  let canvas_ref = useRef<HTMLCanvasElement>(null)
  return (
    <Container>
      <canvas ref={canvas_ref} width={400} height={400} />
      <Button onClick={() => {
        let elt = canvas_ref.current!
        gl = elt.getContext('webgl2')!
        let prog = createProgram(gl)
        // 创建Vertex Array Object(VAO)
        vao = gl.createVertexArray()!
        // 创建Vertex Buffer Object(VBO)
        vbo = gl.createBuffer()!
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo)
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 1, 0, 1, 1]), gl.STATIC_DRAW)
        vbo2 = gl.createBuffer()!
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo2)
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1, 0, 0, 0, 1, 0, 0, 0, 1]), gl.STATIC_DRAW)
        // 绑定VAO记录操作
        gl.bindVertexArray(vao)
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo)
        gl.enableVertexAttribArray(0)
        gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0)
        gl.bindBuffer(gl.ARRAY_BUFFER, vbo2)
        gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0)
        gl.enableVertexAttribArray(1)
        gl.bindVertexArray(null)
        gl.bindBuffer(gl.ARRAY_BUFFER, null)
      }}>Init</Button>
      <Button onClick={() => {
        let elt = canvas_ref.current!
        gl.bindVertexArray(vao)
        // 清除背景色
        gl.clearColor(0, 0, 0, 1)
        gl.clear(gl.COLOR_BUFFER_BIT)
        // 设置视窗
        gl.viewport(0, 0, elt.width, elt.height)
        // 绘制三角形
        gl.drawArrays(gl.TRIANGLES, 0, 3)
      }}>Render</Button>
    </Container>
  )
}