Skip to content

Instantly share code, notes, and snippets.

@edom18
Created February 8, 2013 09:01
Show Gist options
  • Save edom18/4737569 to your computer and use it in GitHub Desktop.
Save edom18/4737569 to your computer and use it in GitHub Desktop.
テクスチャマッピングのテスト
#テクスチャマッピングのテスト
Refer to: [2009-02-11 - 最速チュパカブラ研究会](http://d.hatena.ne.jp/gyuque/20090211#1234364019)
---
少しだけメッシュ作成、操作部分を最適化。
画像を分割する場合は頂点を結ぶ順番は固定になるため、
頂点のインデックスは特になし。
頂点の数を増やすとだいぶ重いので、
もっとこうしたほうがいいよってのがあったら教えて下さい( ;?Д`)
html, body, div, p {
margin: 0;
padding: 0;
}
canvas {
border: solid 1px #333;
}
#container {
width: 500px;
position: relative;
margin: 15px;
}
#container p {
text-align: center;
}
<div id="container">
<canvas id="cv" width="500" height="400"></canvas>
<p><input type="button" id="btn" value="ゆらゆら" /></p>
<!-- /#container --></div>
do (win = window, doc = window.document) ->
$ = (selector) -> doc.querySelector selector
$$ = (selector) -> doc.querySelectorAll selector
w = 0
h = 0
cw = 0
ch = 0
cv = null
ctx = null
btn = null
img = null
mm = null
mesh = 15
meshes = []
vertexes = []
# ---------------------------------------------------------
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 M44
constructor: (cpy)->
if cpy?
@copyFrom(cpy)
else
@ident()
ident: ->
@_12 = @_13 = @_14 = 0
@_21 = @_23 = @_24 = 0
@_31 = @_32 = @_34 = 0
@_41 = @_42 = @_43 = 0
@_11 = @_22 = @_33 = @_44 = 1
return @
copyFrom: (m) ->
@_11 = m._11
@_12 = m._12
@_13 = m._13
@_14 = m._14
@_21 = m._21
@_22 = m._22
@_23 = m._23
@_24 = m._24
@_31 = m._31
@_32 = m._32
@_33 = m._33
@_34 = m._34
@_41 = m._41
@_42 = m._42
@_43 = m._43
@_44 = m._44
return @
transVec3: (out, x, y, z) ->
out[0] = x * @_11 + y * @_21 + z * @_31 + @_41
out[1] = x * @_12 + y * @_22 + z * @_32 + @_42
out[2] = x * @_13 + y * @_23 + z * @_33 + @_43
out[3] = x * @_14 + y * @_24 + z * @_34 + @_44
perspectiveLH: (vw, vh, z_near, z_far) ->
@_11 = 2.0 * z_near / vw
@_12 = 0
@_13 = 0
@_14 = 0
@_21 = 0
@_22 = 2 * z_near / vh
@_23 = 0
@_24 = 0
@_31 = 0
@_32 = 0
@_33 = z_far / (z_far - z_near)
@_34 = 0
@_41 = 0
@_42 = 0
@_43 = z_near * z_far / (z_near - z_far)
@_44 = 0
#multiplication
mul: (A, B) ->
@_11 = A._11 * B._11 + A._12 * B._21 + A._13 * B._31 + A._14 * B._41
@_12 = A._11 * B._12 + A._12 * B._22 + A._13 * B._32 + A._14 * B._42
@_13 = A._11 * B._13 + A._12 * B._23 + A._13 * B._33 + A._14 * B._43
@_14 = A._11 * B._14 + A._12 * B._24 + A._13 * B._34 + A._14 * B._44
@_21 = A._21 * B._11 + A._22 * B._21 + A._23 * B._31 + A._24 * B._41
@_22 = A._21 * B._12 + A._22 * B._22 + A._23 * B._32 + A._24 * B._42
@_23 = A._21 * B._13 + A._22 * B._23 + A._23 * B._33 + A._24 * B._43
@_24 = A._21 * B._14 + A._22 * B._24 + A._23 * B._34 + A._24 * B._44
@_31 = A._31 * B._11 + A._32 * B._21 + A._33 * B._31 + A._34 * B._41
@_32 = A._31 * B._12 + A._32 * B._22 + A._33 * B._32 + A._34 * B._42
@_33 = A._31 * B._13 + A._32 * B._23 + A._33 * B._33 + A._34 * B._43
@_34 = A._31 * B._14 + A._32 * B._24 + A._33 * B._34 + A._34 * B._44
@_41 = A._41 * B._11 + A._42 * B._21 + A._43 * B._31 + A._44 * B._41
@_42 = A._41 * B._12 + A._42 * B._22 + A._43 * B._32 + A._44 * B._42
@_43 = A._41 * B._13 + A._42 * B._23 + A._43 * B._33 + A._44 * B._43
@_44 = A._41 * B._14 + A._42 * B._24 + A._43 * B._34 + A._44 * B._44
return @
translate: (x, y, z) ->
@_11 = 1; @_12 = 0; @_13 = 0; @_14 = 0;
@_21 = 0; @_22 = 1; @_23 = 0; @_24 = 0;
@_31 = 0; @_32 = 0; @_33 = 1; @_34 = 0;
@_41 = x; @_42 = y; @_43 = z; @_44 = 1;
return @
rotX: (r) ->
@_22 = Math.cos(r)
@_23 = Math.sin(r)
@_32 = -@_23
@_33 = @_22
@_12 = @_13 = @_14 = @_21 = @_24 = @_31 = @_34 = @_41 = @_42 = @_43 = 0
@_11 = @_44 = 1
return @
rotY: (r) ->
@_11 = Math.cos(r)
@_13 = Math.sin(r)
@_31 = -@_13
@_33 = @_11
@_12 = @_14 = @_21 = @_23 = @_24 = @_32 = @_34 = @_41 = @_42 = @_43 = 0
@_22 = @_44 = 1
return @
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) ->
@vertex = []
addVertex: (x, y, ux, uy, corner) ->
@vertex.push(new Vertex x, y, ux, uy, corner);
addIndex: (x, y) ->
@index.push(x, y);
getMesh: ->
return @vertex
class Vertex
constructor: (@x, @y, @ux, @uy, @corner) ->
@ox = x
@oy = y
# ---------------------------------------------------------
drawTriangle = (g, img, vertex_list, uv_list) ->
_Ax = vertex_list[2] - vertex_list[0] #x of vector 1
_Ay = vertex_list[3] - vertex_list[1] #y of vertor 1
_Bx = vertex_list[4] - vertex_list[0] #x of vector 2
_By = vertex_list[5] - vertex_list[1] #y of vector 2
Ax = (uv_list[2] - uv_list[0]) * img.width
Ay = (uv_list[3] - uv_list[1]) * img.height
Bx = (uv_list[4] - uv_list[0]) * img.width
By = (uv_list[5] - uv_list[1]) * img.height
# 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|
#
# この式をプログラムで表すと以下になる。
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 = vertex_list[0] - (a * uv_list[0] * img.width + c * uv_list[1] * img.height)
ty = vertex_list[1] - (b * uv_list[0] * img.width + d * uv_list[1] * img.height)
g.save()
g.strokeStyle = '#f00'
g.beginPath()
g.moveTo vertex_list[0], vertex_list[1]
g.lineTo vertex_list[2], vertex_list[3]
g.lineTo vertex_list[4], vertex_list[5]
#for debugging
g.stroke()
g.clip()
g.closePath()
g.transform a, b, c, d, tx, ty
g.drawImage img, 0, 0
g.restore()
# ---------------------------------------------------------
getVertex = (ctx, img) ->
mm = new MeshMgr ctx, img, mesh
w = img.width
h = img.height
wi = w / mesh
hi = h / mesh
_x = 0
_y = 0
len = mesh * mesh + mesh * 2 + 1
ret = []
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)
# ---------------------------------------------------------
deg = 180
PI = Math.PI
TO_RAD = PI / 180
cos = Math.cos
sin = Math.sin
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
ctx.clearRect -50, -50, cw, ch
meshes = mm.getMesh()
seg = mesh + 1
step = 360 / mesh
l = meshes.length - 1
while (l > 0)
i = 0
l -= mesh
deg++
#deg += mesh * i
while (i < mesh)
i++
m = meshes[l + i]
k = ~~(cos((deg * step) * TO_RAD) * 10)
m.x = m.ox + k
deg = deg % 180
for m, i in meshes
if m.corner is true
continue
v1 = meshes[i + 0]
v2 = meshes[i + 1]
v3 = meshes[i + seg + 0]
v4 = meshes[i + seg + 1]
drawTriangle ctx, img, [v1.x, v1.y, v2.x, v2.y, v3.x, v3.y], [v1.ux, v1.uy, v2.ux, v2.uy, v3.ux, v3.uy]
drawTriangle ctx, img, [v4.x, v4.y, v3.x, v3.y, v2.x, v2.y], [v4.ux, v4.uy, v3.ux, v3.uy, v2.ux, v2.uy]
# ---------------------------------------------------------
win.addEventListener 'load', ->
cv = $ 'canvas'
ctx = cv.getContext '2d'
cw = cv.width
ch = cv.height
btn = $ '#btn'
ctx.translate 50, 50
flg = false
timer = null
btn.addEventListener 'click', ->
if (flg = !flg) is true
_loop = ->
timer = setTimeout ->
draw()
_loop()
, 32
_loop()
else
clearTimeout timer
, false
# ---------------------------------------------------------
img = new Image()
img.onload = ->
vertexes = getVertex ctx, img
draw()
img.src = if doc.domain.indexOf('jsrun.it') > -1 then 'http://jsrun.it/assets/k/G/i/S/kGiSG.jpg' else 'pic.jpg'
# ---------------------------------------------------------
, false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment