能否为每个顶点与每个实例设置不同的WebGL顶点属性?
解决方法
你要实现的是让颜色属性每个实例的每个顶点都用不同值,但现在你的颜色缓冲区是按实例堆在一起的(先放第一个三角形的三个颜色,再放第二个的),用drawArraysInstanced的话默认会重复读前三个颜色,第二个实例还是用color1-3,达不到你要的效果。
有两种直接的解决办法:
办法1:调整颜色缓冲区的排列方式(推荐)
把颜色按顶点来分组,每个顶点的所有实例颜色放一块儿:
// 调整后的Color buffer [ color1, color4, // 顶点0对应实例0、实例1的颜色 color2, color5, // 顶点1对应实例0、实例1的颜色 color3, color6 // 顶点2对应实例0、实例1的颜色 ]
然后给colorLocation补充以下设置:
// 设置stride:每个顶点占2个颜色的字节数(2*4*4=32字节) gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 32, 0); // 让颜色属性每切换一个实例更新一次 gl.vertexAttribDivisor(colorLocation, 1);
这样实例0会取每个顶点的第一个颜色,实例1取第二个,正好符合你的要求。
办法2:不改动缓冲区,靠着色器实现
要是不想改缓冲区结构,就得把颜色数据转成纹理(因为顶点缓冲区没法随机跳着读),然后在顶点着色器里用gl_InstanceID和gl_VertexID算索引:
- 把颜色缓冲区的数据传到一个2D纹理里
- 在着色器里算坐标:
vec2 texCoord = vec2(gl_VertexID + gl_InstanceID * 3, 0.0) - 用
texelFetch读对应颜色
这种办法JS端不用改colorLocation的设置,但着色器要写更多代码,效率也不如第一种高。
额外提醒
要是你非得用现在的缓冲区排列又不想改着色器,那其实没必要用实例化渲染,直接调用gl.drawArrays(gl.TRIANGLES, 0, 6)画6个顶点就行,反而更简单。
内容的提问来源于stack exchange,提问作者Holger Seelig
相关产品推荐
相关产品推荐

