0. 序言
学习webgl
或者什么opengl
你要记住这只是帮助你实现绘制的工具,最主要的是学习计算机图形的知识,而不是死磕这个api
该怎么用。
学习webgl
纯属个人兴趣,其实很早的时候我就想学了,打开学习网站,刚看第一章就打脑壳。
现在我准备沉下心来认真学习,顺便也记录一下我的学习历程,希望能帮助你。
我觉得最重要的还是坚持,这里面虽然涉及了一些数学,但是并不是很难,可以说大学学了一点点都能懂。
最重要的还是要自己多思考为什么,很多教程文章书本上并没有特别讲得清楚,甚至是错的。这需要你自己多看几篇文章总结。
1. 上手
介绍就不多说了,直接看看简单的实例。这里是webgl1
不是webgl2、webgpu
。
import { useEffect, useRef } from 'react'
// 我是为了插件可以高亮提示所以单独写的文件,也可以直接写字符串
// 需要配置一下webpack,来读取文件内容
// >5.0在rules里面直接设置type:'asset/source'
// <5.0 需要安装raw-loader
import vert from './index.vert'
import frag from './index.frag'
const WebGL = () => {
const canvas = useRef<HTMLCanvasElement>(null)
useEffect(() => {
if(canvas.current) {
// 获取webgl上下文
const gl = canvas.current.getContext('webgl')
if(gl) {
// 清空颜色缓冲
gl.clearColor(0, 0, 0, 1)
gl.clear(gl.COLOR_BUFFER_BIT)
// 1.创建顶点、片元着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER)
const fragShader = gl.createShader(gl.FRAGMENT_SHADER)
if(vertexShader && fragShader) {
// 2.装载着色器代码
gl.shaderSource(vertexShader, vert)
gl.shaderSource(fragShader, frag)
// 3.编译着色器
gl.compileShader(vertexShader)
gl.compileShader(fragShader)
// 4.创建WebGLProgram对象
// 这个对象是用来和js互操作的
const program = gl.createProgram()
if(program) {
// 5.添加着色器
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragShader)
// 6.链接程序
gl.linkProgram(program)
// 7.WebGLProgram对象添加到渲染状态中
gl.useProgram(program)
// 8.绘制
gl.drawArrays(gl.POINTS, 0, 1)
}
}
}
}
}, [])
return (
<canvas ref = { canvas } style = { {width: 600, height: 600, padding: 20, border: 'solid 2px #000', margin: 20} }></canvas>
)
}
顶点着色器代码
void main() {
// 点位置
gl_Position = vec4(0.5, 0.0, 0.0, 1.0);
// 点大小
gl_PointSize = 30.0;
}
片段着色器代码
void main() {
// 颜色
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
效果
这里有几个问题
- 画出来的点应该是正方形,这里却是长方形 (
canvas
设置问题) - 这个长方形边缘有点模糊 (
canvas
设置问题) - 为什么
(0.5, 0.0, 0.0, 1.0)
会出现在右下角位置(坐标) - 为什么初始代码这么复杂,仅仅是画了一个点(
webgl
原理)
2. canvas
设置问题
刚才我直接给canvas
样式设置的宽高,这样是不正确的。样式中的宽高指的是元素的宽高,canvas
的宽高属性指的是canvas
画的图像的宽高,所以之前的设置仅仅是拉伸了图像
// 改成这样
<canvas ref = { canvas } width = { 600 } height = { 600 } style = { {padding: 20, border: 'solid 2px #000', margin: 20} }></canvas>
3. 坐标
熟悉css
等二维绘画方式的都知道,默认情况下坐标的原点是在左上角,而这里的webgl
是用来绘制更复杂的三维图形,三维图像在前后左右都有绘制需求,所以原点是在正中心。
4. webgl
原理
其实也不是原理,从另外一个角度来说webgl
就是一个大的状态机,通过切换不同program
执行不同的上线文。
大概意思就是
gpu
工作方式就是这样,数据总线的速度比硬件慢,为了提高速度提前设置了很多状态- 利于编译程序做一些缓存之类的优化,能够对比之前的状态来节约更新资源。
- 历史原因,以前没有想到会有现在这些图形技术。
- 因为保存了状态,调用函数的时候可以少传参数