所以应该尽量减少这一步的传输次数,其实可以做到刚加载的时候就把所有的顶点数据和纹理数据从内存一并传输到显存当中,这就是现在three.js做的,第一次就把需要绘制的物体(Geometry)的顶点数据传输到显存中,并且缓存这个buffer到geometry.__webglVertexBuffer,之后每次绘制的时候都会判断Geometry的verticesNeedUpdate属性,如果不需要更新就直接使用现在的缓存,如果看到verticesNeedUpate为true, 就会重新将Geometry中的顶点数据传输到geometry.__webglVertexBuffer中,一般对于静态物体我们是不需要这一步操作的,但是如果遇到顶点会频繁改变的物体,例如用顶点来做粒子的粒子系统,还有使用了骨骼动画的Mesh, 这些物体每一帧都会改变自己的顶点,所以需要每一帧都需要将其verticesNeedUpdate属性设为true来告诉renderer我需要重新传输数据了!
其实在WebGL程序中,更多的会在vertex shader中去改变顶点的位置来完成粒子效果和骨骼动画,尽管如果放在cpu端计算更容易扩展,但是因为javascript的计算能力的限制,更多的还是会把这些计算量大的操作放到gpu端操作。 这种情况下并不需要重新传输一次顶点数据,所以上面那种case在实际程序中其实用到的不多,更多的还是会去更新纹理和材质的缓存。
上面那个case主要描述的是一个传输顶点数据的场景,除了顶点数据,还有一个大头就是纹理,一张1024*1024大小的R8G8B8A8格式的纹理所要占用的内存大小也要高达4M,于是看下面这个例子
这里就不需要变态的重复1000次了,一次传输10241024的纹理就已经花了30ms,一张256256的差不多是2ms,所以three.js中对于纹理也是尽量只在最开始的时候传输一次,之后如果texture.needsUpdate属性不手动设为true的话就会一直直接使用已经传输到显存中的纹理。
需要更新哪些缓存
上面通过两个case描述了为什么three.js要加这么一个needsUpdate属性,接下来列举一下几个场景来知道在什么情况下需要手动的更新这些缓存。
纹理的异步加载
这算是一个小坑吧,因为前端的图片是异步加载的,如果在创建好img后直接写texture.needsUpdate=true的话,three.js的renderer中会这一帧中就使用_gl.texImage2D将空的纹理数据传输到显存中,然后就将这个标志位设成false, 之后真正等到图片加载完成的时候确不再更新显存数据了,所以必须要在onload事件中等整张图片加载完成后再写texture.needsUpdate = true









