sapeck-Body

My goal was to create an environment of balloons where a motion-captured person interacts by popping the balloons. I chose a fight BVH from mocapdata.com that causes the figure to send a serious of punches at the wall of balloons. I looked through a lot of different fight sequences, and this one seemed to fit the best. I think it would have worked better if I had a continuously/endlessly walking and fighting person going through a never-ending stream of balloons. Otherwise, it's just boring.

I wanted to play with the placement of the balloons and having them move out of the way or drift off, but three.js made things difficult. For example, I found a good way to create a matte finish on the balloons, but that would prevent me from setting the opacity to hide the popped ones. I also found a good balloon 3D model, but I could not get three.js to display it. If I use three.js in the future, I need to have a much better understanding of it.

import colors from '../data/colorsHex'
 
var clock = new THREE.Clock()
 
var camera, controls, scene, renderer
var mixer, skeletonHelper
 
init()
animate()
 
var loader = new THREE.BVHLoader()
loader.load('bvh/fighting-31-syotei-yokoyama.bvh', result => {
  skeletonHelper = new THREE.SkeletonHelper(result.skeleton.bones[0])
  skeletonHelper.material.linewidth = 10
  skeletonHelper.skeleton = result.skeleton // allow animation mixer to bind to SkeletonHelper directly
 
  var boneContainer = new THREE.Group()
  boneContainer.add(result.skeleton.bones[0])
 
  scene.add(skeletonHelper)
  scene.add(boneContainer)
 
  // play animation
  mixer = new THREE.AnimationMixer(skeletonHelper)
  mixer.clipAction(result.clip).setEffectiveWeight(1.0).play()
})
 
// create an AudioListener and add it to the camera
var listener = new THREE.AudioListener()
camera.add(listener)
 
// create a global audio source
var sound = new THREE.Audio(listener)
 
// load a sound and set it as the Audio object's buffer
var audioLoader = new THREE.AudioLoader()
audioLoader.load('audio/Balloon Popping-SoundBible.com-1247261379.wav', buffer => {
  sound.setBuffer(buffer)
  sound.setLoop(false)
  sound.setVolume(1)
})
 
var ambientLight = new THREE.AmbientLight(0x000000)
scene.add(ambientLight)
 
var lights = []
lights[0] = new THREE.PointLight(0xffffff, 1, 0)
lights[1] = new THREE.PointLight(0xffffff, 1, 0)
lights[2] = new THREE.PointLight(0xffffff, 1, 0)
 
lights[0].position.set(0, 2000, 0)
lights[1].position.set(1000, 2000, 0)
lights[2].position.set(-1000, -2000, 0)
 
scene.add(lights[0])
scene.add(lights[1])
scene.add(lights[2])
 
let newBalloon = (r, color, x, y, z, o) => {
  var geometry = new THREE.SphereGeometry(r, 32, 32)
  var material = new THREE.MeshStandardMaterial({
    color: color,
    wireframe: false,
    transparent: true,
    opacity: o
  })
  var sphere = new THREE.Mesh(geometry, material)
  sphere.position.set(x, y, z)
  return sphere
}
 
let newBalloonGrid = (r, i, s, o) => {
  let balloons = []
  let pad = (r * 2) + s
  let c = ((i - 1) * pad) / 2
  for (let x of Array(i).keys()) {
    for (let y of Array(i - 4).keys()) {
      for (let z of Array(i - 2).keys()) {
        let color = colors[Math.floor(Math.random() * colors.length)]
        let bx = x * pad - c + 100
        let by = y * pad + r
        let bz = z * pad - c + 250
        let balloon = newBalloon(r, color, bx, by, bz, o)
        scene.add(balloon)
        balloons.push({
          pos: {
            x: bx,
            y: by,
            z: bz
          },
          r: r,
          o: o,
          color: color,
          mesh: balloon
        })
      }
    }
  }
  return balloons
}
let balloons = newBalloonGrid(20, 10, 5, 1)
 
function init () {
  camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 1, 1000)
  camera.position.set(0, 450, -400)
 
  controls = new THREE.OrbitControls(camera)
  controls.minDistance = 300
  controls.maxDistance = 700
 
  scene = new THREE.Scene()
 
  scene.add(new THREE.GridHelper(200, 10))
 
  // renderer
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setClearColor(0xeeeeee)
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(window.innerWidth, window.innerHeight)
 
  document.body.appendChild(renderer.domElement)
 
  window.addEventListener('resize', onWindowResize, false)
}
 
function onWindowResize () {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
 
  renderer.setSize(window.innerWidth, window.innerHeight)
}
 
var set = false
function animate () {
  // if (!isPlay) return
  window.requestAnimationFrame(animate)
 
  var delta = clock.getDelta()
 
  if (mixer) mixer.update(delta)
  // if (skeletonHelper) skeletonHelper.update()
 
  renderer.render(scene, camera)
 
  if (skeletonHelper) {
    if (!set) {
      console.log(skeletonHelper.skeleton.bones)
      set = true
    }
    if (skeletonHelper.skeleton) {
      for (let bone of skeletonHelper.skeleton.bones) {
        if (bone.name !== 'ENDSITE') {
          for (let balloon of balloons) {
            // console.log(skeletonHelper.skeleton.bones)
            let ballPos = balloon.pos
            let bonePos = bone.position
            let dist = Math.sqrt(Math.pow(ballPos.x - bonePos.x, 2) + Math.pow(ballPos.y - bonePos.y, 2) + Math.pow(ballPos.z - bonePos.z, 2))
            // console.log({ dist, ballPos, bonePos, name: bone.name })
            if (dist <= balloon.r * 4 && balloon.mesh.material.opacity !== 0) {
              console.log('KILL BALLOON')
              // console.log({ dist, ballPos, bonePos, name: bone.name })
              // scene.remove(balloon.mesh)
              if (balloon.mesh.material.opacity !== 0) {
                if (sound.isPlaying) sound.stop()
                sound.play()
              }
              balloon.mesh.material.opacity = 0
              // balloons.splice(balloons.indexOf(balloon))
              // scene.add(newBalloon(balloon.r, balloon.color, ballPos.x, ballPos.y, ballPos.z, balloon.o))
            }
          }
        }
      }
    }
  }
}