のぐそんブログ

暗いおじさんがシコシコ書くブログです。

THREE.jsのEffectComposerでオリジナルのポストプロセスをやってみる

前回「THREE.jsでオリジナルのポストプロセスをやってみる」と題しましてポストプロセスについての記事を書きました。

よくよく調べると、THREE.jsにはポストプロセスを行う仕組み自体が用意されており、それを利用すればオリジナルのポストプロセスも簡単に書くことができました。

やってみる

オリジナルのポストプロセスを行うには下記のファイルが必要です。

JS

ShaderPassにShaderMaterialと同じように、unfiforms、vertexShader、fragmentShaderを含んだオブジェクトを追加します。 uniformsには、通常のシーンの描画結果を入れるtDiffuseというテクスチャ型のオブジェクトが必ず必要です。

以下の例では、ポストプロセスで通常のシーンのUV座標をずらすエフェクトをかけています。

var renderer,
    scene,
    camera,
    myCanvas = document.getElementById('myCanvas');

//RENDERER
renderer = new THREE.WebGLRenderer({
    canvas: myCanvas,
    antialias: true
});
renderer.setClearColor(0xffffff);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);

//CAMERA
camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 1;

//SCENE
scene = new THREE.Scene();

//LIGHTS
var light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light);

var material = new THREE.MeshLambertMaterial();
var geometry = new THREE.SphereGeometry(0.1, 20, 20);
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);


//ポストプロセスの設定
//WebGLRendererをラップするためにEffectComposerに渡す
//最終的にはEffectComposerのインスタンスを描画する
var composer = new THREE.EffectComposer(renderer);
//現在のシーンを設定
var renderPass = new THREE.RenderPass(scene, camera);
composer.addPass(renderPass);
//カスタムシェーダー
var myEffect = {
    uniforms: {
        "tDiffuse": {
            value: null,
            type: 't'
        },
        "amount": {
            value: 1.0,
           type:'f'
        }
    },
    vertexShader: [
        "varying vec2 vUv;",
        "void main() {",
        "vUv = uv;",
        "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
        "}"
    ].join("\n"),
    fragmentShader: [
        "uniform float amount;",
        "uniform sampler2D tDiffuse;",
        "varying vec2 vUv;",
        "void main() {",
        "vec4 color = texture2D( tDiffuse, vUv );",
        "gl_FragColor = vec4( color.rgb , color.a );",
        "gl_FragColor.r = texture2D( tDiffuse, vUv + vec2(0.1,0.0)).r;",
        "gl_FragColor.g = texture2D( tDiffuse, vUv - vec2(0.1,0.0)).g;",
        "}"
    ].join("\n")
}

//エフェクト結果をスクリーンに描画する
var customPass = new THREE.ShaderPass(myEffect);
customPass.renderToScreen = true;
composer.addPass(customPass);

render();


function render() {

    composer.render();

    requestAnimationFrame(render);
}

まとめ

THREE.EffectComposerを使うと、オフスクリーンレンダリング明示的にやらなくてよかったり、画面全体を覆うポリゴンを作る必要がなかったりとポストプロセスを行う上で手間がかからない印象でした。 また、ShaderMaterialを使わなくてもシェーダーを定義することができるので、ライトをつかえるなど私のような初心者にはメリットが多そうでした。