サンプルスクリプト
いきなりAPIを羅列するよりも、サンプルスクリプトを見た方が「あぁなるほど」と納得して頂けると思いますので :D
(1) 適当な画像を作り、コピーし、ドキュメントの作成
local w = 512 local h = 300 local idx = mdi_img_offscreen( 0 ) -- offscreenバッファの取得 mdi_img32_resize( idx, w,h ) -- ↑のリサイズ for j = 0,h do for i = 0,w do local r = i local g = j local b = r * g / 255 mdi_img32_pixelset( idx, i,j, r,g,b,255 ) end end local idx2 = mdi_img_offscreen( 1 ) -- 意味も無く新規バッファを作り、 mdi_img32_copy( idx2, idx ) -- そこにコピーして、 mdi_new_img32( idx2 ) -- 画像から新規作成
(2) 32bppレイヤーのネガポジ反転 (重いので小さな画像限定で…)
mdi_undo_layer(); -- レイヤを操作するので、Undoに保存 local w = mdi_width(); local h = mdi_height(); local li = mdi_layer_active(); local bpp = mdi_layer_type( li ); local idx = mdi_img_layer( li ); for j = 0,h do for i = 0,w do -- 32bppの場合 if bpp == 32 then local r,g,b,a = mdi_img32_pixelget( idx, i,j ); mdi_img32_pixelset( idx, i,j, 255-r,255-g,255-b,a ); end end end
(3) アクティブな32bppレイヤに、矩形と楕円を描画する
mdi_undo_layer(); local w = mdi_width(); local h = mdi_height(); local bw = w / 100; local bh = h / 100; local li = mdi_layer_active(); local bpp = mdi_layer_type( li ); local idx = mdi_img_layer( li ); for j = 0,bh do for i = 0,bw do -- こういう判定は、本来for,forの外で行うのがいいんですが :D -- 1bppレイヤの場合 if bpp == 1 then mdi_img1_rect( idx, i*100,j*100, 80,80, 1 ); mdi_img1_ellipse( idx, i*100+10,j*100+10, 60,60, 0 ); end -- 8bppレイヤの場合 if bpp == 8 then mdi_img8_rect( idx, i*100,j*100, 80,80, 255,255 ); mdi_img8_ellipse( idx, i*100+10,j*100+10, 60,60, 0,128 ); end -- 32bppレイヤの場合 if bpp == 32 then local r = math.random() * 255; local g = math.random() * 255; local b = math.random() * 255; mdi_img32_rect( idx, i*100,j*100, 80,80, r,g,b, 255 ); mdi_img32_ellipse( idx, i*100+10,j*100+10, 60,60, 255-r,255-g,255-b, 255 ); end end end
(4) かんたん絵画風フィルタ (id:XELFさんのスクリプトが元ネタ)
mdi_undo_all(); local act = mdi_layer_active() -- アクティブなレイヤ local sourceImage = mdi_img_layer( act ) -- 参照元レイヤとする local newLayer = mdi_layer_add( 32 ) -- レイヤを追加し、 local destImage = mdi_img_layer( newLayer ); -- 追加した新規レイヤに対して描画する math.randomseed( mdi_ms() ) -- 乱数シードの初期化 local w, h = mdi_width(), mdi_height(); local n = w * h / 20 for i = 0,n do local x = math.random() * w local y = math.random() * h local r,g,b,a = mdi_img32_pixelget( sourceImage, x, y ) local r2 = 5 + math.random()*4 mdi_img32_ellipse( destImage, x,y, r2,r2, r,g,b,a ); end
(5) 8bpp画像を使って、32bpp画像から不透明度を抜く
mdi_undo_layer() local idx0 = mdi_img_offscreen( 0 ) local idx1 = mdi_img_layer( 0 ) local w, h = mdi_width(), mdi_height(); mdi_img8_resize( idx0, w, h ) -- 8bpp画像に、円を描画する for i=0,200 do local x = math.random() * w local y = math.random() * h local r2 = 10 + math.random()*40 mdi_img8_ellipse( idx0, x,y, r2,r2, 255,255 ); end -- 32bppレイヤ画像から、8bpp画像を不透明度として引く mdi_img8_sub32( idx1, idx0 ) ||< ** (6) 選択範囲内だけ、ネガポジ反転をする >|| mdi_undo_layer(); -- レイヤを操作するので、Undoに保存 local w = mdi_width(); local h = mdi_height(); local li = mdi_layer_active(); -- アクティブなIndex local bpp = mdi_layer_type( li ); -- そのレイヤのbpp取得 local idx = mdi_img_layer( li ); -- そのレイヤの画像バッファのIndex取得 local sx,sy,sw,sh = mdi_select_range() -- 選択範囲の有効範囲を取得 -- 有効範囲のみ処理 (選択範囲がない場合は、全体になる) for j = sy,sy+sh do for i = sx,sx+sw do -- 32bppの場合 if bpp == 32 then local v = mdi_select_pixelget( i,j ) -- 選択範囲情報の取得 local r,g,b,a = mdi_img32_pixelget( idx, i,j ); -- レイヤ色の取得 mdi_img32_pixelset( idx, i,j, 255-r,255-g,255-b, v ); -- 選択範囲の濃度を元に色反転 end end end
(7) 警告そして終了、ガウスぼかしで華やかな画に
-- モード警告 local num = mdi_layer_num() if num == 0 then mdi_halt( "This script needs 32bpp layer" ) end mdi_undo_all() -- レイヤを新規作成して、加算モードに local idx0 = mdi_img_layer( 0 ) local li = mdi_layer_add( 32 ) mdi_layer_setmode( li, "add" ) local idx1 = mdi_img_layer( li ) local idx2 = mdi_img_offscreen( 1 ) -- コピーを作り、レベル補正で高輝度抽出 mdi_img32_copy( idx2, idx0 ) mdi_img32_level( idx2, 128,255, 0,255, 1.0 ) -- それをガウスぼかしして、新規レイヤへ mdi_img32_gaussblur( idx1, idx2, 5 )
(8) aobench (数十秒以上掛かります)
-------------------------------------------- -- vec.pde -------------------------------------------- function vec_zero() local res = {} res.x = 0 res.y = 0 res.z = 0 return res end function vec_new( x, y, z ) local res = {} res.x = x res.y = y res.z = z return res end function vec_copy( vec ) local res = {} res.x = vec.x res.y = vec.y res.z = vec.z return res end function vec_sub( vec, vecSub ) local res = {} res.x = vec.x - vecSub.x res.y = vec.y - vecSub.y res.z = vec.z - vecSub.z return res end function vec_cross( vec1, vec2 ) local res = {} res.x = vec1.y * vec2.z - vec2.y * vec1.z res.y = vec1.z * vec2.x - vec2.z * vec1.x res.z = vec1.x * vec2.y - vec2.x * vec1.y return res end function vec_len( vec ) local res = vec.x*vec.x + vec.y*vec.y + vec.z*vec.z if res ~= 0 then res = math.sqrt( res ) end return res end function vec_dot( vec1, vec2 ) local res = vec1.x*vec2.x + vec1.y*vec2.y + vec1.z*vec2.z return res end function vec_normalize( vec ) local res = vec_copy( vec ) local d = vec_len( res ) if math.abs( d ) > 1.0e-6 then local invlen = 1.0 / d res.x = res.x * invlen res.y = res.y * invlen res.z = res.z * invlen return res end return res end -------------------------------------------- -- geometry.pde -------------------------------------------- function ray_new( org, dir ) local res = {} res.org = vec_copy( org ) res.dir = vec_copy( dir ) return res end function ray_copy( ray ) local res = {} res.org = vec_copy( ray.org ) res.dir = vec_copy( ray.dir ) return res end function intersection_new() local res = {} res.hit = false res.t = 1.0e+30 res.n = vec_zero() res.p = vec_zero() return res end function intersection_copy( isec ) local res = {} res.hit = isec.hit res.t = isec.t res.n = vec_copy( isec.n ) res.p = vec_copy( isec.p ) return res end function sphere_new( center, radius ) local res = {} res.center = vec_copy( center ) res.radius = radius return res end function sphere_copy( sphere ) local res = {} res.center = vec_copy( sphere.center ) res.radius = sphere.radius return res end function sphere_intersect( isect, sphere, ray ) local rs = vec_sub( ray.org, sphere.center ) local B = vec_dot( rs, ray.dir ) local C = vec_dot( rs, rs ) - ( sphere.radius * sphere.radius ) local D = B * B - C if D > 0.0 then local t = -B - math.sqrt( D ) if (t > 0.0) and (t < isect.t) then isect.t = t isect.hit = true local p = vec_new( ray.org.x + ray.dir.x * t, ray.org.y + ray.dir.y * t, ray.org.z + ray.dir.z * t ) local n = vec_sub( p, sphere.center ) n = vec_normalize( n ) isect.n = vec_copy( n ) isect.p = vec_copy( p ) end end end function plane_new( p, n ) local res = {} res.p = vec_copy( p ) res.n = vec_copy( n ) return res end function plane_intersect( isect, plane, ray ) local d = -vec_dot( plane.p, plane.n ) local v = vec_dot( ray.dir, plane.n ) if math.abs(v) < 1.0e-6 then return end local t = -(vec_dot( ray.org, plane.n ) + d) / v if (t > 0) and (t < isect.t) then isect.hit = true isect.t = t isect.n = vec_copy( plane.n ) isect.p = vec_new( ray.org.x + t * ray.dir.x, ray.org.y + t * ray.dir.y, ray.org.z + t * ray.dir.z ) end end -------------------------------------------- -- ao.pde -------------------------------------------- local NAO_SAMPLES = 8 local sphere = {} sphere[0] = sphere_new( vec_new( -2.0, 0.0, -3.5 ), 0.5 ) sphere[1] = sphere_new( vec_new( -0.5, 0.0, -3.0 ), 0.5 ) sphere[2] = sphere_new( vec_new( 1.0, 0.0, -2.2 ), 0.5 ) local plane = plane_new( vec_new( 0.0, -0.5, 0.0 ), vec_new( 0.0, 1.0, 0.0 ) ) function clamp( f ) local i = f * 255.5 if i < 0 then i = 0 end if i > 255 then i = 255 end return i end function orthoBasis( basis, n ) basis[2] = vec_copy( n ) basis[1] = vec_zero() basis[0] = vec_zero() if (n.x < 0.6) and (n.x > -0.6) then basis[1].x = 1.0 elseif (n.y < 0.6) and (n.y > -0.6) then basis[1].y = 1.0 elseif (n.z < 0.6) and (n.z > -0.6) then basis[1].z = 1.0 else basis[1].x = 1.0 end basis[0] = vec_cross( basis[1], basis[2] ) basis[0] = vec_normalize( basis[0] ) basis[1] = vec_cross( basis[2], basis[0] ) basis[1] = vec_normalize( basis[1] ) end function ambientOcclusion( isect ) local i,j local ntheta = NAO_SAMPLES local nphi = NAO_SAMPLES local eps = 0.0001 local p = vec_new( isect.p.x + eps * isect.n.x, isect.p.y + eps * isect.n.y, isect.p.z + eps * isect.n.z ) local basis = {} orthoBasis( basis, isect.n ) local occlusion = 0.0 for j=0,ntheta-1 do for i=0,nphi-1 do local r = math.random() local phi = 2.0 * math.pi * math.random() local x = math.cos(phi) * math.sqrt(1.0 - r) local y = math.sin(phi) * math.sqrt(1.0 - r) local z = math.sqrt(r) local rx = x * basis[0].x + y * basis[1].x + z * basis[2].x local ry = x * basis[0].y + y * basis[1].y + z * basis[2].y local rz = x * basis[0].z + y * basis[1].z + z * basis[2].z local raydir = vec_new( rx, ry, rz ) local ray = ray_new( p, raydir ) local occIsect = intersection_new() sphere_intersect( occIsect, sphere[0], ray ) sphere_intersect( occIsect, sphere[1], ray ) sphere_intersect( occIsect, sphere[2], ray ) plane_intersect( occIsect, plane, ray ) if occIsect.hit then occlusion = occlusion + 1.0 end end end occlusion = (ntheta * nphi - occlusion) / (ntheta * nphi) return vec_new( occlusion, occlusion, occlusion ) end function render( width, height, y, nsubsamples ) local fimg = {} local i,j, u,v for i=0,width do fimg[3 * i + 0] = 0 fimg[3 * i + 1] = 0 fimg[3 * i + 2] = 0 for v=0,nsubsamples-1 do for u=0,nsubsamples-1 do local px = (i + (u / nsubsamples) - (width / 2.0)) / (width / 2.0) local py = (y + (v / nsubsamples) - (height / 2.0)) / (height / 2.0) py = -py local t = 10000.0 local eye = vec_new( px, py, -1.0 ) eye = vec_normalize( eye ) local ray = ray_new( vec_zero(), eye ) local isect = intersection_new() sphere_intersect( isect, sphere[0], ray ) sphere_intersect( isect, sphere[1], ray ) sphere_intersect( isect, sphere[2], ray ) plane_intersect( isect, plane, ray ) if isect.hit then t = isect.t local col = ambientOcclusion( isect ) fimg[3 * i + 0] = fimg[3 * i + 0] + col.x fimg[3 * i + 1] = fimg[3 * i + 1] + col.y fimg[3 * i + 2] = fimg[3 * i + 2] + col.z end end end fimg[3 * i + 0] = fimg[3 * i + 0] / (nsubsamples * nsubsamples) fimg[3 * i + 1] = fimg[3 * i + 1] / (nsubsamples * nsubsamples) fimg[3 * i + 2] = fimg[3 * i + 2] / (nsubsamples * nsubsamples) end return fimg end -------------------------------------------- -- main -------------------------------------------- local IMAGE_WIDTH = 64 local IMAGE_HEIGHT = 64 local NSUBSAMPLES = 2 local idx = mdi_img_offscreen( 0 ) mdi_img32_resize( idx, IMAGE_WIDTH, IMAGE_HEIGHT ) for y=0,IMAGE_HEIGHT-1 do local fimg = render( IMAGE_WIDTH, IMAGE_HEIGHT, y, NSUBSAMPLES ) local i for i=0,IMAGE_WIDTH-1 do local r = clamp( fimg[3*i + 0] ) local g = clamp( fimg[3*i + 1] ) local b = clamp( fimg[3*i + 2] ) mdi_img32_pixelset( idx, i,y, r,g,b,255 ) end end mdi_new_img32( idx )