CANNON

ThreeJS

参考

https://codesandbox.io/p/sandbox/bestservedbold-christmas-baubles-zxpv7

cannonとは

オープンソースのJavascript3D物理エンジンです

<script type="importmap">
{
    "imports": {
        "three": "https://cdn.jsdelivr.net/npm/three@0.175.0/build/three.module.js",
    }
}
</script>
<script type="module">
import * as THREE from "three";
import * as CANNON from "https://cdn.skypack.dev/cannon-es";

よくわからん部分

<?php get_header(); ?>
<script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.175.0/build/three.module.js",
	  "three/addons/controls/OrbitControls.js": "https://cdn.jsdelivr.net/npm/three@0.175.0/examples/jsm/controls/OrbitControls.js"
    }
  }
</script>

<script type="module">
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import * as CANNON from 'https://cdn.skypack.dev/cannon-es'

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(32.5, window.innerWidth / window.innerHeight, 1, 100)
camera.position.set(0, 0, 20)

const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true })
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
renderer.setClearColor(0x111111, 1) // 背景を暗く
document.body.appendChild(renderer.domElement)

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

// Lights
scene.add(new THREE.AmbientLight(0xffffff, 1))
const spotLight = new THREE.SpotLight(0xffffff, 1)
spotLight.position.set(20, 20, 25)
spotLight.castShadow = true
scene.add(spotLight)

const dirLight = new THREE.DirectionalLight(0xff0000, 2)
dirLight.position.set(0, -15, 0)
scene.add(dirLight)

const pointLight = new THREE.PointLight(0xffffff, 1, 100)
pointLight.position.set(0, 10, 20)
scene.add(pointLight)


// Materials
const baubleMaterial = new THREE.MeshLambertMaterial({
  color: "#c0a0a0",
  roughness: 0.25,
  metalness: 0.6,
});

// Physics
const world = new CANNON.World()
world.gravity.set(0, 0, 0)

// Bauble geometry
const sphereGeometry = new THREE.SphereGeometry(1, 28, 28)
const baubles = []


function spawnBaubles() {
  for (let i = 0; i < 50; i++) {
    const scale = [0.75, 0.75, 1, 1, 1.25][Math.floor(Math.random() * 5)]
    const mesh = new THREE.Mesh(sphereGeometry, baubleMaterial)
    mesh.scale.set(scale, scale, scale)
    mesh.castShadow = true
    scene.add(mesh)

    const body = new CANNON.Body({
      mass: 1,
      shape: new CANNON.Sphere(scale),
      position: new CANNON.Vec3(
        Math.random() * 40 - 20,
        Math.random() * 40 - 25,
        Math.random() * 40 - 10
      ),
      linearDamping: 0.75,
      angularDamping: 0.15,
    })
    world.addBody(body)

    baubles.push({ mesh, body, scale })
  }
}
spawnBaubles();

// Pointer
const pointerBody = new CANNON.Body({ mass: 0, shape: new CANNON.Sphere(2), type: CANNON.Body.KINEMATIC })
pointerBody.position.set(100, 100, 100)
world.addBody(pointerBody)

let pointerVec = new THREE.Vector3()
window.addEventListener("mousemove", (e) => {
  pointerVec.x = (e.clientX / window.innerWidth) * 2 - 1
  pointerVec.y = -(e.clientY / window.innerHeight) * 2 + 1
})

const clock = new THREE.Clock()



function animate() {
  requestAnimationFrame(animate)
  const delta = clock.getDelta()

  world.step(1 / 60, delta)
  
  controls.update(); // 追加

  // Move pointer
  const pointerPos = new THREE.Vector3(pointerVec.x, pointerVec.y, 0)
  pointerPos.unproject(camera)
  pointerBody.position.copy(pointerPos)

  // Impulse & update positions
  for (const { mesh, body, scale } of baubles) {
    const direction = new THREE.Vector3().copy(mesh.position).normalize().multiplyScalar(-150 * delta * scale)
    body.applyImpulse(new CANNON.Vec3(direction.x, direction.y, direction.z), body.position)
    mesh.position.copy(body.position)
    mesh.quaternion.copy(body.quaternion)
  }

  renderer.render(scene, camera)
}
animate()

window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
})
</script>
<main></main>
<?php get_footer(); ?>
BACK