Three.js: [EffectComposer] Problem mit 2 aufeinanderfolgenden RenderPass

Erstellt am 1. Feb. 2012  ·  18Kommentare  ·  Quelle: mrdoob/three.js

Der Link

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

Der 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

Der Kontext

Ich habe zwei Szenen mit demselben Objekt / Kamera / Licht. Eine mit der diffusen Textur (http://demo.bkcore.com/threejs/webgl_tron.html) und eine mit einer leuchtenden Textur (leuchtende Bereiche sind weiß auf schwarz).

Meine Rendering-Pipeline lautet wie folgt:
Ich rendere zuerst die Glühenszene und wende eine H / V-Unschärfe darauf an. Dann speichere ich die Ausgabe mit einem SavePass in einem FrameBuffer.
Dann möchte ich die diffuse Szene rendern.
Und zum Schluss mischen Sie das mit dem Glow Framebuffer.

Die Angelegenheit

Mein Glow Sampler2D wird gut an meinen finalPass-Shader übergeben, aber wie Sie in der Demo sehen können, funktioniert der zweite RenderPass-Aufruf für die diffuse Szene nicht gut. Es wird nur Schwarz ausgegeben.

Ich habe versucht, die diffuse Szene in einem einzigen Render-Durchgang zu rendern, und das funktioniert. Wenn ich es als zweiten RenderPass verwende, funktioniert es nicht.

Irgendwelche Ideen ?

Vielen Dank.
Thibaut D.

Question

Hilfreichster Kommentar

Scheint, als ob die ursprüngliche Demo nicht mehr funktioniert:

FWIW Ich habe hier eine reduzierte Demo zum selektiven Anwenden von FX und Komponieren über Additive Blend (unter Verwendung von Three.js v79) erstellt: https://www.airtightinteractive.com/demos/selective-fx/

Alle 18 Kommentare

Ich denke, das liegt daran, dass der Tiefenpuffer zerstört wird, siehe # 1017.

Für Ihren Anwendungsfall können stattdessen zwei Komponisten (und damit zwei vollständig separate Renderziele mit jeweils eigenem Tiefenpuffer) verwendet werden.

Etwas wie das:

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

Jetzt ist die diffuse Ebene als regulärer tDiffuse Textur-Sampler in finalComposer und als Glow-Ebene verfügbar, die Sie ab glowComposer liefern.

Es wird entweder glowComposer.renderTarget1 oder glowComposer.renderTarget2 abhängig von der Anzahl der Durchgänge und davon, ob die Durchgänge die vorderen und hinteren Puffer wechseln. Am einfachsten ist es, beide zu versuchen und zu sehen, welche funktionieren.

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

Ich habe das versucht, aber ein sehr unerwartetes Ergebnis erzielt.

Dies ist der Code, den Sie vorgeschlagen haben:
http://demo.bkcore.com/threejs/webgl_tron_glow_swap.html
Die tDiffuse aus dem renderModel ist immer noch schwarz.

Und dies ist genau derselbe Code, bei dem nur die beiden Renderpässe vertauscht sind (die diffuse Szene befindet sich im Glow Composer und die Glow-Szene im endgültigen Composer):
http://demo.bkcore.com/threejs/webgl_tron_glow_swap2.html
Es ist natürlich nicht das Effet, nach dem ich suche, da das Diffuse verschwommen ist und nicht das Leuchten, aber wie Sie sehen können, funktionieren sowohl tGlow- als auch tDiffuse-Sampler ...

Und alles was ich getan habe war zu tauschen (Zeile 130 & 175):
neuer THREE.RenderPass (Szene, Kamera);
mit
neuer THREE.RenderPass (Glowscene, Glowcamera);

Es ist ziemlich verblüffend.

Sie müssen das Format RGBA zum Rendern von Zielen verwenden, wenn Sie Transparenz verwenden.

Nun, ich stimme zu, aber ich verwende keine Transparenz, da mein Glühpass Weiß auf Schwarz und mein diffuser Pass gut ... diffus auf Schwarz darstellt. Ich komponiere sie dann mit einem Zusatz, damit keine Transparenz benötigt wird.

Trotzdem habe ich das RT-Format auf RGBA geändert, aber das hat nichts geändert.

Das seltsame Problem hierbei ist, dass das Ausführen des RenderPass für meine Szene / Kamera nach meiner RowsPass / Glowcamera nicht funktioniert, während der RenderPass für meine Szene / Kamera vor dem RenderPass für meine Glowscene / Glowamera ausgeführt wird.

Hmmm, scheint ein Problem mit der gemeinsamen Nutzung von Geometrie für verschiedene Materialien zu sein (siehe # 1211).

Versuche dies:

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

    // ...
}

Ja ! Das war's.

Meine beiden Sampler sind jetzt korrekt gefüllt. Vielen Dank :)

