Created
March 4, 2013 00:27
-
-
Save edom18/5079073 to your computer and use it in GitHub Desktop.
おっぱいがうごくJS inspire by damele0n
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
[damele0n](http://jsdo.it/damele0n)さんの[おっぱいがうごくJS](http://jsdo.it/damele0n/h8BW)を参考に、新しく作ってみた。 | |
(あ、案件で使うときがあったので・・w) | |
主な実装内容は、胸のあたりに5x5程度のメッシュを作成し、テクスチャマッピングした各頂点を揺らす、ということで実装しています。 | |
[History] | |
* [2013/03/04] 常にレンダリングし続けるのを防ぎ、CPU使用率を下げるよう修正しました。 |
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
body { | |
background: #111; | |
} | |
div, p { | |
margin: 0; | |
padding: 0; | |
} | |
#container { | |
position: absolute; | |
left: 50px; | |
top: 50px; | |
} | |
#cv, | |
#cv2 { | |
cursor: pointer; | |
position: absolute; | |
z-index: 10; | |
} | |
.char { | |
position: absolute; | |
left: 0; | |
top: 0; | |
} |
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
<p><input type="button" id="btn" value="Debug mode" /></p> | |
<div id="container"> | |
<canvas id="cv"></canvas> | |
<canvas id="cv2"></canvas> | |
<p class="char"><img src="http://jsrun.it/assets/w/y/x/d/wyxdz.jpg" alt="" /></p> | |
<!-- /#container --></div> | |
<script> | |
document.addEventListener('DOMContentLoaded', function () { | |
var btn = document.getElementById('btn'); | |
var canvasElem = document.getElementById('cv'); | |
var canvasElem2 = document.getElementById('cv2'); | |
var src = 'http://jsrun.it/assets/w/y/x/d/wyxdz.jpg'; | |
var oppai = new Oppai({ | |
cv: canvasElem, | |
src: src, | |
mesh: 6, | |
rect: [215, 364, 330, 518], | |
elasticity: 0.82, | |
responsiveness: 0.25, | |
displacementRadius: 75, | |
displacementIntensity: -0.15 | |
}); | |
var oppai2 = new Oppai({ | |
cv: canvasElem2, | |
src: src, | |
mesh: 6, | |
rect: [320, 364, 430, 518], | |
elasticity: 0.82, | |
responsiveness: 0.25, | |
displacementRadius: 75, | |
displacementIntensity: -0.15 | |
}); | |
btn.addEventListener('click', function () { | |
oppai.debug = !oppai.debug; | |
oppai2.debug = !oppai2.debug; | |
}, false); | |
}); | |
</script> |
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, exports = window) -> | |
{sqrt, atan2, max, cos, sin, abs, ceil} = Math | |
ARC = Math.PI * 2 | |
requestAnimFrame = do -> | |
return window.requestAnimationFrame or | |
window.webkitRequestAnimationFrame or | |
window.mozRequestAnimationFrame or | |
window.oRequestAnimationFrame or | |
window.msRequestAnimationFrame or | |
( callback, element ) -> | |
window.setTimeout(callback, 1000 / 60) | |
class EventHandler | |
handleEvent: (evt) -> | |
@[evt.type]?(evt); | |
# ----------------------------------------------------------------------- | |
class Oppai extends EventHandler | |
mesh: 10 | |
constructor: (settings) -> | |
@[s] = settings[s] for s of settings | |
@center = | |
x: ~~((@rect[2] - @rect[0]) / 2) | |
y: ~~((@rect[3] - @rect[1]) / 2) | |
@cursors = {} | |
@g = @cv.getContext '2d' | |
@_img = new Image() | |
@_img.onload = @onload | |
@_img.src = @src | |
@left = @rect[0] | |
@top = @rect[1] | |
@width = @rect[2] - @left | |
@height = @rect[3] - @top | |
@offsetX = @cv.parentNode.offsetLeft + @left | |
@offsetY = @cv.parentNode.offsetTop + @top | |
@cv.style.left = "#{@left}px" | |
@cv.style.top = "#{@top}px" | |
@cv.addEventListener 'mousedown', @, false | |
onload: => | |
@img = doc.createElement 'canvas' | |
@width = @img.width = @cv.width = @width | |
@height = @img.height = @cv.height = @height | |
ctx = @img.getContext '2d' | |
ctx.drawImage @_img, @rect[0], @rect[1], @width, @height, 0, 0, @width, @height | |
@createVertex() | |
@play() | |
drawTriangles: (vertecies, indecies, uvData) -> | |
cv = doc.createElement 'canvas' | |
_g = cv.getContext '2d' | |
g = @g | |
img = @img | |
w = cv.width = img.width | |
h = cv.height = img.height | |
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 | |
#To invert | |
mi = m.getInvert() | |
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 | |
#for debugging | |
if @debug is true | |
_g.strokeStyle = '#444' | |
_g.stroke() | |
_g.clip() | |
_g.closePath() | |
_g.setTransform a, b, c, d, tx, ty | |
_g.drawImage img, 0, 0 | |
_g.restore() | |
g.clearRect 0, 0, w, h | |
g.drawImage cv, 0, 0 | |
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] | |
ignore = false | |
x = wi * _x | |
y = hi * _y | |
if x >= w | |
_x = 0 | |
_y++ | |
corner = true | |
else | |
_x++ | |
corner = false | |
if y >= h | |
corner = true | |
dx = @center.x - x | |
dy = @center.y - y | |
distance = sqrt(dx * dx + dy * dy) | |
ignore = true if distance > @displacementRadius | |
ux = x / w | |
uy = y / h | |
mm.addVertex | |
x: x | |
y: y | |
ux: ux | |
uy: uy | |
corner: corner | |
ignore: ignore | |
seg = mesh + 1 | |
meshes = mm.getMesh() | |
for m, i in meshes when m.corner isnt true | |
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 | |
draw: -> | |
g = @g | |
mm = @mm | |
vertecies = mm.getVertecies() | |
indecies = mm.getIndecies() | |
uvData = mm.getUvData() | |
chk = vertecies.length | |
for i in [0...vertecies.length] | |
vertecx = vertecies[i] | |
vertecx.update() | |
if vertecx.stopped is true or vertecx.ignore is true | |
chk-- | |
#if all vertecies are stopped, skip rendering. | |
if chk is 0 | |
return | |
g.clearRect 0, 0, @width, @height | |
@drawTriangles vertecies, indecies, uvData | |
play: -> | |
requestAnimFrame => | |
@draw() | |
@play() | |
mousedown: (event) -> | |
@cursorStart event | |
event.preventDefault() | |
mousemove: (event) -> | |
@cursors.mouse = event | |
mouseup: (event) -> | |
@cursorEnd event | |
cursorStart: (cursor) -> | |
@cursors.mouse = cursor | |
doc.addEventListener 'mousemove', @, false | |
doc.addEventListener 'mouseup', @, false | |
cursorEnd: (event) -> | |
delete @cursors.mouse | |
doc.removeEventListener 'mousemove', @, false | |
doc.removeEventListener 'mouseup', @, false | |
# ------------------------------------------------------------------ | |
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: (@parent, @g, @img, @mesh) -> | |
@vertecies = [] | |
@indecies = [] | |
@uvData = [] | |
addVertex: (attributes) -> | |
attributes.parent = @parent | |
@vertecies.push(new Vertex attributes) | |
@uvData.push(new UvData attributes.ux, attributes.uy) | |
addIndex: (i1, i2, i3) -> | |
@indecies.push(i1, i2, i3); | |
getVertecies: -> | |
@vertecies | |
getIndecies: -> | |
@indecies | |
getUvData: -> | |
@uvData | |
getMesh: -> | |
@vertecies | |
# ------------------------------------------------------------------ | |
class Vertex | |
constructor: (attributes) -> | |
for id of attributes | |
@[id] = attributes[id] | |
@ox = @x | |
@oy = @y | |
@angle = @offsetX = @offsetY = 0 | |
elasticizeProperty: (prop, target) -> | |
deltaProp = "#{prop}Delta" | |
@[deltaProp] = (@[deltaProp] or 0) * @parent.elasticity + (@[prop] - target) * @parent.responsiveness | |
if abs(@[deltaProp]) < 0.001 | |
@stopped = true | |
else | |
@stopped = false | |
@[prop] -= @[deltaProp] | |
update: -> | |
return if @ignore | |
if 'mouse' of @parent.cursors | |
cursors = @parent.cursors.mouse | |
dx = cursors.pageX - @x - @parent.offsetX | |
dy = cursors.pageY - @y - @parent.offsetY | |
distance = sqrt(dx * dx + dy * dy) | |
angle = atan2(dy, dx) | |
@angle = angle or @angle | |
targetD = if distance then @parent.displacementRadius - distance else 0 | |
targetD = max(targetD, 0) * @parent.displacementIntensity | |
targetOffsetX = cos(@angle) * -targetD | |
targetOffsetY = sin(@angle) * -targetD | |
@elasticizeProperty 'offsetX', targetOffsetX | |
@elasticizeProperty 'offsetY', targetOffsetY | |
@x = @ox + @offsetX | |
@y = @oy + @offsetY | |
# ------------------------------------------------------------------ | |
class UvData | |
constructor: (@x, @y) -> | |
# ------------------------------------------------------------------ | |
# EXPORTS | |
# ------------------------------------------------------------------ | |
exports.Oppai = Oppai |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment