🌉

Three.jsで板ポリに貼るテクスチャのアスペクト比を維持する

SHARE

TABLE OF CONTENTS

    🌉

    Three.jsで板ポリに貼るテクスチャのアスペクト比を維持する

    WebGLやThree.jsのGLSLで板ポリに貼るテクスチャのアスペクト比を維持する方法を備忘録としてまとめました。
    実際に自分が使用しているデモの例になります。

    コード全体

    ※ Three.jsのShaderMaterialを使用しているため、precision 宣言等のライブラリ内部でよしなにおこなっているコードは記述していません。

    FragmentShader

    varying vec2 vUv;
    uniform vec2 uTextureSize;
    uniform vec2 uPlaneSize;
    uniform sampler2D uTexture;
    
    vec2 optimizationTextureUv(vec2 uv, float pa, float ta){
      vec2 ratio = vec2(
        min(pa / ta, 1.0),
        (min((1.0 / pa) / (1.0 / ta), 1.0))
      );
      return vec2(
        ((uv.x - 0.5) * ratio.x + 0.5),
        ((uv.y - 0.5) * ratio.y + 0.5)
      );
    }
    
    void main( void ) {
      vec2 uv = optimizationTextureUv(vUv, (uPlaneSize.x / uPlaneSize.y), (uTextureSize.x / uTextureSize.y));
      gl_FragColor = texture2D(uTexture, uv);
    }

    VertexShader

    varying vec2 vUv;
    void main(){
      vUv = uv;
       gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0 );
    }

    JS

    const m = new THREE.ShaderMaterial({
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
      uniforms: {
        uTexture: { value: this.texture },
        uTextureSize: { value: new THREE.Vector2(1280, 720) },
        uPlaneSize: { value: new THREE.Vector2(window.innerWidth;, window.innerHeight) },
      },
    });

    FragmentShaderの内容

    1. Uniform変数について

    • uTextureSize:テクスチャの解像度
    • uPlaneSize:板ポリの縦横サイズ
    • uTexture:テクスチャ

    2. 関数について

    optimizationTextureUv 関数の引数は下記の3つあります。

    • uv:テクスチャ座標
    • pa:板ポリのアスペクト比
    • ta:テクスチャのアスペクト比

    vec2 ratio でテクスチャと板ポリの解像度を比較し、フィットする割合の値を取得します。
    そして、その値をテクスチャ座標に割り当てます。

    vec2(
      uv.x * ratio.x,
      uv.y * ratio.y
    );

    解像度を割り当てるのみだとリサイズ時に左下基準ででテクスチャが表示されます。
    極端にリサイズするとテクスチャの右側が板ポリからはみ出た状態になります。
    実際に gl_FragColor = vec4(uv, 0.0, 1.0); で色デバッグをすると左下が黒 vec4(vec3(0.0), 1.0); になっており、左下が原点になっていることを確認できると思います。
    左下基準 vec2(0.0, 0.0); になっているテクスチャ座標を中央配置 vec2(0.5, 0.5); になるように修正します。
    イメージとしては下記のCSSようなことをuvにも同様に実装する必要があります。

    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    uvが中央になるように修正します。

    vec2(
      (uv.x - 0.5) * ratio.x + 0.5,
      (uv.y - 0.5) * ratio.y + 0.5
    );

    あとはいつも通りテクスチャを表示するだけです。

    Reference Site

    ©2025 SHOYA KAJITA.