TABLE OF CONTENTS
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
);
あとはいつも通りテクスチャを表示するだけです。