tp-interaction/js/main.js

284 lines
8.6 KiB
JavaScript

class Controls {
constructor(object) {
// object is the object controlled by the controls, in our case, the camera.
this.object = object;
// 3D coordinates where the camera is looking at
this.target = new THREE.Vector3(0, 0, 0);
// Unit vectors of the local camera frame
// forward is in the z-direction
// left point towards the x-direction
// (a vector towards y is not necessary)
// in the direction of the angles
this.forward = new THREE.Vector3(0,0,0);
this.left = new THREE.Vector3(0,0,0);
// speed at which the camera will translate
this.speed = 50;
// speed at which the camera will rotate
this.sensitivity = 0.004;
// angles of the camera
this.angles = {
delta: 0,
theta: 0,
};
// the position of the camera is this.object.position
this.vectorsFromAngles();
// currently pressed keys
this.keys = {
up: false,
down: false,
left: false,
right: false,
};
// whether the mouse is being pressed or not
this.mouseClicked = false;
// whether there is a transition running or not
// if not, this.t is NaN
// otherwise, this.t is in [0, 1]
this.t = NaN;
// calls this.keyChange(true) when a key is pressed
document.addEventListener('keydown', this.keyChange(true));
// calls this.keyChange(false) when a key is released
document.addEventListener('keyup', this.keyChange(false));
// calls this.mouseDown(e) when a mouse button is pressed
document.addEventListener('mousedown', (e) => this.mouseDown(e));
// sets this.mouseClicked to false when a mouse button is released
document.addEventListener('mouseup', () => this.mouseClicked = false);
// calls this.mouseMove(e) when the mouse is moved
document.addEventListener('mousemove', (e) => this.mouseMove(e));
}
// rotates the camera to make it look to its target.
look() {
this.object.lookAt(this.target);
}
// updates this.forward, this.left and this.target
// from this.angles.delta and this.angles.theta
// this.forward is the vector moving direction
// this.left is the vector moving sideways to the left
// this.target is the point that the camera is looking
vectorsFromAngles() {
// TODO Part 1
}
// computes this.angles.delta and this.angles.theta from this.forward
// (may be useless)
anglesFromVectors() {
// TODO Part 2
}
// updates this.keys when a key is pressed or released
keyChange(setting) {
return (event) => {
switch (event.keyCode) {
case 37: case 81: this.keys.left = setting; break;
case 38: case 90: this.keys.up = setting; break;
case 39: case 68: this.keys.right = setting; break;
case 40: case 83: this.keys.down = setting; break;
case 13:
console.log("Position:", this.object.position);
console.log("Target:", this.target);
break;
}
};
}
// sets mouseClicked to true, and searches for a bookmark being clicked
mouseDown(event) {
this.mouseClicked = true;
let mouse = {
x: ( event.clientX / window.innerWidth ) * 2 - 1,
y: - ( event.clientY / window.innerHeight ) * 2 + 1,
};
// update the picking ray with the camera and mouse position
raycaster.setFromCamera(mouse, camera);
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects(scene.children, true);
if (this.testIntersection(intersects)) {
this.bookmarkClicked(intersects[0].object.parent);
}
}
// tests that a bookmark is clicked or not
//
// this function filters out other objects of the scene.
testIntersection(intersects) {
if (intersects.length === 0) {
return;
}
if (intersects[0].object === undefined) {
return;
}
if (! (intersects[0].object.parent instanceof Bookmark)) {
return;
}
if (this.object.position.distanceTo(intersects[0].object.parent.position) < 10) {
return;
}
this.bookmarkClicked(intersects[0].object.parent);
}
// initializes the paramters for the transition to a bookmark.
bookmarkClicked(bookmark) {
// TODO Part 2
}
// changes this.angles depending of event.movementX and event.movementY
//
// event.movementX indicates how many pixels the mouse has moved to the right
// event.movementY indicates how many piels the mouse has moved to the bottom
// both those values can be negative to indicate a motion in the opposite direction
mouseMove(event) {
// TODO Part 1
}
// called at every frame
update() {
// No transition : use keyboard and mouse to update the camera
if (isNaN(this.t)) {
// TODO Part 1
if (this.keys.up) {
// ...
}
} else {
// Transition to bookmark
// TODO Part 2
}
// update the camera parameters
this.look();
}
}
let container, controls;
let camera, scene, renderer;
let raycaster = new THREE.Raycaster();
init();
animate();
function init() {
container = document.createElement('div');
document.body.appendChild(container);
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 100, 50000);
camera.position.y = 1000;
camera.position.z = 1000;
scene = new THREE.Scene();
let ambientLight = new THREE.AmbientLight(0xcccccc, 0.4);
scene.add(ambientLight);
let pointLight = new THREE.PointLight(0xffffff, 0.8);
camera.add(pointLight);
scene.add(camera);
let geometry = new THREE.PlaneGeometry(20000, 20000);
for (let index = 0; index < geometry.faceVertexUvs[0].length; index++) {
geometry.faceVertexUvs[0][index][0].multiplyScalar(10);
geometry.faceVertexUvs[0][index][1].multiplyScalar(10);
geometry.faceVertexUvs[0][index][2].multiplyScalar(10);
}
let texture = new THREE.TextureLoader().load('assets/windfall/water.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
let material = new THREE.MeshBasicMaterial({map: texture});
let sea = new THREE.Mesh(geometry, material);
sea.rotation.x = -Math.PI / 2;
scene.add(sea);
// controls
controls = new Controls(camera);
// model
let directory = "assets/windfall/";
let modelName = "Windfall";
let onProgress = function (xhr) {
if (xhr.lengthComputable) {
let percentComplete = xhr.loaded / xhr.total * 100;
console.log(Math.round(percentComplete, 2) + '% downloaded');
}
};
let onError = function () { };
let manager = new THREE.LoadingManager();
new THREE.MTLLoader(manager)
.setPath(directory)
.load(modelName + ".mtl", function (materials) {
materials.preload();
new THREE.OBJLoader(manager)
.setMaterials(materials)
.setPath(directory)
.load(modelName + ".obj", function (object) {
scene.add(object);
}, onProgress, onError);
});
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(new THREE.Color(0x87ceeb));
container.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false);
// Add a bookmark to the scene
// let position = { x: -3089.6612461510463, y: 3944.8226721499614, z: -2409.0350261969947 };
// let target = { x: -3088.665295409939, y: 3944.824672148628, z: -2409.124904566436 };
// let bookmark = new Bookmark(position, target);
// scene.add(bookmark);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
for (let child of scene.children) {
if (child instanceof Bookmark) {
child.update(camera);
}
}
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}