ベジェ曲面による画像変形
ベジェ曲面とは
ベジェ曲面とはベジェ関数で補間された曲面のことです。
ベジェ曲面を用いて画像を変形するスクリプトを作りました。luajitで動きます。
プログラム
code:ベジェ変形_M(luajit).lua
--[[
ベジェ変形_M(luajit).anm
ベジェ曲面を用いて画像を変形します。
luajit実装版です。
]]
--track0:size,0,800,100,0.01
--track1:line,1,100,10,0.01
--track2:dot,1,100,30,1
--track3:bezier,1,50,10,1
--check0:help,1
--dialog:set_anchor,pos={-300,-300,-100,-300,100,-300,300,-300,-300,-100,-100,-100,100,-100,300,-100,-300,100,-100,100,100,100,300,100,-300,300,-100,300,100,300,300,300,};
--リサイズ
obj.effect("リサイズ","拡大率",obj.track0)
--アンカー取得
local n=obj.setanchor("pos",16)
if(n<16)then
end
--ベクトル定義(メタテーブル)
local vec={}
local function new_vec(x,y)
local a={x,y}
return setmetatable(a,vec)
end
local function tcheck(a) return getmetatable(a)==vec and "vec" or type(a) end
local function chengeVec(a) return tcheck(a)=="vec" and a or new_vec(a,a) end
function vec.__index(p,key) return key=="x" and p1 or p2 end function vec.__add(a,b)
a,b=chengeVec(a),chengeVec(b)
return new_vec(a.x+b.x,a.y+b.y) end
function vec.__sub(a,b)
a,b=chengeVec(a),chengeVec(b)
return new_vec(a.x-b.x,a.y-b.y) end
function vec.__mul(a,b)
a,b=chengeVec(a),chengeVec(b)
return new_vec(a.x*b.x,a.y*b.y) end
--配列pにはピクセル基準の座標を入れる
local p={}
for i=0,15 do pi+1=new_vec(posi*2+1+obj.w/2,posi*2+2+obj.h/2) end --ffi
local work,data,w,h=obj.getpixeldata"work",obj.getpixeldata()
local ffi=require("ffi")
pcall(ffi.cdef,typedef struct Pixel_ {uint8_t b,g,r,a;} Pixel;)
local cdata=ffi.cast("uint32_t*",data)
local cwork=ffi.cast("uint32_t*",work)
--workを初期化
for i=0,w*h-1 do cworki=0x00000000 end --三次関数
local function BezierLineC(c,t) return ((c1*t+c2)*t+c3)*t+c4 end --制御点->三次関数の係数
local function BezierCoefficient(p1,p2,p3,p4)
local c={}
c1 = -1 * p1 + 3 * p2 - 3 * p3 + 1 * p4 c2 = 3 * p1 - 6 * p2 + 3 * p3 return c
end
local function ch(ox,oy,w,h)
if (ox < 0 or ox >= w)then return false end
if (oy < 0 or oy >= h)then return false end
return true
end
local c={} --三次関数の係数(縦方向)
c1=BezierCoefficient(p1,p5,p9,p13) c2=BezierCoefficient(p2,p6,p10,p14) c3=BezierCoefficient(p3,p7,p11,p15) c4=BezierCoefficient(p4,p8,p12,p16) local function dcast(a) return math.floor(a+0.5) end
for y=0,h-1 do
local cx,yh={},y/h
cx1,cx2=BezierLineC(c1,yh),BezierLineC(c2,yh) cx3,cx4=BezierLineC(c3,yh),BezierLineC(c4,yh) cx=BezierCoefficient(cx1,cx2,cx3,cx4) for x=0,w-1 do
local pt=BezierLineC(cx,x/w)
pt.x,pt.y=dcast(pt.x),dcast(pt.y)
end
end
obj.putpixeldata(work)
obj.effect() obj.draw()
local function drawLine(x1,y1,x2,y2,width,color,alpha)
local dx,dy=x2-x1,y2-y1
local s=width*.5/math.sqrt(dx*dx+dy*dy)
dx,dy=dx*s,dy*s
obj.load("figure","四角形",color,1)
obj.drawpoly(
x1+dy, y1-dx, 0,
x2+dy, y2-dx, 0,
x2-dy, y2+dx, 0,
x1-dy, y1+dx, 0,
0,0,1,0,1,1,0,1,
alpha or 1)
end
local function line(pos,num)
num=2*num
end
local function bline(c)
local p1,p2=BezierLineC(c,0)
for i=1,obj.track3 do
p2=BezierLineC(c,i/obj.track3)
drawLine(p1.x,p1.y,p2.x,p2.y,obj.track1,0xfffe68)
p1=p2
end
end
local function bline4()
local d=new_vec(-w/2,-h/2)
bline(c1) bline(c2) bline(c3) bline(c4) end
if(obj.check0==true)then
bline4()--縦方向のベジェ曲線
c1=BezierCoefficient(p1,p2,p3,p4) c2=BezierCoefficient(p5,p6,p7,p8) bline4()--横方向のベジェ曲線
line(pos,0) line(pos,4) line(pos,8) line(pos,12)
local function swap(a,b)
local a2,b2=2*a+1,2*b+1
end
swap(1,4) swap(2,8) swap(3,12)
swap(6,9) swap(7,13) swap(11,14)
line(pos,0) line(pos,4) line(pos,8) line(pos,12)
obj.load("figure","円",0x68fffe,obj.track2)
for i=0,15 do
obj.draw(pi+1.x-w/2,pi+1.y-h/2) end
end
pos=nil
反省点
本来は細かい四角形や三角形に分割するらしいのですが、めんどくさいのでただのピクセル移動です。リサイズして誤魔化してください。
luajitだとc++ver.ほどの速度はでませんでした。アルゴリズムとか見直したんですけどね。残念です。c++ver.はdiscodeで配布していますので、よければどうぞ。
ピクセル毎の画像処理ということで、GPU向けの処理ですね。他の方が作ったベジェ曲面のレンダリングプログラムの中にはOpenGLを使用していたものも見受けられました。僕もいつかGPUでのベジェ曲面にチャレンジしてみたいですね。
by metaphysical bard