经典的代码:
//buffer的创建和赋值
let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
问题1:
为啥不直接把vertices赋值给buffer对象?
比如这样
buffer = vertices
非要gl.ARRAY_BUFFER这个“中间商”赚差价呢?
回答:
不行,因为buffer和vertices本身都是JavaScript中存在的变量
所以他们都是“内存的地址”,而不是“显存的地址”
我们现在需要的是把vertices放到“GPU的显存”中
问题2:
为啥不让buffer直接代表显存地址?
让gl.createBuffer()直接返回的就是“GPU显存地址”呢?
然后就可以buffer = vertices
回答:
内存是cpu在管理,显存是gpu在管理
或者说
cpu无法管理显存、gpu也无法管理内存
cpu不认识,也无法操作显存地址
所以没法直接让gl.createBuffer()返回显存地址
或者说
在webgl规范下
“GPU显卡”并不愿意把自己“显存的地址”让“CPU处理器”去访问和操作!
问题3
那么webgl又是如何做到数据的传递?内存数据传递到显存呢?
回答:
webgl必须让“GPU显卡”做出妥协!
webgl开了一个口子
gl.ArrayBuffer对象,可以在
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
语句执行的时候,
gpu主动把vertices的内容复制到gl.ARRAY_BUFFER绑定的显存中
问题4:
为啥只开一个口子,全开了不好吗?
回答:
技术上应该可以实现“全开口”
但是webgl做为一个规范,它的这个规范并没有让“全开口”
我觉得可能是因为
要做到“硬件的解耦”、“硬件的独立”吧
如果你可以改变我的、我也可以改变你的,可能会出现管理上的混乱
(备注:规范是变化的,也有可能webgl会在哪天,直接让cpu操作任意的显存地址)
问题5:
再举几个通俗的例子来理解gl.ARRAY_BUFFER存在的原因
回答:
例子1:
中国和美国
代表显存和内存
如果放开2个国家的人们直接买卖货物,会让2个国家彼此都无法控制贸易的具体行为,可能会出现混乱
所以,要有一个“外贸商”来负责货物的转运?
例子2:
你要给正在上课的孩子送午饭
你无法进入教室
你只能把东西给老师,让老师带过去
let vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);//创建孩子的午饭
let buffer = gl.createBuffer();//创建了一个孩子“张三”,并且让他进入教室
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);//告诉老师,待会所有给老师的东西,都要转交给“张三”
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);//把“午饭”转交给老师
//因为刚才已经告诉老师,收到的所有东西都给“张三”
//所以,上述语句之后,“vertices午饭”就已经转送给了“buffer孩子张三”
备注:
一切技术都是变化的
现在DirectX12好像出了相关规范和技术
让CPU可以直接访问显存
但是webgl规范应该没有跟进
感觉“cpu直接访问显存”
更多的是一个“规范”问题,而不是“技术”实现不了的问题