Skip to main content

mouse

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://unpkg.com/three@0.142.x/build/three.min.js"></script>
<script src="https://unpkg.com/xnew@2.3.x/dist/xnew.js"></script>
<script src="https://unpkg.com/xnew@2.3.x/dist/addons/xthree.js"></script>

<style>
html {
height: -webkit-fill-available;
}
body {
min-height: 100vh;
min-height: -webkit-fill-available;
position: absolute;
margin: 0;
inset: 0;
overflow: hidden;
}
</style>
</head>

<body>
<div id="main" style="width: 100%; height: 100%;"></div>
<script>
xnew('#main', (self) => {
const screen = xnew(xnew.Screen, { width: 800, height: 400 });

const three = xthree.setup({ renderer: new THREE.WebGLRenderer({ canvas: screen.canvas }) });

three.renderer.shadowMap.enabled = true;
three.renderer.shadowMap.type = THREE.PCFSoftShadowMap;

three.camera.position.set(0, 0, +200);
three.scene.rotation.x = -60 / 180 * Math.PI

self.on('+scale', (scale) => {
three.camera.position.z /= scale;
})
self.on('+translate', (move) => {
three.camera.position.x += move.x * three.camera.position.z * 0.001;
three.camera.position.y += move.y * three.camera.position.z * 0.001;
})
self.on('+rotate', (move) => {
three.scene.rotation.x += move.y * 0.01;
three.scene.rotation.z += move.x * 0.01;
})

xnew(ThreeContents);
xnew(Event);
});

function Event(self) {
self.on('touchstart contextmenu wheel', (event) => {
event.preventDefault();
});
self.on('wheel', (event) => {
self.emit('+scale', 1 + 0.001 * event.wheelDeltaY);
});

const gesture = xnew(xnew.GestureEvent);
let isActive = false;
gesture.on('-down -up -cancel', () => {
isActive = (xnew.event.type === '-down');
});
gesture.on('-move', ({ scale }) => {
self.emit('+scale', scale);
});
const drag = xnew(xnew.DragEvent);
drag.on('-move', ({ position, delta }) => {
if (isActive === true) return;
if (event.buttons & 1 || !event.buttons) {
self.emit('+rotate', { x: +delta.x, y: +delta.y });
}
if (event.buttons & 2) {
self.emit('+translate', { x: -delta.x, y: +delta.y });
}
});
}

function ThreeContents(self) {
xnew(DirectionaLight, { x: 20, y: -50, z: 100 });
xnew(AmbientLight);

xnew(Ground, { size: 1000, color: 0xF8F8FF });
xnew(Dorm, { size: 500 });
xnew(Cube, { x: 0, y: 0, z: 20, size: 40, color: 0xAAAAFF });
}

function DirectionaLight(self, { x, y, z }) {
const object = xthree.nest(new THREE.DirectionalLight(0xFFFFFF, 0.40));
object.position.set(x, y, z);

const s = object.position.length();
object.castShadow = true;
object.shadow.mapSize.width = 1024;
object.shadow.mapSize.height = 1024;
object.shadow.camera.left = -s * 1.0;
object.shadow.camera.right = +s * 1.0;
object.shadow.camera.top = -s * 1.0;
object.shadow.camera.bottom = +s * 1.0;
object.shadow.camera.near = +s * 0.1;
object.shadow.camera.far = +s * 10.0;
object.shadow.camera.updateProjectionMatrix();
}

function AmbientLight(self) {
const object = xthree.nest(new THREE.AmbientLight(0xFFFFFF, 0.50));
}

function Dorm(self, { size }) {
const geometry = new THREE.SphereGeometry(size, 25, 25);
const material = new THREE.MeshBasicMaterial({ color: 0xEEEEFF, side: THREE.BackSide });
const object = xthree.nest(new THREE.Mesh(geometry, material));
}

function Ground(self, { size, color }) {
const geometry = new THREE.PlaneGeometry(size, size, 1, 1);
const material = new THREE.MeshStandardMaterial({ color, transparent: true, });
const object = xthree.nest(new THREE.Mesh(geometry, material));
object.receiveShadow = true;
object.material.opacity = 0.7;
}

function Cube(self, { x, y, z, size, color }) {
const geometry = new THREE.BoxGeometry(size, size, size);
const material = new THREE.MeshLambertMaterial({ color, });
const object = xthree.nest(new THREE.Mesh(geometry, material));
object.position.set(x, y, z);
object.castShadow = true;
}
</script>
</body>

</html>