概要
plunkerでthree.jsやってみた。
練習問題、やってみた。
練習問題
クリックして、ballを投げると、くっ付く。
参考にしたページ
写真
サンプルコード
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();
成果物
以上。