この記事はアドカレに参加しています。
グラデーションを考える2
二次元空間でのグラデーションを考えていきます。
グラデーションを考えるとは違うタイプのグラデーションです。
コード
ソースコードを以下に示します。LuaJitを使用しているので、お持ちでない方はこちらから導入しておいてください。
<?--テキストボックスに貼っておいて、グロ変で流す
--sqrt
local function sq(x,y)
return math.sqrt(x*x+y*y)
end
--切り捨てとか
local function d(a)
if(a<0)then a=0
elseif(a>255)then a=255
else a=math.floor(a)
end
return a
end
--ピクセル座標から色を求める関数
function me(x,y)
local r,g,b=0,0,0
local k={}
for i=0,3 do--各点との距離を求める
k[i+1]=sq(pos[i*3+1]-x,pos[i*3+2]-y)
end
for i=0,3 do--逆2乗の法則で
if(k[i+1]==0)then
k={0,0,0,0}
k[i+1]=1
break
else
k[i+1]=1/(k[i+1]*k[i+1])
end
end
local s=0
for i=0,3 do
s=s+k[i+1]
end
for i=0,3 do
local e=k[i+1]/s
r=r+RT[i+1]*e
g=g+GT[i+1]*e
b=b+BT[i+1]*e
end
return d(r),d(g),d(b)
end
?>
--グラデしたいオブジェクトにこっちを貼り付ける
--ffiのロード
local ffi=require"ffi"
--RGBA形式の構造体定義
pcall(ffi.cdef,[[
typedef struct Pixel_ {
uint8_t b,g,r,a;
} Pixel;
]])
--dataの取得
local data,w,h=obj.getpixeldata()
--キャスト
local cdata=ffi.cast("Pixel*",data)
--色関連
local ColorTable={0xff8e58,0x4dd9ff,0xe5ade0,0x7eb069}
RT,GT,BT={},{},{}
for i=1,4 do RT[i],GT[i],BT[i]=RGB(ColorTable[i]) end
--座標関連(xyzが必要。実際に使うのはxyだけ
pos={-200,-200,0,200,-200,0,-200,200,0,200,200,0}
for i=0,3 do
pos[i*3+1]=pos[i*3+1]+w/2
pos[i*3+2]=pos[i*3+2]+h/2
end
--ピクセル操作
for y=0,h-1 do
for x=0,w-1 do
local p=cdata+y*w+x
p.r,p.g,p.b=me(x,y)
end
end
--dataをはりつけ
obj.putpixeldata(data)
解説
上記のコードは、4色でのグラデーションを行います。
4つの座標とそれと対応するカラーコードでピクセルごとの色を決定していきます。
ピクセル操作については、LuaJIT FFI で高速ピクセル操作を見るといいです。
さて、ピクセルごとに色を決定していきますが、このときにピクセルの場所と4つの座標とで距離を求めて、その距離をもとに色に重みをつけていきます。
例えば、一つ目の座標とピクセルの距離が近ければ、ピクセルの色は一つ目の座標の示す色に近くなります。二つ目の座標とピクセルの距離が近ければ、ピクセルの色は二つ目の座標の示す色に近くなります。
ここで、逆2乗の法則を使用して自然にグラデーションするように色に重みを付けます。
纏めると、
- 座標とピクセルの距離を求める。
- 距離を逆2乗する。
- 2の結果の総和を求める。
- 3で求めた総和と2の結果をもとにピクセルの色を決定する。
…こんなかんじになります。
おわりに
今回は4色のグラデーションでしたが、同じような流れで5,6,7色以上のグラデーションも簡単にできます。とはいえ、除算があるので処理にはどうしても時間がかかります。
いつかadobeさんの4色グラデーションのコードを覗きたいですね。