Three.js: [EffectComposer] Problema com 2 RenderPass consecutivos

Criado em 1 fev. 2012  ·  18Comentários  ·  Fonte: mrdoob/three.js

A ligação

http://demo.bkcore.com/threejs/webgl_tron_glow.html

O código

glowcomposer = new THREE.EffectComposer( renderer, renderTarget );

glowcomposer.addPass( renderModelGlow ); // RenderPass
glowcomposer.addPass( hblur ); // ShaderPass
glowcomposer.addPass( vblur ); // ShaderPass
glowcomposer.addPass( effectSave ); // SavePass

glowcomposer.addPass( renderModel ); // RenderPass
glowcomposer.addPass( finalPass ); // ShaderPass

O contexto

Tenho duas cenas com o mesmo objeto / câmera / luz. Um com a textura difusa (http://demo.bkcore.com/threejs/webgl_tron.html) e outro com uma textura brilhante (as áreas brilhantes são brancas no preto).

Meu pipeline de renderização é o seguinte:
Eu primeiro renderizo a cena brilhante e aplico um desfoque H / V a ela, então armazeno a saída em um frameBuffer usando um SavePass.
Em seguida, quero renderizar a cena difusa.
E, finalmente, misture isso com o buffer de quadro de brilho.

O problema

Meu glow sampler2D está passando bem para meu shader finalPass, mas como você pode ver na demonstração, a segunda chamada de RenderPass para a cena difusa não está funcionando bem. Produz apenas preto.

Tentei renderizar a cena difusa em uma única passagem de renderização e funcionou. É quando eu o uso como um segundo RenderPass que ele não funciona.

Alguma ideia ?

Obrigado.
Thibaut D.

Question

Comentários muito úteis

Parece que a demonstração original não está mais funcionando:

FWIW Fiz uma demonstração simplificada de aplicação seletiva de FX e composição via Additive Blend (usando Three.js v79) aqui: https://www.airtightinteractive.com/demos/selective-fx/

Todos 18 comentários

Acho que é porque o buffer de profundidade foi destruído, consulte # 1017.

Para o seu caso de uso, o que pode funcionar é usar dois compositores (e, portanto, dois destinos de renderização totalmente separados, cada um com seu próprio buffer de profundidade).

Algo assim:

glowComposer = new THREE.EffectComposer( renderer, renderTargetGlow );

glowComposer.addPass( renderModelGlow ); // RenderPass
glowComposer.addPass( hblur ); // ShaderPass
glowComposer.addPass( vblur ); // ShaderPass

finalComposer = new THREE.EffectComposer( renderer, renderTargetFinal );
finalComposer.addPass( renderModel ); // RenderPass
finalComposer.addPass( finalPass ); // ShaderPass

Agora a camada difusa estará disponível como um amostrador de textura normal tDiffuse em finalComposer e a camada de brilho que você fornecerá de glowComposer .

Será glowComposer.renderTarget1 ou glowComposer.renderTarget2 dependendo do número específico de passes e se os passes alternam os buffers dianteiro e traseiro, o mais simples é tentar ambos e ver o que funciona.

finalshader.uniforms[ 'tGlow' ].texture = glowComposer.renderTarget1;

Eu tentei isso, mas obtive um resultado muito inesperado.

Este é o código que você propôs:
http://demo.bkcore.com/threejs/webgl_tron_glow_swap.html
O tDiffuse do renderModel ainda está preto.

E este é exatamente o mesmo código, com apenas as duas passagens de renderização trocadas (a cena difusa está no compositor de brilho e a cena de brilho no compositor final):
http://demo.bkcore.com/threejs/webgl_tron_glow_swap2.html
É claro que não é o efeito que estou procurando, pois o difuso está borrado e não o brilho, mas como você pode ver, os amostradores tGlow e tDiffuse estão funcionando ...

E tudo o que fiz foi trocar (linha 130 e 175):
novo THREE.RenderPass (cena, câmera);
com
novo THREE.RenderPass (glowscene, glowcamera);

É bastante surpreendente.

Você precisa usar o formato RGBA para os alvos de renderização se usar transparência.

Bem, eu concordo, mas não estou usando nenhuma transparência já que meu passe de brilho renderiza branco em preto e meu passe difuso bem ... difuso em preto. Eu então os componho com um acréscimo para que a transparência não seja necessária.

Mesmo assim, só para ter certeza, mudei o formato do RT para RGBA, mas isso não mudou nada.

O problema estranho aqui é que fazer o RenderPass de minha cena / câmera depois do RenderPass de glowscene / glowcamera não funciona, enquanto faço o RenderPass de minha cena / câmera antes de meu RenderPass de glowscene / glowcamera.

Hmmm, parece um problema de compartilhamento de geometria para diferentes materiais (consulte # 1211).

Experimente isto:

function createScene( geometry, x, y, z, b ) {

    zmesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );

    // ...

    var geometryClone = THREE.GeometryUtils.clone( geometry );
    var gmat = new THREE.MeshBasicMaterial( { map: gtex } );
    var gmesh = new THREE.Mesh( geometryClone, gmat );

    // ...
}

Sim ! Foi isso.

Meus dois amostradores agora estão corretamente preenchidos. Obrigado :)

