<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>WebGL 日本Roxik大师的3D空间随机球作品</title>
<style>
html,
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script src='js/three.js'></script>
<script>
class Roxik {
constructor() {
this.models = [];
this.initialize();
this.animate();
}
initialize() {
this.initializeEngine();
this.initializeCamera();
this.initializeLights();
this.initializeMaterials();
this.initializeObjects();
this.initializeFilters();
this.initializeListeners();
}
initializeEngine() {
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xfefefe);
this.renderer = new THREE.WebGLRenderer({
antialias: true
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(this.renderer.domElement);
}
initializeCamera() {
this.camera = new THREE.PerspectiveCamera(
55,
window.innerWidth / window.innerHeight,
0.001,
1000
);
this.camera.position.x = 2;
this.camera.position.y = 2;
this.camera.position.z = -2;
this.cameraController = new CameraController();
this.cameraController.camera = this.camera;
}
initializeLights() {
this.ambientLight = new THREE.DirectionalLight(0x9090aa);
this.ambientLight.position.set(-10, 10, -10).normalize();
this.scene.add(this.ambientLight);
var light = new THREE.HemisphereLight(0xffffff, 0x444444);
light.position.set(1, 1, 1);
this.scene.add(light);
}
initializeMaterials() {
const colors = [
0x97350b,
0x266ea5,
0x00847f,
0x2f818e,
0x08917c,
0x08917c,
0x6b458c,
0x7a4526
];
this.sphereMaterial = [];
for (var i = 0; i < 8; i++) {
let mat = new THREE.MeshLambertMaterial({
color: colors[i]
});
this.sphereMaterial.push(mat);
}
this.cubeMaterial = new THREE.MeshBasicMaterial({
color: 0xdddddd
});
this.cubeMaterial.wireframe = true;
}
initializeObjects() {
const bet = 0.7;
const offset = (8 - 1) * bet * 0.5;
let geometry = new THREE.IcosahedronBufferGeometry(0.3, 2);
for (var i = 0; i < 8; i++) {
for (var j = 0; j < 8; j++) {
for (var k = 0; k < 8; k++) {
let m = this.sphereMaterial[Math.floor(Math.random() * 8)];
let s = new THREE.Mesh(geometry, m);
s.position.set(i * bet - offset, j * bet - offset, k * bet - offset);
this.models.push(s);
this.scene.add(s);
}
}
}
this.cube = new THREE.CubeGeometry(18, 18, 18, 4, 4, 4);
this.cubeMesh = new THREE.Mesh(this.cube, this.cubeMaterial);
this.scene.add(this.cubeMesh);
this.cameraController.models = this.models;
this.motionController = new MotionController();
this.motionController.models = this.models;
this.motionController.changeScene(this.motionController.CYLINDER);
}
initializeFilters() {}
initializeListeners() {
window.addEventListener("resize", this.updateDimensions.bind(this));
document.addEventListener("keydown", this.keydownHandler.bind(this));
}
animate() {
requestAnimationFrame(this.animate.bind(this));
this.cameraController.step();
this.motionController.step();
this.renderer.render(this.scene, this.camera);
}
updateDimensions() {
let width = window.innerWidth;
let height = window.innerHeight;
this.renderer.setSize(width, height);
this.camera.aspect = width / height;
this.camera.updateProjectionMatrix();
}
keydownHandler(event) {
var keyCode = event.which;
switch (keyCode) {
case 49:
case 97:
this.motionController.changeScene(this.motionController.CYLINDER);
break;
case 50:
case 98:
this.motionController.changeScene(this.motionController.SPHERE);
break;
case 51:
case 99:
this.motionController.changeScene(this.motionController.CUBE);
break;
case 52:
case 100:
this.motionController.changeScene(this.motionController.TUBE);
break;
case 53:
case 101:
this.motionController.changeScene(this.motionController.WAVE);
break;
case 54:
case 102:
this.motionController.changeScene(this.motionController.GRAVITY);
break;
case 55:
case 103:
this.motionController.changeScene(this.motionController.ANTIGRAVITY);
break;
}
}
}
class CameraController {
constructor() {
this.camera = null;
this.models = [];
this.frame = 1000;
this.sceneLimit = 90;
this.tm;
this.target = new THREE.Vector3(0, 0, 0);
this.cs = 0;
this.gy = 0;
this.l = 0;
this.bl = 6;
this.ts = 0;
this.r = 0;
this.rp = 0.03;
}
step() {
if (++this.frame > this.sceneLimit) {
this.frame = 0;
this.sceneLimit = Math.floor(Math.random() * 60 + 30);
this.tm = this.models[Math.floor(Math.random() * this.models.length)];
this.ts = 0;
this.cs = 0;
this.gy = Math.random() * 8 - 4;
this.rp = Math.random() * 0.06 - 0.03;
this.bl = Math.random() * 4 + 7;
}
if (this.ts < 0.05) {
this.ts += 0.005;
}
if (this.cs < 0.5) {
this.cs += 0.005;
}
this.target.x += (this.tm.position.x - this.target.x) * this.ts;
this.target.y += (this.tm.position.y - this.target.y) * this.ts;
this.target.z += (this.tm.position.z - this.target.z) * this.ts;
this.camera.lookAt(this.target);
this.r += this.rp;
this.l += (this.bl - this.l) * 0.1;
this.camera.position.x +=
(Math.cos(this.r) * this.l +
this.tm.position.x -
this.camera.position.x) *
this.cs;
this.camera.position.y +=
(this.tm.position.y + this.gy - this.camera.position.y) * this.cs;
this.camera.position.z +=
(Math.sin(this.r) * this.l +
this.tm.position.z -
this.camera.position.z) *
this.cs;
}
}
class MotionController {
constructor() {
this.CYLINDER = 0;
this.SPHERE = 1;
this.CUBE = 2;
this.TUBE = 3;
this.WAVE = 4;
this.GRAVITY = 5;
this.ANTIGRAVITY = 6;
this.models = [];
this.scene = this.CYLINDER;
this.sceneLimit = 100;
this.frame = 0;
this.cutoff = 0;
this.r = 0.0;
this.r0 = 0.0;
this.rp = 0.0;
this.rl = 0.0;
}
changeScene(scene, limit = -1) {
this.cutoff = 0;
th