shuffle = (a) ->
i = a.length
while --i > 0
j = ~~(Math.random() * (i + 1))
t = a[j]
a[j] = a[i]
a[i] = t
a
class Trampoline
size: 14
constructor: (@scene, $options) ->
@subdivisions = @size
@geometry = new THREE.PlaneGeometry(@size, @size, @subdivisions, @subdivisions )
@uniforms = {
size: {type: 'f', value: @size}
width: {type: 'f', value: window.innerWidth}
height: {type: 'f', value: window.innerHeight}
time: {type: 'f', value: 0.0}
}
@uniforms = THREE.UniformsUtils.merge([THREE.UniformsLib['lights'], @uniforms])
@attributes = {
idx: {type: 'f', value: []}
velocity: {type: 'f', value: []}
}
if $options.trampolineShader
@materials = [
new THREE.ShaderMaterial { transparent: false, lights: true, side: THREE.DoubleSide, uniforms: @uniforms, attributes: @attributes, vertexShader: document.getElementById( 'trampolineVertShader' ).textContent, fragmentShader: document.getElementById( 'trampolineFragShader' ).textContent }
]
else
@materials = [
new THREE.MeshBasicMaterial {wireframe: true, transparent: true, color: 0x333333, shading: THREE.FlatShading}
new THREE.MeshPhongMaterial { specular: 0x111111, shininess: 20, vertexColors: THREE.VertexColors, side: THREE.DoubleSide},
]
@halfsize = @size / 2
@vwidth = @subdivisions + 1
@acceleration = []
@velocity = []
for x in [0...@vwidth]
@acceleration[x] = []
@velocity[x] = []
for y in [0...@vwidth]
@acceleration[x][y] = 6.0
@velocity[x][y] = 0.0
@attributes.velocity.value[@at(x,y)] = 0.0
faceIndices = [ 'a', 'b', 'c', 'd' ]
for face in @geometry.faces
numberOfSides = 3
for j in [0...numberOfSides]
vertexIndex = face[ faceIndices[ j ] ];
@attributes.idx.value[vertexIndex] = vertexIndex
p = @geometry.vertices[vertexIndex]
color = new THREE.Color( 0xffffff );
color.setRGB(p.x / @halfsize, 1.0 - p.y / @halfsize, (p.x * p.x + p.y * p.y) / (@halfsize * @halfsize))
face.vertexColors[j] = color
# @mesh = new THREE.Mesh @geometry, @material
@mesh = THREE.SceneUtils.createMultiMaterialObject @geometry, @materials
@mesh.rotation.x = - Math.PI / 2.0
@scene.add @mesh
@geometry.colorsNeedUpdate = true
at: (x, z) ->
x = (x) / @size * @vwidth
z = (z) / @size * @vwidth
return Math.floor(z * @subdivisions + x)
dist: (x, z) ->
@geometry.vertices[@at(x,z)].z
update: (step) ->
@uniforms.time.value += step
for x in shuffle [0..@subdivisions - 1]
for y in shuffle [0..@subdivisions - 1]
idx = @at(x, y)
k = 50.5 * step
d = 5.0
da = 7.0
dk = k * 0.25
@geometry.vertices[idx].z += @velocity[x][y] * step
@velocity[x][y] += @acceleration[x][y] * step * d
@acceleration[x][y] = - da * @geometry.vertices[idx].z
# @velocity[x][y] = 0.0 if @geometry.vertices[idx].z > 0 and @velocity[x][y] > 0
@geometry.vertices[idx].z = 0.0 if @geometry.vertices[idx].z > 0
limit = @subdivisions
z = @geometry.vertices[idx].z
if x + 1 < limit
@velocity[x][y] += (@dist(x + 1, y) - z) * k
if y + 1 < limit
@velocity[x][y] += (@dist(x, y + 1) - z) * k
if x - 1 > 0
@velocity[x][y] += (@dist(x - 1, y) - z) * k
if y - 1 > 0
@velocity[x][y] += (@dist(x, y - 1) - z) * k
if x + 1 < limit and y + 1 < limit
@velocity[x][y] += (@dist(x + 1, y + 1) - z) * dk
if x + 1 < limit and y - 1 > 0
@velocity[x][y] += (@dist(x + 1, y - 1) - z) * dk
if x - 1 > 0 and y + 1 < limit
@velocity[x][y] += (@dist(x - 1, y + 1) - z) * dk
if x - 1 > 0 and y - 1 > 0
@velocity[x][y] += (@dist(x - 1, y - 1) - z) * dk
@attributes.velocity.value[idx] = @velocity[x][y]
@geometry.verticesNeedUpdate = true
impact: (particle) ->
k = 0.8 * particle.mass
vk = 0.9
d = 0.05
rx = particle.position.x + @halfsize
ry = particle.position.z + @halfsize
x = Math.floor(rx)
y = Math.floor(ry)
py = particle.velocity.length() + particle.angularVelocity.y
fx = rx - x
fy = ry - y
newV = particle.velocity.y * d
limit = @subdivisions
if x < limit and x > 0 and y < limit and y > 0
newV += @velocity[x][y] * vk * (1.0 - fx) * (1.0 - fy)
@velocity[x][y] += - py * k * (1.0 - fx) * (1.0 - fy)
if x + 1 < limit and x + 1 > 0 and y < limit and y > 0
newV += @velocity[x + 1][y] * vk * fx * (1.0 - fy)
@velocity[x + 1][y] += - py * k * fx * (1.0 - fy)
if x + 1 < limit and x + 1 > 0 and y + 1 < limit and y + 1 > 0
newV += @velocity[x + 1][y + 1] * vk * fx * fy
@velocity[x + 1][y + 1] += - py * k * fx * fy
if x < limit and x > 0 and y + 1 < limit and y + 1 > 0
newV += @velocity[x][y + 1] * vk * (1.0 - fx) * fy
@velocity[x][y + 1] += - py * k * (1.0 - fx) * (fy)
if newV < 0
newV = 0.01
particle.velocity.y += newV
window.Trampoline = Trampoline