EDITAR

Hum ... Mais um comportamento estranho, meus dois samplers são bons, quando eu faço

gl_FragColor = texel;

Recebo o diffuse corretamente (http://demo.bkcore.com/threejs/webgl_tron_glow_swap2.html)

Quando eu faço

gl_FragColor = glow;

Eu recebo o brilho corretamente.

Mas quando tento fazer uma mistura simples de aditivos em ambos
gl_FragColor = texel + brilho;
Eu só consigo o brilho (http://demo.bkcore.com/threejs/webgl_tron_glow_swap.html).

Desculpe por fazer tantas perguntas, estou tentando fazer isso funcionar, mas sem sucesso.

EDIT2

Na verdade, parece que fazer

gl_FragColor = texel + glow;

Parece mais com isto em relação à saída de renderização:

gl_FragColor = glow + glow;

É como se o texel vec4 fosse inexplicavelmente substituído pelo brilho vec4. Parece loucura.

Você precisa colocar texturas em unidades de textura diferentes:

uniforms: {
    tDiffuse: { type: "t", value: 0, texture: null },
    tGlow:    { type: "t", value: 1, texture: null }
},

Verão!

Caso alguém esteja interessado em renderização seletiva de brilho com Three.js, acabei de publicar um pequeno artigo sobre isso: http://bkcore.com/blog/3d/webgl-three-js-animated-selective-glow.html

Espero que ajude.

Agradável ;)

Alternativamente, em vez de clonagem de geometria, outra opção mais barata seria usar materiais mais semelhantes (de modo que a geometria em ambas as passagens precisaria dos mesmos buffers).

Nesse caso, em vez de usar o material básico para passagem de brilho, você pode tentar o material Lambert com iluminação difusa zero, apenas com luz ambiente.

Algo assim:

glowScene.add( new THREE.AmbientLight( 0xffffff ) );

// ...

var gmat = new THREE.MeshLambertMaterial( { map: gtex, ambient: 0xffffff, color: 0x000000 } );
var gmesh = new THREE.Mesh( geometry, gmat );

Na verdade, está funcionando perfeitamente.

http://demo.bkcore.com/threejs/webgl_tron_glow_seq.html

Vou atualizar meu artigo sobre esta solução. Obrigado !

Estou portando este código para r60 e estranhamente encontrando o mesmo problema com o encadeamento dos compositores de efeito. Eu tenho o passe godray funcionando se eu renderizá-lo para a tela. Mas a passagem final apenas exibe o modelo. A saída do oclcompositor para o canal de textura "tadd" parece funcionar bem quando não uso um Effect Composer separado !! Eu tentei com renderer.PreserveDrawingBuffer = true, mas também não funcionou. Eu tentei definir autoclear como false, mas não foi isso.

Se eu renderizar o oclcompositor após o compositor final e fazer o godray passar a saída para a tela, posso ver os godrays, mas nenhum modelo.

Em vez de direcionar a saída do oclcompositor para o canal tadd na passagem final, se eu canalizá-lo para um MeshBasicMaterial e criar um quad texturizado e adicioná-lo à cena principal, agora posso ver o modelo e os godrays (em um plano), não o efeito que eu quero, mas me diz que o encanamento de textura está funcionando.

// COMPOSERS
//-------------------
var renderTargetParameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBAFormat, stencilBufer: false };

renderTargetOcl = new THREE.WebGLRenderTarget( SCREEN_WIDTH/2, SCREEN_HEIGHT/2, renderTargetParameters );

hblur = new THREE.ShaderPass( THREE.ShaderExtras[ "horizontalBlur" ] );
vblur = new THREE.ShaderPass( THREE.ShaderExtras[ "verticalBlur" ] );
var bluriness = 2;

hblur.uniforms[ 'h' ].value = bluriness / SCREEN_WIDTH*2;
vblur.uniforms[ 'v' ].value = bluriness / SCREEN_HEIGHT*2;

