plunkerでthree.js その10

# 概要
plunkerでthree.jsやってみた。
練習問題、やってみた。

# 練習問題
クリックして、ballを投げると、くっ付く。

# 参考にしたページ

https://qiita.com/0taUtan/items/7959c00da37068dd210e

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/0f38e75f-1a28-da47-9d49-7186f353c0fc.png)


# サンプルコード

```


let scene, 
    camera, 
    light,
    renderer;
var clock;
var mixer;
var objects = [];

function getPositionKeyframe(startPosition, endPosition, duration) {
		const times = [0];
		const { x, y, z } = startPosition;
		const values = [x, y, z];
		const direction = endPosition.clone().add(startPosition.clone().multiplyScalar(-1)).normalize();
		const raycaster = new THREE.Raycaster();
		raycaster.set(startPosition, direction);
		const intersects = raycaster.intersectObjects(objects, true);
		if (intersects.length > 0)
		{
			const intersect = intersects[0];
			const { distance } = intersect;
			const intersectPosition = startPosition.clone().add(direction.multiplyScalar(distance));
			const { x, y, z } = intersectPosition;
			values.splice(values.length, 0, x, y, z, x, y, z);
			const rate = distance / startPosition.distanceTo(endPosition);
			times.push(duration * rate);
		}
		else
		{
			const { x, y, z } = endPosition;
			values.splice(values.length, 0, x, y, z);
		}
		times.push(duration);
		return new THREE.VectorKeyframeTrack(".position", times, values);
};
function setObjectInitialPosition(position, relativeX, relativeY ) {
	const forward = new THREE.Vector3();
	camera.getWorldDirection(forward);
	forward.normalize();
	const { up } = camera; 
	const left = up.clone().cross(forward); 
	left.multiplyScalar(relativeX * camera.getFilmWidth()); 
	const top = up.clone().multiplyScalar(relativeY * camera.getFilmHeight()); 
	forward.multiplyScalar(camera.near);
	position.copy(camera.position).add(left).add(top).add(forward);
};
function moveObject(object) {
	const startPosition = object.position;
	const { x, y, z } = startPosition;
	const endPosition = new THREE.Vector3();
	camera.getWorldDirection(endPosition);
	endPosition.multiplyScalar(camera.far).add(startPosition);
	//const positionKF = new THREE.VectorKeyframeTrack(".position", [0, 10], [x, y, z, endPosition.x, endPosition.y, endPosition.z]);
	const positionKF = getPositionKeyframe(startPosition, endPosition, 10);
	const moveObjectClip = new THREE.AnimationClip(`move-object-${object.id}`, -1, [positionKF,]);
	mixer = new THREE.AnimationMixer(object);
	mixer.addEventListener("finished", () => {
		scene.remove(object);
		object.geometry.dispose();
	});
	const action = mixer.clipAction(moveObjectClip);
	action.setLoop(THREE.LoopOnce, 0);
	action.play();
};
renderer = new THREE.WebGLRenderer({ 
	antialias: true 
});
renderer.setSize(400, 400);
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
clock = new THREE.Clock();
scene.background = new THREE.Color(0xbfd1e5);
camera = new THREE.PerspectiveCamera(45, 400 / 400, 1, 1000);
camera.position.set(0, 30, 50);
scene.add(camera);
scene.add(new THREE.GridHelper(60, 10));
light = new THREE.AmbientLight(0xFFFFFF);
scene.add(light);
const geometry = new THREE.TorusGeometry(10, 3, 16, 100); 
const material = new THREE.MeshBasicMaterial({ 
	color: 0xff2222 
}); 
const torus = new THREE.Mesh(geometry, material); 
torus.rotation.x += Math.PI / 2;
scene.add(torus);
objects.push(torus);

renderer.render(scene, camera);
var raycaster = new THREE.Raycaster();
var controls = new THREE.OrbitControls(camera, renderer.domElement);
renderer.domElement.addEventListener('click', function(e) {
  var raymouse = new THREE.Vector2();
	raymouse.x = -(e.offsetX / 400) * 2 + 1;
	raymouse.y = -(e.offsetY / 400) * 2 + 1;
	raycaster.setFromCamera(raymouse, camera);
	var intersects = raycaster.intersectObjects(scene.children);
	if (intersects.length > 0)
	{
		const geometry = new THREE.SphereBufferGeometry(3);
    const material = new THREE.MeshBasicMaterial({ 
			color: 0xffffff
	 	});
		const ball = new THREE.Mesh(geometry, material);
		setObjectInitialPosition(ball.position, raymouse.x, raymouse.y);
		scene.add(ball);
		moveObject(ball);
	}
})
function tick() {
	requestAnimationFrame(tick);
	var delta = clock.getDelta();
	if (mixer)
	{
		mixer.update(delta);
	}
	renderer.render(scene, camera);
	controls.update();
}
tick();





```

# 成果物

https://embed.plnkr.co/plunk/Bz4EiVCSUbE5qGQv


以上。