此系列文章用于记录我使用WebGL开发3D引擎时遇到的问题和解决方案(也可能暂未解决)。
项目demo地址:cool.js
项目源码地址:cool.js——码云
----------------------正文分割线---------------------------------
开始做渲染GLTF模型时,出现只能渲染出一部分的问题。经查,是由于我创建index数据时用的Uint8Array类型
下面是错误做法:
var indices = new Uint8Array([0,1,2,1000,...]); // 错误! 大于255的数据会被错误读取
var indexBuffer = gl.createBuffer(); //创建buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); //绑定buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); //绑定数据
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0); //Uint8Array对应UNSIGNED_BYTE
Uint8Array类型的取值范围是0~255,所以数据中大于255的数据会被截断到二进制的前8位,读取出的值就错了。结果就是只渲染出顶点数据里的前255个!
注意,drawElements第3个参数要和index的数据类型一致,否则会出错。Uint8Array对应gl.UNSIGNED_BYTE。
正确做法如下:
var indices = new Uint16Array([0,1,2,1000,...]); // Uint16Array最大可以到65535
var indexBuffer = gl.createBuffer(); //创建buffer
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); //绑定buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); //绑定数据
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0); //Uint16Array对应UNSIGNED_SHORT
Uint16Array类型的取值范围是0~65535。注意,此时drawElements第3个参数要用gl.UNSIGNED_SHORT。
这样就没问题了!
总结:
drawElements第3个参数有两种选择:byte和short。
如果模型的顶点数量小于等于255,可以用byte,对应index数据用Uint8Array类型。
如果模型的顶点数量大于255,只能用short,对应index数据用Uint16Array类型。
-------------------------------讨论---------------------------------
如果模型的顶点数量大于65536怎么办?我觉得只能把模型拆成几个小的分开渲染,或者用drawArray。有大佬知道更好的解决方案求告知一下,感激不尽。
-------------------------------------------------------
转载请注明出处:微笑君的博客