線形補間
昔やった拡大縮小のメソッドを、線形補間に対応させてみた。
実験的に。
昔の記事はこれ。
http://d.hatena.ne.jp/mirichi/20090708/p3
#! ruby -Ks require 'dxruby' class Image def strechRect(x1, y1, w1, h1, image, x2, y2, w2, h2) if image.width < x2 + w2 or image.height < y2 + h2 or self.width < x1 + w1 or self.height < x1 + h1 or x1 < 0 or y1 < 0 or w1 < 0 or h1 < 0 or x2 < 0 or y2 < 0 or w2 < 0 or h2 < 0 raise "座標がはみ出してるようです" end dx = w2.quo(w1) dy = h2.quo(h1) x = x2 y = y2 for i in y1...(y1 + h1) ty1 = y % 1.0 ty2 = 1.0 - ty1 for j in x1...(x1 + w1) s1 = image[x, y] s2 = image[x+1, y] s3 = image[x, y+1] s4 = image[x+1, y+1] tx1 = x % 1.0 tx2 = 1.0 - tx1 s1.map! { |c| tx2 * ty2 * c } s2.map! { |c| tx1 * ty2 * c } s3.map! { |c| tx2 * ty1 * c } s4.map! { |c| tx1 * ty1 * c } self[j, i] = [s1[0]+s2[0]+s3[0]+s4[0], s1[1]+s2[1]+s3[1]+s4[1], s1[2]+s2[2]+s3[2]+s4[2], s1[3]+s2[3]+s3[3]+s4[3]] x = x + dx end x = x2 y = y + dy end return self end end image0 = Image.new(100,100).circleFill(49,49,49, [255,0,255,0]). # もとねた circleFill(49,49,30, [255,128,128,0]) image1 = Image.new(50,50) # 縮小先 image2 = Image.new(200,200) # 拡大先 image1.strechRect(0, 0, 50, 50, image0, 0, 0, 100, 100) # 縮小 image2.strechRect(0, 0, 200, 200, image0, 10, 10, 50, 50) # 拡大 Window.loop do break if Input.keyPush?(K_ESCAPE) Window.draw(0,0,image0) Window.draw(0,100,image1) Window.draw(0,150,image2) end
真面目にRubyでやると死ぬほど遅い。
Cでやってもそれなりに遅いだろう。
アルゴリズムとしては、ピクセルの中心を(0.0, 0.0)として、右と下と右下の点の色を、端数のぶんだけ合成する。
透明色の計算をきちんとしてないから、色のついてるところに色を置くと輪郭がおかしくなる。
アルファブレンドの処理を追加する必要がある。
また、このやりかただけでは縮小に対応ができない。
縮小のほうは元画像の座標が飛ぶから、間の色を全部足して距離で割る必要がある。
線形補間をリアルタイムにやるならソフトウェアでやるべきではない。RGSSも単純拡縮しかしていない。
このアルゴリズムでは左上(0.0, 0.0)から始まるから、右下のピクセルを描画するときに元画像の範囲からはみ出した色を合成する。
画像の中心を拡大縮小の中心におくと、左上のピクセルも左上にはみ出した色を合成する。
DirectXはこのへん真面目にそのままやっているため、拡大したときに指定テクスチャ範囲外の色を拾ってしまう。
昨日の記事のコメントのtotobook氏の指摘はその問題のことで、DirectXの固定機能パイプラインを使う限り、なんらかの細工で対策するしか手が無い。
とりあえず拡大縮小アルゴリズムについてもDirectXについてもぜんぜん知識が足りてないから、勉強しつつ対策を考えていこうと思う。