![8b186f56fae1b7b4e66b3aa769cc3511.png](https://i-blog.csdnimg.cn/blog_migrate/308a1c63d7a11d6c3c25229b2d398de2.jpeg)
halo,大家好,俺又回来了,好久不贱哇
今天这篇文章是关于 webgl 的,起因最近在玩一个小游戏,然后突发奇想,想写写 webgl 试试手感,然后引发了一些思考
webgl 对我一个数学不及格的人来说,其实乍一看还是很难的,但好在我是动画专业,对 3d 软件比较熟悉……所以碰到模型,贴图(纹理),灯光等概念还不算陌生
但是真的当我开始写的时候,我快疯了:
const drawImage = (tex, h, w, x, y) => {
gl.bindTexture(gl.TEXTURE_2D, tex)
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer)
gl.enableVertexAttribArray(positionLocation)
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0)
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer)
gl.enableVertexAttribArray(texcoordLocation)
gl.vertexAttribPointer(texcoordLocation, 2, gl.FLOAT, false, 0, 0)
gl.uniformMatrix4fv(matrixLocation, false, matrix(gl.canvas.width, gl.canvas.height, h, w, x, y))
gl.uniform1i(textureLocation, 0)
gl.drawArrays(gl.TRIANGLES, 0, 6)
}
如上,仅仅是画一张图片,就要一堆 gl.xxxxxxxxxxxx,我一直以为 canvas 的命令式代码已经够瞎了,没想到它只是个弟弟,webgl 才是真的惨绝人寰
所以到了这个时候,我第一感觉,就是有一个声明式的封装就好了
Elm
提到声明式,elm 可以说是做的最好的,后来居上的有 redux,dva 等
const reducer = (state, action) => {
switch (action.type) {
case 'ADD':
return state + action.payload;
default:
return state
}
}
const state = reducer(0, {
type: 'ADD',
payload: 2
})
let store = createStore(reducer)
store.subscribe(listener)
store.dispatch({ type:'ADD' })
通过 state 控制 UI,然后只能通过 dispatch 来修改 UI,通过 effects 来管理副作用
经常和发布订阅、memo 等特性联用
如果我们的 webgl 库也能拥有类似的模型就太好了,答案是有的
import { create } from './src/index.js'
const stage = create('#canvas')
const sprite = stage.add('hj.png') // 发布
function loop() {
sprite.x = Math.random() * stage.gl.canvas.width // 修改 state
sprite.y = Math.random() * stage.gl.canvas.height
stage.draw() // 订阅
requestAnimationFrame(loop)
}
loop()
是不是很熟悉,有点 redux 的样子了,唯一的区别在于 state 可以通过 sprite.xxx 这样修改
这里有一个误解,就是为什么 react 不使用 this.state.xxx 这样直接修改,而必须通过 setState
其实 react 是可以使用 this.state.xxx 修改的,只需要这样用:
this.state.x = 0
this.state.y = 1
this.setState(this.state)
它和 vue 的 Proxy 的方式的区别在于多了一个订阅函数(setState)
所以上面的 gei 的代码是一样的,必须有个 draw() 函数去订阅,当然这里可以使用 immer 等库,让它变成劫持状态,但是 core 中没有必要内置
经过一顿封装,终于有了一个声明式的 API,但我们的初衷其实是做游戏,在游戏领域内有没有类似的思想呢?
答案还是有的,就是 ecs
将游戏分为 entity、component、system
component 和 state 一样,它是纯状态,无逻辑,system 和 action 差不多,纯逻辑,无状态,entity 可有可无,和 effect 差不多,用来处理 component 和 system 的副作用(有点状态,有点逻辑)
好了,饶了一圈,又回到了我熟悉的东西,突然领悟了万变不离其宗的真谛::>_<::
总结
经过一番摸索,大概有了思路,我开了个新坑:
https://github.com/yisar/gei
因为我有写 fre 的经验,所以架构思路可以比较流畅,但是总归在 3d 领域我是个新人……只能慢慢来
尤其是思想要转变过来,我们平时写 UI 时刻面对的是 html 元素和 css 布局,但是在 3d 领域,我们时刻想的应该是 canvas,模型,贴图,灯光
p.s. 最近失业了::>_<:: 又要准备面试了,希望能有个好归宿了
等基本稳定后再贱!