Created
February 14, 2013 00:13
-
-
Save edom18/4949624 to your computer and use it in GitHub Desktop.
テクスチャマッピングを使って動的に背景を作るテスト
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#テクスチャマッピングのテストから発展して、ちょっと立体的に見える背景の生成をやってみた。 | |
動的に画像を生成し、それをパラパラ漫画風に表示するため、初期化処理が少し重いです。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html, body, div, p { | |
margin: 0; | |
padding: 0; | |
} | |
canvas { | |
border: solid 1px #333; | |
background: #000; | |
} | |
#container { | |
width: 500px; | |
position: relative; | |
margin: 15px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="container"> | |
<canvas id="cv" width="500" height="166"></canvas> | |
<p><input type="button" id="btn" value="STOP" /></p> | |
<p>動的に画像を生成し、それをパラパラ漫画風に表示するため、初期化処理が少し重いです。<br /> | |
その代わり、初期化後はiPhoneなどのモバイル機器でも高速に動きます。</p> | |
<!-- /#container --></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
do (win = window, doc = window.document) -> | |
$ = (selector) -> doc.querySelector selector | |
$$ = (selector) -> doc.querySelectorAll selector | |
btn = $('#btn') | |
ci = null | |
flg = false | |
btn.addEventListener 'click', (e) -> | |
if (flg = !flg) is true | |
ci.stop() | |
else | |
ci.play() | |
, false | |
# -------------------------------------------------------------------- | |
drawTriangles = (g, img, vertecies, indecies, uvData) -> | |
# move position from A(Ax, Ay) to _A(_Ax, _Ay) | |
# move position from B(Ax, Ay) to _B(_Bx', _By) | |
# A,Bのベクトルを、_A,_Bのベクトルに変換することが目的。 | |
# 変換を達成するには、a, b, c, dそれぞれの係数を導き出す必要がある。 | |
# | |
# ↓まずは公式。アフィン変換の移動以外を考える。 | |
# | |
# _Ax = a * Ax + c * Ay | |
# _Ay = b * Ax + d * Ay | |
# _Bx = a * Bx + c * By | |
# _By = b * Bx + d * By | |
# | |
# ↓上記の公式を行列の計算で表すと以下に。 | |
# | |
# |_Ax| = |Ax Ay||a| | |
# |_Bx| = |Bx By||c| | |
# | |
# ↓a, cについて求めたいのだから、左に掛けているものを「1」にする必要がある。 | |
# 行列を1にするには、逆行列を左から掛ければいいので、両辺に逆行列を掛ける。(^-1は逆行列の意味) | |
# | |
# |Ax Ay|^-1 |_Ax| = |a| | |
# |Bx By| |_Bx| = |c| | |
# | |
# この式をプログラムで表すと以下になる。 | |
cv = doc.createElement 'canvas' | |
_g = cv.getContext '2d' | |
w = img.width | |
h = img.height | |
cv.width = w | |
cv.height = h | |
for index, i in indecies by 3 | |
i0 = indecies[i + 0] | |
i1 = indecies[i + 1] | |
i2 = indecies[i + 2] | |
v0 = vertecies[i0] | |
v1 = vertecies[i1] | |
v2 = vertecies[i2] | |
uv0 = uvData[i0] | |
uv1 = uvData[i1] | |
uv2 = uvData[i2] | |
v0x = v0.x | |
v0y = v0.y | |
v1x = v1.x | |
v1y = v1.y | |
v2x = v2.x | |
v2y = v2.y | |
uv0x = uv0.x | |
uv0y = uv0.y | |
uv1x = uv1.x | |
uv1y = uv1.y | |
uv2x = uv2.x | |
uv2y = uv2.y | |
_Ax = v1x - v0x | |
_Ay = v1y - v0y | |
_Bx = v2x - v0x | |
_By = v2y - v0y | |
Ax = (uv1x - uv0x) * w | |
Ay = (uv1y - uv0y) * h | |
Bx = (uv2x - uv0x) * w | |
By = (uv2y - uv0y) * h | |
m = new M22 | |
m._11 = Ax | |
m._12 = Ay | |
m._21 = Bx | |
m._22 = By | |
mi = m.getInvert() #To invert | |
if mi is null then return | |
a = mi._11 * _Ax + mi._12 * _Bx | |
c = mi._21 * _Ax + mi._22 * _Bx | |
b = mi._11 * _Ay + mi._12 * _By | |
d = mi._21 * _Ay + mi._22 * _By | |
tx = v0x - (a * uv0x * w + c * uv0y * h) | |
ty = v0y - (b * uv0x * w + d * uv0y * h) | |
_g.save() | |
_g.beginPath() | |
_g.moveTo v0x, v0y | |
_g.lineTo v1x, v1y | |
_g.lineTo v2x, v2y | |
#TODO | |
#for debugging | |
#g.strokeStyle = 'red' | |
#g.stroke() | |
_g.clip() | |
_g.closePath() | |
_g.setTransform a, b, c, d, tx, ty | |
_g.drawImage img, 0, 0 | |
_g.restore() | |
g.drawImage cv, 0, 0 | |
# --------------------------------------------------------- | |
class CubeImage | |
mesh: 10 | |
constructor: (@g, @url, @bgColor = '#000') -> | |
@img = new Image() | |
@img.onload = @onload | |
@img.src = url | |
@_cv = doc.createElement 'canvas' | |
@_ctx = @_cv.getContext '2d' | |
@frame = 0 | |
@dx = 0 | |
@delta = 3 | |
onload: => | |
@width = @_cv.width = @img.width | |
@height = @_cv.height = @img.height | |
@vertexes = @createVertex @g, @img | |
@addCurve() | |
@createMovie() | |
@play() | |
createMovie: -> | |
movie = @movie = [] | |
drawTriangles = @drawTriangles | |
img = @_cv | |
w = @width | |
h = @height | |
g = @g | |
mm = @mm | |
vertecies = mm.getVertecies() | |
indecies = mm.getIndecies() | |
uvData = mm.getUvData() | |
for i in [0..@width / @delta] | |
cv = doc.createElement 'canvas' | |
cv.width = w | |
cv.height = h | |
ctx = cv.getContext '2d' | |
@drawTriangles ctx, img, vertecies, indecies, uvData | |
movie.push cv | |
@createNextImage() | |
createNextImage: -> | |
dx = @dx | |
w = @width | |
h = @height | |
img = @img | |
ctx = @_ctx | |
ctx.fillStyle = @bgColor | |
ctx.fillRect 0, 0, w, h | |
ctx.drawImage img, dx, 0 | |
ctx.drawImage img, (w - dx), 0, dx, h, 0, 0, dx, h | |
@dx = ((@dx += @delta) % @width) | |
addCurve: -> | |
PI = Math.PI | |
TO_RAD = PI / 180 | |
sin = Math.sin | |
img = @_cv | |
hh = @height / 2 | |
strength = 30 | |
deg = 0 | |
mesh = @mesh | |
seg = mesh + 1 | |
step = 180 / mesh | |
meshes = @mm.getMesh() | |
l = meshes.length | |
while (l > 0) | |
i = 0 | |
l -= seg | |
while (i <= mesh) | |
m = meshes[l + i] | |
k = sin(step * i * TO_RAD) | |
f = (hh - m.oy) / hh | |
m.y = m.oy + ~~(strength * k * f) | |
i++ | |
createVertex: -> | |
mesh = @mesh | |
img = @img | |
mm = new MeshMgr @g, img, mesh | |
w = img.width | |
h = img.height | |
wi = w / mesh | |
hi = h / mesh | |
_x = 0 | |
_y = 0 | |
len = mesh * mesh + mesh * 2 + 1 | |
for i in [0...len] | |
x = wi * _x | |
y = hi * _y | |
if x >= w | |
_x = 0 | |
_y++ | |
corner = true | |
else | |
_x++ | |
corner = false | |
if y >= h | |
corner = true | |
ux = x / w | |
uy = y / h | |
mm.addVertex(x, y, ux, uy, corner) | |
seg = mesh + 1 | |
meshes = mm.getMesh() | |
for m, i in meshes | |
if m.corner is true | |
continue | |
i1 = (i + 0) | |
i2 = (i + 1) | |
i3 = (i + seg + 0) | |
i4 = (i + seg + 1) | |
mm.addIndex(i1, i2, i3) | |
mm.addIndex(i4, i3, i2) | |
@mm = mm | |
drawTriangles: drawTriangles | |
draw: -> | |
#[arguments list] | |
#transform(a, b, c, d, tx, ty) | |
# ↓ as result. | |
#|a c tx| |x| = ax + cy + tx | |
#|b d ty|x|y| = bx + dy + ty | |
#|0 0 1 | |1| = 0 + 0 + 1 | |
@createNextImage() | |
g = @g | |
mm = @mm | |
g.clearRect 0, 0, @width, @height | |
vertecies = mm.getVertecies() | |
indecies = mm.getIndecies() | |
uvData = mm.getUvData() | |
@drawTriangles g, @_cv, vertecies, indecies, uvData | |
draw2: -> | |
frame = (++@frame % @movie.length) | |
img = @movie[frame] | |
@g.drawImage img, 0, 0 | |
play: -> | |
do _loop = => | |
@draw2() | |
@timer = setTimeout _loop, 32 | |
stop: -> | |
clearTimeout @timer | |
class Vec3 | |
constructor: (@x = 0, @y = 0, @z = 0) -> | |
zero: -> | |
@x = @y = @z = 0; | |
sub: (v) -> | |
@x -= v.x | |
@y -= v.y | |
@z -= v.z | |
return @ | |
add: (v) -> | |
@x += v.x | |
@y += v.y | |
@z += v.z | |
return @ | |
copyFrom: (v) -> | |
@x = v.x | |
@y = v.y | |
@z = v.z | |
return @ | |
norm: -> | |
Math.sqrt(@x * @x + @y * @y + @z * @z) | |
normalize: -> | |
nrm = @norm() | |
if nrm isnt 0 | |
@x /= nrm | |
@y /= nrm | |
@z /= nrm | |
return @ | |
#scalar multiplication | |
smul: (k) -> | |
@x *= k | |
@y *= k | |
@z *= k | |
return @ | |
#dot product | |
dpWith: (v) -> | |
@x * v.x + @y * v.y + @z * v.z | |
#cross product | |
cp: (v, w) -> | |
@x = (w.y * v.z) - (w.z * v.y) | |
@y = (w.z * v.x) - (w.x * v.z) | |
@z = (w.x * v.y) - (w.y * v.x) | |
return @ | |
toString: -> | |
"#{@x},#{@y},#{@z}" | |
class M22 | |
constructor: -> | |
@_11 = 1 | |
@_12 = 0 | |
@_21 = 0 | |
@_22 = 1 | |
getInvert: -> | |
out = new M22 | |
det = @_11 * @_22 - @_12 * @_21 | |
if 0.0001 > det > -0.0001 | |
return null | |
out._11 = @_22 / det | |
out._22 = @_11 / det | |
out._12 = @_12 / det | |
out._21 = @_21 / det | |
return out | |
class MeshMgr | |
constructor: (@g, @img, @mesh) -> | |
@vertecies = [] | |
@indecies = [] | |
@uvData = [] | |
addVertex: (x, y, ux, uy, corner) -> | |
@vertecies.push(new Vertex x, y, corner) | |
@uvData.push(new UvData ux, uy) | |
addIndex: (i1, i2, i3) -> | |
@indecies.push(i1, i2, i3); | |
getVertecies: -> | |
@vertecies | |
getIndecies: -> | |
@indecies | |
getUvData: -> | |
@uvData | |
getMesh: -> | |
@vertecies | |
class Vertex | |
constructor: (@x, @y, @corner) -> | |
@ox = x | |
@oy = y | |
class UvData | |
constructor: (@x, @y) -> | |
# --------------------------------------------------------- | |
init = -> | |
cv = $ 'canvas' | |
ctx = cv.getContext '2d' | |
ci = new CubeImage ctx, 'http://jsrun.it/assets/8/B/7/O/8B7OB.png' | |
win.addEventListener 'load', init, false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment