🌃

WebGLRenderTargetでオフスクリーンレンダリングする

SHARE

TABLE OF CONTENTS

    🌃

    WebGLRenderTargetでオフスクリーンレンダリングする

    概要

    WebGLRenderTargetでオフスクリーンレンダリングするフローをメモしました。

    ※ Three.js r156

    フレームバッファオブジェクトの生成

    // fbo作成
    const size = 1024;  // テクスチャの解像度
    const fbo = new THREE.WebGLRenderTarget(size, size);

    フレームバッファオブジェクト用のシーンを作成

    const fboScene = new THREE.Scene();

    テクスチャを板ポリに貼り付ける

    画面サイズぴったりにする場合は板ポリのサイズを2にします。

    サイズが2の理由は gl_Position の座標系が下記の画像のように「-1.0 ~ 1.0」の正規化デバイス座標空間になるためです。

    gl_Positionの座標
    const geometry = new THREE.PlaneGeometry(2, 2, 1, 1);
    const material = new THREE.ShaderMaterial({
      fragmentShader: fragmentShader,
      vertexShader: vertexShader,
      uniforms: {
        uTexture: { type: "t", value: this.fbo.texture },
      },
    });
    const fboMesh = new THREE.Mesh(geometry, material);
    fboScene.add(fboMesh);
    // fragment shader
    uniform sampler2D uTexture;
    varying vec2 vUv;
    
    void main( void ) {
      vec4 t = texture2D(uTexture, vUv);
      gl_FragColor = LinearTosRGB(t);
    }

    LinearTosRGB で出力しているのは WebGLRenderTargetで色味が変わってしまう で確認してください🙏

    // vertex shader
    varying vec2 vUv;
    
    void main(){
      vUv = uv;
      gl_Position = vec4(position, 1.0);
    }

    レンダリング

    1. フレームバッファをバインドする(有効化)
    2. レンダリング結果をフレームバッファのテクスチャに焼き付ける
    3. フレームバッファのバインドを解除する
    4. 板ポリのシーンをレンダリングする
    // requestAnimationFrame
    renderer.setRenderTarget(fbo);
    renderer.render(scene, camera);
    
    renderer.setRenderTarget(null);
    renderer.render(fboScene, camera);

    その他

    解像度をデバイスによって調整する

    ▼ 解像度を固定している場合 ▼

    sphereがギザギザしている

    ▼ 解像度をデバイスによって変更している場合 ▼

    sphereのギザギザが少し滑らかになった
    const clamp = (num, min, max) => {
      return min > num ? min : max < num ? max : num;
    };
    const pixelRatio = clamp(window.devicePixelRatio, 1, 2);
    const size = 1024;
    const fbo = new THREE.WebGLRenderTarget(size * pixelRatio, size * pixelRatio);

    WebGLRenderTargetのオプションについて

    const type = /(iPad|iPhone|iPod)/g.test(navigator.userAgent) ? THREE.HalfFloatType : THREE.FloatType;
    const pixelRatio = clamp(window.devicePixelRatio, 1, 2);
    const size = 1024;
    
    const fbo = new THREE.WebGLRenderTarget(size * pixelRatio, size * pixelRatio, {
      // 深度バッファ
      depthBuffer: false,
    
      // ステンシルバッファ
      stencilBuffer: false,
    
      // フォーマット
      format: THREE.RGBAFormat,
    
      // テクスチャのタイプ
      type: THREE.UnsignedByteType,
      
      // 出力時のエンコード設定
      colorSpace: THREE.SRGBColorSpace,
      // THREE.NoColorSpace: 
      // THREE.SRGBColorSpace: 
      // THREE.LinearSRGBColorSpace: 
      
      // テクスチャが拡大縮小するときの設定
      magFilter: THREE.LinearFilter,
      minFilter: THREE.LinearFilter,
      // THREE.LinearFilter: 対象のピクセルに近い4つのピクセルから平均した色になる
      // THREE.NearestFilter: 対象のピクセルに最も近い色になる
    
      // テクスチャのラッピングの設定
      wrapS: THREE.ClampToEdgeWrapping, // st.s === uv.x
      wrapT: THREE.ClampToEdgeWrapping, // st.t === uv.y
      // THREE.RepeatWrapping: 無限に繰り返す
      // THREE.ClampToEdgeWrapping: テクスチャの端のピクセルがメッシュの端まで引き伸ばされる
      // THREE.MirroredRepeatWrapping: 無限に繰り返しながら繰り返しでミラーリングする
    });

    参考サイト

    ©2025 SHOYA KAJITA.