var renderModel = new THREE.RenderPass( scene, camera );
var renderModelOcl = new THREE.RenderPass( oclscene, oclcamera );

grPass = new THREE.ShaderPass( THREE.Extras.Shaders.Godrays );
grPass.needsSwap = true;
grPass.renderToScreen = false;

oclcomposer = new THREE.EffectComposer( renderer, renderTargetOcl );

oclcomposer.addPass( renderModelOcl );
oclcomposer.addPass( hblur );
oclcomposer.addPass( vblur );
oclcomposer.addPass( grPass );

var finalPass = new THREE.ShaderPass( THREE.Extras.Shaders.Additive );
finalPass.needsSwap = true;
finalPass.renderToScreen = true;
finalPass.uniforms[ 'tAdd' ].texture = oclcomposer.renderTarget1;

renderTarget = new THREE.WebGLRenderTarget( SCREEN_WIDTH, SCREEN_HEIGHT, renderTargetParameters );
finalcomposer = new THREE.EffectComposer( renderer, renderTarget );

finalcomposer.addPass( renderModel );
finalcomposer.addPass( finalPass );

//RENDER
//-----------
oclcomposer.render(0.1);
finalcomposer.render( 0.1 );

@bbiswas Tenho o mesmo problema com a versão mais recente. Você descobriu alguma coisa?

Sim, consegui fazer funcionar - aqui está o código

var renderTargetOcl = new THREE.WebGLRenderTarget( webGL_window_width/4, webGL_window_height/4, renderTargetParameters );

            hblur = new THREE.ShaderPass( THREE.ShaderExtras[ "horizontalBlur" ] );
            vblur = new THREE.ShaderPass( THREE.ShaderExtras[ "verticalBlur" ] );

            var bluriness = 3;

            hblur.uniforms[ 'h' ].value = bluriness / webGL_window_width*2;
            vblur.uniforms[ 'v' ].value = bluriness / webGL_window_height*2;

            var renderModel = new THREE.RenderPass( scene, camera );
            var renderModelOcl = new THREE.RenderPass( g_occlusion_buffer, g_occlusion_camera );

            grPass = new THREE.ShaderPass( THREE.Extras.Shaders.Godrays );
            grPass.needsSwap = true;
            grPass.renderToScreen = false;

            g_volumetric_light_composer = new THREE.EffectComposer( webGLRenderer, renderTargetOcl );

            g_volumetric_light_composer.addPass( renderModelOcl );
            g_volumetric_light_composer.addPass( hblur );
            g_volumetric_light_composer.addPass( vblur );
            g_volumetric_light_composer.addPass( hblur );
            g_volumetric_light_composer.addPass( vblur );
            g_volumetric_light_composer.addPass( grPass );

            var finalPass = new THREE.ShaderPass( THREE.Extras.Shaders.Additive );
            finalPass.needsSwap = true;
            finalPass.renderToScreen = true;
            finalPass.uniforms[ 'tAdd' ].value = g_volumetric_light_composer.renderTarget1;

            finalcomposer.addPass( renderModel );
            finalcomposer.addPass( finalPass );

//in Render Loop



                g_occlusion_camera.position = camera.position;

                g_occlusion_camera.lookAt( new THREE.Vector3(0,0,0) );
                camera.lookAt( new THREE.Vector3(0,0,0)  );

                vlight.position = pointLight1.position;
                vlight.updateMatrixWorld();

                var lPos = THREE.Extras.Utils.projectOnScreen(pointLight1, camera);
                grPass.uniforms["fX"].value = lPos.x;
                grPass.uniforms["fY"].value = lPos.y;

                g_volumetric_light_composer.render(0.1);
                finalcomposer.render( 0.1 );

Muito obrigado!
Era a linha com finalPass.uniforms[ 'tAdd' ].value . Eu tinha finalPass.uniforms[ 'tAdd' ].texture antes.

Ei bbiswas, você pode adicionar onde criou g_occlusion_buffer para esta parte:

var renderModelOcl = new THREE.RenderPass (g_occlusion_buffer, g_occlusion_camera);

Parece que a demonstração original não está mais funcionando:

FWIW Fiz uma demonstração simplificada de aplicação seletiva de FX e composição via Additive Blend (usando Three.js v79) aqui: https://www.airtightinteractive.com/demos/selective-fx/

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

mrdoob picture mrdoob  ·  66Comentários

goodsign picture goodsign  ·  101Comentários

RicoLiu picture RicoLiu  ·  100Comentários

WaltzBinaire picture WaltzBinaire  ·  67Comentários

mrdoob picture mrdoob  ·  75Comentários