JavaScript
WebGL
pixi.js

Pixi.jsでどんなアスペクト比の画像でも正しくuv座標を取る方法

Pixi.jsを使っていて詰まったところをメモ。
任意のアスペクト比の画像に対して同じようにwebglのエフェクトを掛けようとする時、一手間が必要になります。
具体的には mappedMatrix という変換行列を用意してあげて、これをfilterに適用します。

let cvs = document.getElementById('cvs')
cvs.width = 800
cvs.height = 600

let renderer = new PIXI.WebGLRenderer(cvs.width, cvs.height, {view: cvs, antialias: true} )
let container = new PIXI.Container()

let img = new Image()
img.src = "/images/detail/" + imgID + ".jpg";


img.onload = function(){
  let sprite = new PIXI.Sprite(new PIXI.Texture(new PIXI.BaseTexture(img)))
  sprite.width = cvs.width
  sprite.height = cvs.height
  container.addChild(sprite)
  renderer.render(container)
}


let frag =
   `precision mediump float;
    uniform vec4 filterArea;
    uniform sampler2D uSampler;
    uniform mat3 mappedMatrix;
    uniform float val;
    varying vec2 vTextureCoord;
    void main (void) {
     vec3 map = vec3(vTextureCoord.xy, 1) * mappedMatrix;
     vec4 col = texture2D(uSampler, vTextureCoord);
     if(map.x > val) 
       gl_FragColor = texture2D(uSampler, vec2(val, vTextureCoord.y));
     else
       gl_FragColor = col;
   }`
   .split('\n').reduce((c, a) => c + a.trim() + '\n')


let uniforms = {
  val: { type: 'float', value: 0 },
  mappedMatrix : { type: 'mat3', value: new PIXI.Matrix() }
};


let filter = new PIXI.Filter(null, frag, uniforms);


filter.apply = function (filterManager, input, output){
  filterManager.calculateNormalizedScreenSpaceMatrix(uniforms.mappedMatrix.value)
  filterManager.applyFilter(this, input, output);
};


container.filters = [filter]


function update(){
  uniforms = {
    val: { type: 'float', value: 1 },
    mappedMatrix : { type: 'mat3', value: new PIXI.Matrix() }
  };
  filter = new PIXI.Filter(null, frag, uniforms);
  container.filters = [filter]
  renderer.render(container)
  requestAnimationFrame(update)
}


update();

ご参考までに!