BEARBEITEN

Hum ... Noch ein seltsames Verhalten, meine beiden Sampler sind gut, wenn ich es tue

gl_FragColor = texel;

Ich bekomme das diffuse richtig (http://demo.bkcore.com/threejs/webgl_tron_glow_swap2.html)

Wenn ich es tue

gl_FragColor = glow;

Ich bekomme das Leuchten richtig.

Aber wenn ich versuche, eine einfache additive Mischung auf beiden zu machen
gl_FragColor = texel + glow;
Ich bekomme nur das Leuchten (http://demo.bkcore.com/threejs/webgl_tron_glow_swap.html).

Es tut mir leid, dass ich so viele Fragen gestellt habe. Ich habe versucht, dies zum Laufen zu bringen, aber ohne Erfolg.

EDIT2

In der Tat scheint es, dass zu tun

gl_FragColor = texel + glow;

Sieht beim Rendern der Ausgabe eher so aus:

gl_FragColor = glow + glow;

Es ist, als würde das Texel vec4 unerklärlicherweise durch das Glühen vec4 ersetzt. Klingt verrückt.

Sie müssen Texturen in verschiedene Textureinheiten einfügen:

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

Sommer!

Für den Fall, dass jemand Interesse an selektivem Glow-Rendering mit Three.js hat, habe ich gerade einen kleinen Artikel darüber veröffentlicht: http://bkcore.com/blog/3d/webgl-three-js-animated-selective-glow.html

Ich hoffe es hilft.

Nett ;)

Alternativ wäre anstelle des Klonens von Geometrie eine andere billigere Option die Verwendung ähnlicherer Materialien (so dass die Geometrie in beiden Durchgängen dieselben Puffer benötigt).

In diesem Fall können Sie anstelle von Basismaterial für den Glühdurchgang Lambert-Material ohne diffuse Beleuchtung und nur mit Umgebungslicht verwenden.

Etwas wie das:

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

// ...

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

In der Tat funktioniert das perfekt.

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

Ich werde meinen Artikel zu dieser Lösung aktualisieren. Vielen Dank !

Ich portiere diesen Code auf r60 und stoße seltsamerweise auf dasselbe Problem bei der Verkettung der Effektkomponisten. Ich habe den Godray-Pass zum Laufen gebracht, wenn ich ihn auf dem Bildschirm wiedergebe. Der letzte Durchgang gibt jedoch nur das Modell aus. Die Ausgabe des oclcomposer an den "tadd" -Texturkanal scheint in Ordnung zu sein, wenn ich keinen separaten Effect Composer verwende !! Ich habe es mit renderer.PreserveDrawingBuffer = true versucht, aber das hat auch nicht funktioniert. Ich habe versucht, Autoclear auf false zu setzen, aber das war es nicht.

Wenn ich den oclcomposer nach dem endgültigen Komponisten rendere und die Ausgabe von Godray an den Bildschirm weitergebe, sehe ich die Godrays, aber keine Modelle.

Anstatt die Ausgabe von oclcomposer im letzten Durchgang auf den Tadd-Kanal zu lenken, kann ich jetzt das Modell und die Godrays (in einer Ebene) sehen, wenn ich sie an ein MeshBasicMaterial weitergebe, ein strukturiertes Quad erstelle und es der Hauptszene hinzufüge der Effekt, den ich will, aber es sagt mir, dass die Textur-Piping funktioniert.

// 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 Ich habe das gleiche Problem mit der neuesten Version. Hast du etwas herausgefunden?

Ja, ich habe es zum Laufen gebracht - Hier ist der 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 );

Vielen Dank!
Es war die Zeile mit finalPass.uniforms[ 'tAdd' ].value . Ich hatte vorher finalPass.uniforms[ 'tAdd' ].texture .

Hey bbiswas, kannst du hinzufügen, wo du g_occlusion_buffer für diesen Teil erstellt hast:

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

Scheint, als ob die ursprüngliche Demo nicht mehr funktioniert:

FWIW Ich habe hier eine reduzierte Demo zum selektiven Anwenden von FX und Komponieren über Additive Blend (unter Verwendung von Three.js v79) erstellt: https://www.airtightinteractive.com/demos/selective-fx/

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen