Three.js: [EffectComposer] Problème avec 2 RenderPass consécutifs

Créé le 1 févr. 2012  ·  18Commentaires  ·  Source: mrdoob/three.js

Le lien

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

Le code

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

Le contexte

J'ai eu deux scènes avec le même objet / caméra / lumière. Un avec la texture diffuse (http://demo.bkcore.com/threejs/webgl_tron.html) et un avec une texture éclatante (les zones brillantes sont blanc sur noir).

Mon pipeline de rendu est le suivant:
Je commence par rendre la scène luminescente et j'y applique un flou H / V, puis je stocke la sortie dans un frameBuffer à l'aide d'un SavePass.
Ensuite, je veux rendre la scène diffuse.
Et enfin mélanger cela avec le framebuffer glow.

Le problème

Mon glow sampler2D passe bien à mon shader finalPass, mais comme vous pouvez le voir dans la démo, le deuxième appel RenderPass pour la scène diffuse ne fonctionne pas bien. Il ne produit que du noir.

J'ai essayé de rendre la scène diffuse en une seule passe de rendu et cela fonctionne. C'est lorsque je l'utilise comme deuxième RenderPass que cela ne fonctionne pas.

Des idées ?

Je vous remercie.
Thibaut D.

Question

Commentaire le plus utile

On dirait que la démo originale ne fonctionne plus:

FWIW J'ai fait une démo simplifiée de l'application sélective d'effets et de la composition via Additive Blend (en utilisant Three.js v79) ici: https://www.airtightinteractive.com/demos/selective-fx/

Tous les 18 commentaires

Je pense que c'est parce que le tampon de profondeur est détruit, voir # 1017.

Pour votre cas d'utilisation, ce qui peut fonctionner à la place est d'utiliser deux compositeurs (et donc deux cibles de rendu complètement séparées, chacune avec son propre tampon de profondeur).

Quelque chose comme ça:

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

Maintenant, la couche diffuse sera disponible en tant qu'échantillonneur de texture normal tDiffuse dans finalComposer et la couche luminescente sera fournie à partir de glowComposer .

Ce sera soit glowComposer.renderTarget1 ou glowComposer.renderTarget2 selon le nombre de passes et si les passes commutent les tampons avant et arrière, le plus simple est d'essayer les deux et de voir ce qui fonctionne.

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

J'ai essayé cela, mais j'ai obtenu un résultat très inattendu.

Voici le code que vous avez proposé:
http://demo.bkcore.com/threejs/webgl_tron_glow_swap.html
Le tDiffuse du renderModel est toujours noir.

Et ceci, c'est exactement le même code, avec juste les deux passes de rendu échangées (la scène diffuse est dans le composeur de lueur, et la scène de lueur dans le composeur final):
http://demo.bkcore.com/threejs/webgl_tron_glow_swap2.html
Ce n'est bien sûr pas l'effet que je recherche car le diffus est flou et non la lueur, mais comme vous pouvez le voir, les échantillonneurs tGlow et tDiffuse fonctionnent ...

Et tout ce que j'ai fait a été d'échanger (lignes 130 et 175):
nouveau THREE.RenderPass (scène, caméra);
avec
nouveau THREE.RenderPass (glowscene, glowcamera);

C'est assez surprenant.

Vous devez utiliser le format RGBA pour les cibles de rendu si vous utilisez la transparence.

Bon, je suis d'accord, mais je n'utilise aucune transparence puisque ma glow pass rend blanc sur noir et ma diffuse passe bien ... diffuse sur noir. Je les compose ensuite avec un ajout donc la transparence n'est pas nécessaire.

Pourtant, juste pour être sûr, j'ai changé le format du RT en RGBA, mais cela n'a rien changé.

Le problème étrange ici, c'est que faire ma scène / caméra RenderPass après mon glowscene / glowcamera RenderPass ne fonctionne pas, tout en faisant ma scène / caméra RenderPass avant mon glowscene / glowcamera RenderPass.

Hmmm, cela semble être un problème de partage de géométrie pour différents matériaux (voir # 1211).

Essaye ça:

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 );

    // ...
}

Oui ! C'était ça.

Mes deux échantillonneurs sont maintenant correctement remplis. Je vous remercie :)

ÉDITER

Hum ... Encore un comportement étrange, mes deux samplers sont bons, quand je le fais

gl_FragColor = texel;

J'obtiens le diffus correctement (http://demo.bkcore.com/threejs/webgl_tron_glow_swap2.html)

Quand je fais

gl_FragColor = glow;

J'obtiens correctement la lueur.

Mais quand j'essaye de faire un simple mélange d'additifs sur les deux
gl_FragColor = texel + lueur;
Je ne reçois que la lueur (http://demo.bkcore.com/threejs/webgl_tron_glow_swap.html).

Désolé d'avoir posé autant de questions, j'ai essayé de faire fonctionner cela, mais en vain.

MODIFIER2

En fait, il semble que faire

gl_FragColor = texel + glow;

Cela ressemble plus à ceci concernant la sortie de rendu:

gl_FragColor = glow + glow;

C'est comme si le texel vec4 était inexplicablement remplacé par le glow vec4. Ça a l'air fou.

Vous devez mettre des textures dans différentes unités de texture:

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

Été!

Au cas où quelqu'un serait intéressé par le rendu sélectif avec Three.js, je viens de publier un petit article à ce sujet: http://bkcore.com/blog/3d/webgl-three-js-animated-selective-glow.html

J'espère que cela aide.

Agréable ;)

Alternativement, au lieu du clonage de la géométrie, une autre option moins chère serait d'utiliser plus de matériaux similaires (de sorte que la géométrie dans les deux passes aurait besoin des mêmes tampons).

Dans ce cas, au lieu d'utiliser le matériau de base pour le passage de la lueur, vous pouvez essayer le matériau Lambert avec un éclairage diffus nul, juste avec la lumière ambiante.

Quelque chose comme ça:

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

// ...

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

En effet, cela fonctionne parfaitement.

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

Je mettrai à jour mon article concernant cette solution. Je vous remercie !

Je porte ce code sur r60 et rencontre étrangement le même problème avec l'enchaînement des compositeurs d'effets. Je fais fonctionner le pass godray si je le rend à l'écran. Mais la passe finale ne produit que le modèle. La sortie oclcomposer vers le canal de texture "tadd" semble bien fonctionner quand je n'utilise pas un composeur d'effets séparé !! J'ai essayé avec renderer.PreserveDrawingBuffer = true mais cela n'a pas fonctionné non plus. J'ai essayé de régler autoclear sur false mais ce n'était pas ça.

Si je rend le oclcomposer après le compositeur final et que le godray passe la sortie à l'écran, je peux voir les godrays mais aucun modèle.

Au lieu de diriger la sortie oclcomposer vers le canal tadd lors de la passe finale, si je le dirige vers un MeshBasicMaterial et que je crée un quad texturé et l'ajoute à la scène principale, je peux maintenant voir le modèle et les godrays (sur un plan), pas l'effet que je veux mais cela me dit que le passepoil de texture fonctionne.

// 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 J'ai le même problème avec la dernière version. Avez-vous découvert quelque chose?

Oui, je l'ai fait fonctionner - Voici le code

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 );

Merci beaucoup!
C'était la ligne avec finalPass.uniforms[ 'tAdd' ].value . J'avais finalPass.uniforms[ 'tAdd' ].texture avant.

Hey bbiswas, pouvez-vous ajouter où vous avez créé g_occlusion_buffer pour cette partie:

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

On dirait que la démo originale ne fonctionne plus:

FWIW J'ai fait une démo simplifiée de l'application sélective d'effets et de la composition via Additive Blend (en utilisant Three.js v79) ici: https://www.airtightinteractive.com/demos/selective-fx/

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

jack-jun picture jack-jun  ·  3Commentaires

fuzihaofzh picture fuzihaofzh  ·  3Commentaires

filharvey picture filharvey  ·  3Commentaires

akshaysrin picture akshaysrin  ·  3Commentaires

Horray picture Horray  ·  3Commentaires