最近在做Three.js相关的一些工作,其中需要对构建好的mesh动态改变其着色器,于是就做了下面的修改
this.mesh.material.vertexShader = material.vertexShader;
this.mesh.material.fragmentShader = material.fragmentShader;
因为mesh是不断创建、添加到scene中,这就造成了一个问题,着色器已经修改完毕,在场景中应该按照修改完的着色器的值来展示,但现实却不是,而是一部分按照后来修改的着色器展示,一部分没有按照修改完的着色器展示,也就是说--修改后的着色器使mesh的展示,一部分正常,一部分异常,这是为什么呢?
借助调试Spector.js工具的先看到修改之前的着色器,这里只看一个典型值NUMBER_OF_TEXTURES,修改shader之前是4;修改之后依然是4。
是不是觉得很怪异,图片是我偷懒复制粘贴的,但情况就是这样,why???
吾日三省吾身,着实经过一番痛苦的自查,自认为在代码赋值这一块应该是没问题的,那这是什么问题???
后来就仔细跟了一下Three.js的源码,发现在其内部使用了一个叫WeakMap的键值对集合,搜索一下,巴拉巴拉一大堆,核心就最后一段
再看一下Three.js是如何使用这个东西的
在Three.js中这个类会将要渲染的material存放在这里面,等下次渲染时候会从这个缓存中查找,如果存在,就直接使用缓存中的shader,恍然大悟,原来如此;
上面三幅图就是造成我修改shader失败的核心,回过头再看一下WebGLProperties这个类,它有一个remove函数,正好使用就是WeakMap的方法,那就每次修改着色器之前把当前的material从键值对中移除就好了吧?
那么就把代码做点修改吧,增加下面一句
代码跑起来,结果已经可以预见。
仅此,记录一下Three.js的踩坑之旅。