2024-09-24 18:02:01 +00:00
|
|
|
<!DOCTYPE html>
|
|
|
|
<html lang="hu">
|
|
|
|
|
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
2024-10-08 21:46:59 +00:00
|
|
|
<title>Benedek László - IH1RZJ - masodik beadandó: Lego Batman</title>
|
2024-09-24 18:02:01 +00:00
|
|
|
<script async src="./dist/es-module-shims.js"></script>
|
|
|
|
<script type="importmap">
|
|
|
|
{
|
|
|
|
"imports": {
|
|
|
|
"three": "./js-r167/build/three.module.min.js",
|
2024-10-08 13:24:48 +00:00
|
|
|
"TrackballControls": "./js-r167/examples/jsm/controls/TrackballControls.js",
|
|
|
|
"OBJLoader": "./js-r167/examples/jsm/loaders/OBJLoader.js"
|
2024-09-24 18:02:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
<style>
|
|
|
|
body,
|
|
|
|
html canvas {
|
|
|
|
margin: 0;
|
|
|
|
border: 0;
|
|
|
|
padding: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
canvas {
|
|
|
|
width: 100vw;
|
|
|
|
height: 100vh;
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</head>
|
|
|
|
|
|
|
|
<body>
|
|
|
|
<canvas id="canvas"></canvas>
|
|
|
|
|
|
|
|
<script type="module">
|
|
|
|
import * as THREE from "three";
|
|
|
|
import { TrackballControls } from "TrackballControls";
|
2024-10-08 13:24:48 +00:00
|
|
|
import { OBJLoader } from "OBJLoader";
|
2024-09-24 18:02:01 +00:00
|
|
|
|
|
|
|
class SceneLoader {
|
2024-09-30 09:51:39 +00:00
|
|
|
static FromJson(data) {
|
|
|
|
let _scene = new THREE.Scene();
|
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
let geometries = {};
|
|
|
|
let materials = {};
|
|
|
|
let objects = {};
|
|
|
|
|
2024-09-30 09:51:39 +00:00
|
|
|
const geometryTypes = {
|
2024-09-24 18:02:01 +00:00
|
|
|
"CircleGeometry": THREE.CircleGeometry,
|
|
|
|
"PlaneGeometry": THREE.PlaneGeometry,
|
|
|
|
"BoxGeometry": THREE.BoxGeometry,
|
|
|
|
"SphereGeometry": THREE.SphereGeometry,
|
|
|
|
"ConeGeometry": THREE.ConeGeometry,
|
|
|
|
"CylinderGeometry": THREE.CylinderGeometry,
|
|
|
|
"TorusGeometry": THREE.TorusGeometry,
|
|
|
|
};
|
|
|
|
|
2024-09-30 09:51:39 +00:00
|
|
|
const materialTypes = {
|
2024-10-08 13:24:48 +00:00
|
|
|
"MeshBasicMaterial": THREE.MeshBasicMaterial,
|
|
|
|
"MeshLambertMaterial": THREE.MeshLambertMaterial,
|
|
|
|
"MeshPhongMaterial": THREE.MeshPhongMaterial,
|
|
|
|
"MeshStandardMaterial": THREE.MeshStandardMaterial
|
2024-09-24 18:02:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for (let [key, value] of Object.entries(data.geometries)) {
|
|
|
|
geometries[key] = new geometryTypes[value.type](...value.options);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let [key, value] of Object.entries(data.materials)) {
|
|
|
|
materials[key] = new materialTypes[value.type](value.options);
|
2024-11-14 15:28:13 +00:00
|
|
|
if (value.texture) {
|
|
|
|
materials[key].map = new THREE.TextureLoader().load(value.texture.path);
|
|
|
|
if (value.texture.repeat == true) {
|
|
|
|
materials[key].map.wrapS = THREE.RepeatWrapping;
|
|
|
|
materials[key].map.wrapT = THREE.RepeatWrapping;
|
|
|
|
}
|
|
|
|
}
|
2024-09-24 18:02:01 +00:00
|
|
|
}
|
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
function createObject(data, name) {
|
|
|
|
const objectConstructors = {
|
|
|
|
"empty": data => new THREE.Object3D(),
|
2024-10-08 13:56:06 +00:00
|
|
|
"OBJ": data => {
|
|
|
|
let empty = new THREE.Object3D();
|
|
|
|
let loader = new OBJLoader();
|
|
|
|
loader.load(
|
|
|
|
data.url,
|
|
|
|
result => {
|
|
|
|
result.traverse(element => {
|
|
|
|
if (element instanceof THREE.Mesh) {
|
|
|
|
element.material = materials[data.material];
|
|
|
|
if (data.castShadow) element.castShadow = data.castShadow;
|
|
|
|
if (data.receiveShadow) element.receiveShadow = data.receiveShadow;
|
|
|
|
empty.add(element);
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
return empty;
|
|
|
|
},
|
2024-10-08 13:24:48 +00:00
|
|
|
"Mesh": data => new THREE.Mesh(geometries[data.geometry], materials[data.material]),
|
|
|
|
"LineSegments": data => new THREE.LineSegments(geometries[data.geometry], materials[data.material]),
|
|
|
|
|
|
|
|
"AmbientLight": data => new THREE.AmbientLight(data.color ? data.color : 0xffffff, data.intensity ? data.intensity : 1),
|
|
|
|
"PointLight": data => {
|
|
|
|
let object = new THREE.PointLight(data.color ? data.color : 0xffffff, data.intensity ? data.intensity : 1);
|
|
|
|
object.distance = data.distance ? data.distance : 100;
|
|
|
|
return object;
|
|
|
|
},
|
|
|
|
"SpotLight": data => {
|
|
|
|
let object = new THREE.SpotLight(data.color ? data.color : 0xffffff, data.intensity ? data.intensity : 1);
|
2024-10-08 13:56:06 +00:00
|
|
|
object.angle = THREE.MathUtils.degToRad(data.angle ? data.angle : 45);
|
2024-10-08 13:24:48 +00:00
|
|
|
if (data.position) object.position.set(...data.position);
|
|
|
|
object.target = objects[data.target];
|
|
|
|
object.distance = data.distance ? data.distance : 100;
|
|
|
|
return object;
|
|
|
|
},
|
|
|
|
"DirectionalLight": data => {
|
|
|
|
let object = new THREE.DirectionalLight(data.color ? data.color : 0xffffff, data.intensity ? data.intensity : 1);
|
|
|
|
if (data.position) object.position.set(...data.position);
|
|
|
|
object.target = objects[data.target];
|
|
|
|
object.distance = data.distance ? data.distance : 100;
|
|
|
|
object.shadow.camera.left = -50;
|
|
|
|
object.shadow.camera.right = 50;
|
|
|
|
object.shadow.camera.bottom = -50;
|
|
|
|
object.shadow.camera.top = 50;
|
|
|
|
return object;
|
|
|
|
},
|
|
|
|
"HemisphereLight": data => new THREE.HemisphereLight(data.color ? data.color : 0xffffff, data.groundColor ? data.groundColor : 0x00ff00, data.intensity ? data.intensity : 1),
|
|
|
|
|
|
|
|
"PointLightHelper": data => new THREE.PointLightHelper(objects[data.target], data.sphereSize ? data.sphereSize : 5),
|
|
|
|
"SpotLightHelper": data => new THREE.SpotLightHelper(objects[data.target]),
|
|
|
|
"DirectionalLightHelper": data => new THREE.DirectionalLightHelper(objects[data.target], data.planeSize ? data.planeSize : 10),
|
|
|
|
"HemisphereLightHelper": data => new THREE.HemisphereLightHelper(objects[data.target], data.sphereSize ? data.sphereSize : 5),
|
|
|
|
"AxesHelper": data => new THREE.AxesHelper(data.helperSize ? data.helperSize : 10),
|
|
|
|
"ArrowHelper": data => new THREE.ArrowHelper(...(data.direction ? data.direction : [1, 0, 0]), ...(data.origin ? data.origin : [0, 0, 0]), data.length ? data.length : 10, data.color ? data.color : 0xff00ff),
|
|
|
|
"ShadowCameraHelper": data => new THREE.CameraHelper(objects[data.target].shadow.camera),
|
|
|
|
};
|
|
|
|
|
|
|
|
// create object
|
2024-09-30 09:51:39 +00:00
|
|
|
let type = data.type ? data.type : "Mesh";
|
2024-10-08 13:24:48 +00:00
|
|
|
let object = (objects[name] = objectConstructors[type](data));
|
2024-09-30 09:51:39 +00:00
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
if (data.position) object.position.set(...data.position);
|
|
|
|
if (data.rotation) object.rotation.set(...Array.from(data.rotation, x => THREE.MathUtils.degToRad(x)));
|
|
|
|
if (data.scale) object.scale.set(...data.scale);
|
|
|
|
if (data.castShadow) object.castShadow = data.castShadow;
|
|
|
|
if (data.receiveShadow) object.receiveShadow = data.receiveShadow;
|
2024-11-14 15:28:13 +00:00
|
|
|
if (data.animation) object.animation = data.animation;
|
2024-09-24 18:02:01 +00:00
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
// add children to parent
|
2024-09-24 18:02:01 +00:00
|
|
|
if (data.children) {
|
|
|
|
for (let [key, value] of Object.entries(data.children)) {
|
2024-10-08 13:24:48 +00:00
|
|
|
object.add(createObject(value, key));
|
2024-09-24 18:02:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
return object;
|
2024-09-24 18:02:01 +00:00
|
|
|
}
|
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
for (let [key, value] of Object.entries(data.objects)) {
|
|
|
|
_scene.add(createObject(value, key));
|
2024-09-24 18:02:01 +00:00
|
|
|
}
|
2024-09-30 09:51:39 +00:00
|
|
|
|
|
|
|
return _scene;
|
2024-09-24 18:02:01 +00:00
|
|
|
}
|
|
|
|
};
|
2024-09-30 09:51:39 +00:00
|
|
|
|
|
|
|
const fov = 75;
|
2024-10-08 13:24:48 +00:00
|
|
|
const near = 0.1;
|
|
|
|
const far = 10000;
|
2024-09-30 09:51:39 +00:00
|
|
|
const rotateSpeed = 5.0;
|
|
|
|
const panSpeed = 1.0;
|
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
const loop = true;
|
|
|
|
|
2024-11-14 15:28:13 +00:00
|
|
|
let canvas, renderer, scene, camera, controls, clock;
|
2024-09-30 09:51:39 +00:00
|
|
|
|
2024-10-08 13:24:48 +00:00
|
|
|
init().then(loop && animate());
|
2024-09-30 09:51:39 +00:00
|
|
|
|
|
|
|
async function init() {
|
|
|
|
canvas = document.querySelector("#canvas");
|
|
|
|
renderer = new THREE.WebGLRenderer({ antialias: true, canvas: canvas, alpha: true });
|
2024-10-08 13:24:48 +00:00
|
|
|
renderer.shadowMap.enabled = true;
|
2024-09-30 09:51:39 +00:00
|
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
2024-10-08 21:46:59 +00:00
|
|
|
renderer.setClearColor("black");
|
2024-09-30 09:51:39 +00:00
|
|
|
|
|
|
|
camera = new THREE.PerspectiveCamera(fov, window.innerWidth / window.innerHeight, near, far);
|
|
|
|
camera.position.set(0, 10, 50);
|
|
|
|
|
|
|
|
controls = new TrackballControls(camera, canvas);
|
|
|
|
controls.rotateSpeed = rotateSpeed;
|
|
|
|
controls.panSpeed = panSpeed;
|
|
|
|
|
2024-11-14 15:28:13 +00:00
|
|
|
clock = new THREE.Clock();
|
|
|
|
|
2024-09-30 09:51:39 +00:00
|
|
|
scene = await fetch("scene.json")
|
|
|
|
.then((response) => response.json())
|
|
|
|
.catch(reason => console.log(`fetch failed: ${reason}`))
|
|
|
|
.then((json) => SceneLoader.FromJson(json));
|
|
|
|
|
|
|
|
window.addEventListener("resize", handleWindowResize, false);
|
2024-10-08 13:24:48 +00:00
|
|
|
|
|
|
|
render();
|
2024-09-30 09:51:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function handleWindowResize() {
|
|
|
|
console.log(`resize: ${window.innerWidth}x${window.innerHeight}`)
|
|
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
|
|
|
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
|
|
camera.updateProjectionMatrix();
|
|
|
|
|
|
|
|
render();
|
|
|
|
}
|
|
|
|
|
|
|
|
function animate() {
|
|
|
|
requestAnimationFrame(animate);
|
|
|
|
controls.update();
|
2024-11-14 15:28:13 +00:00
|
|
|
|
|
|
|
let delta = clock.getDelta();
|
|
|
|
let time = clock.getElapsedTime();
|
|
|
|
|
|
|
|
scene.traverse((element)=>{
|
|
|
|
if (element.animation) {
|
|
|
|
(() => {
|
|
|
|
eval(element.animation);
|
|
|
|
})
|
|
|
|
.call({ element: element, delta: delta, time: time });
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2024-09-30 09:51:39 +00:00
|
|
|
render();
|
|
|
|
}
|
|
|
|
|
|
|
|
function render() {
|
|
|
|
renderer.render(scene, camera);
|
|
|
|
}
|
2024-09-24 18:02:01 +00:00
|
|
|
</script>
|
|
|
|
</body>
|
|
|
|
|
|
|
|
</html>
|