Threejs 字体单独发光

本文章纯原创,转载请标注

先上效果图

这里用的是three的后效EffectComposer,材质用的是UnrealBloomPass。

正常使用后效的代码如下:

            var renderPass = new RenderPass( scene, camera );

            var bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85 );

            var composer = new EffectComposer( renderer);

            composer.addPass( renderPass );

            composer.addPass( bloomPass );

然后每帧调用composer.render();

这时候会整个场景都发光,效果图如下:

如果想要做到部分发光怎么办呢?

我搜了网上其他人的代码,比如我想让鞋带单独发光

代码如下:

            model_.traverse(function(obj)

                    {

                        if(obj.isMesh)

                            obj.layers.set(1);

                    });

                    xiedai.layers.set(0);

其实就是把鞋带的层级设为0, 其他都设为1

render()中在composer.render();前后添加:

            renderer.clear();

            camera.layers.set(0);

            composer.render();

           render.clearDepth();

            camera.layers.set(1);

            renderer.render(scene, camera);

效果图如下

我们发现鞋带没了。。。。

真的没了吗?

我换了个角度看

鞋带其实是在的,而且正常发光,只不过three后效的layer被原场景挡住了

而且还有个很坑的问题,就是three的后效只有layer为0的时候才会生效,其他层都不会显示。

那该怎么办呢?

于是我想了个办法,让后效按照我的顺序渲染,所以就把UnrealBloomPass.js的render改了一下

具体做法如下:

先注掉外部render()中的这三行代码

            // renderer.clearDepth();

            // camera.layers.set(1);

            //renderer.render(scene, camera);

首先解决只有layer为0才有后效的问题,只要改一行代码即可

找到fsQuad的定义,也就是this.fsQuad = new FullScreenQuad( null );这行代码

在下面加上this.fsQuad._mesh.layers.enableAll();

其实就是后效没有在所有层级上生效导致的

我们再解决后效渲染问题

首先改一下UnrealBloomPass的构造函数,添加两个参数 scene和camera

再添加到this属性中,这个后面要用到

class UnrealBloomPass extends Pass {

    constructor( resolution, strength, radius, threshold, scene, camera ) {

        super();

        this.renderScene = scene;

        this.renderCamera = camera;

        this.strength = ( strength !== undefined ) ? strength : 1;

定义UnrealBloomPass的时候要做相应的修改,把scene和camera传入

var bloomPass = new UnrealBloomPass( new THREE.Vector2( window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85, scene, camera );

然后到UnrealBloomPass.js中的render()中

有两个if ( this.renderToScreen )这样的判断

我们就修改这两个地方

第一个判断中注释掉这行

//this.fsQuad.render( renderer );

在下面添加代码

renderer.render( this.renderScene, this.renderCamera );

第二个判断

if和else中都注释掉

//this.fsQuad.render( renderer );

然后在判断外部添加

        this.renderCamera.layers.set(1);

        renderer.render( this.renderScene, this.renderCamera );

        this.fsQuad.render( renderer );

这样就改好了 效果图如下

这样就实现了局部发光,但是随即我有发现了个问题

就是透明材质会和背景混合

比如我的字体的背景就是透明的 跟黑色的背景混合了,如下图:

字体虽然发光了,但是黑色背景挡住了模型,我能想到的办法就是专门用一个层级去跟透明材质混合,所以我又进行了如下处理:

把字体背景挡住的材质放到一个新的层级

houpian.layers.set(2);

回到UnrealBloomPass的render(),在第一个上述renderToScreen的判断中添加代码:

this.renderCamera.layers.set(2);

就可以得到开头的效果图了

不过以上所有的做法都没有封装性,希望three官方能考虑到多个层级需要单独后效的问题

完事

                                                                             

                                                                                                 cslg.panda

                                                                                                                     2021.6.22


版权声明:本文为cslgpanda原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。