<!DOCTYPE html> <html lang="hu"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Benedek László - IH1RZJ - masodik beadandó: Lego Batman</title> <script async src="./dist/es-module-shims.js"></script> <script type="importmap"> { "imports": { "three": "./js-r167/build/three.module.min.js", "TrackballControls": "./js-r167/examples/jsm/controls/TrackballControls.js", "OBJLoader": "./js-r167/examples/jsm/loaders/OBJLoader.js" } } </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"; import { OBJLoader } from "OBJLoader"; class SceneLoader { static FromJson(data) { let _scene = new THREE.Scene(); let geometries = {}; let materials = {}; let objects = {}; const geometryTypes = { "CircleGeometry": THREE.CircleGeometry, "PlaneGeometry": THREE.PlaneGeometry, "BoxGeometry": THREE.BoxGeometry, "SphereGeometry": THREE.SphereGeometry, "ConeGeometry": THREE.ConeGeometry, "CylinderGeometry": THREE.CylinderGeometry, "TorusGeometry": THREE.TorusGeometry, }; const materialTypes = { "MeshBasicMaterial": THREE.MeshBasicMaterial, "MeshLambertMaterial": THREE.MeshLambertMaterial, "MeshPhongMaterial": THREE.MeshPhongMaterial, "MeshStandardMaterial": THREE.MeshStandardMaterial }; 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); 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; } } } function createObject(data, name) { const objectConstructors = { "empty": data => new THREE.Object3D(), "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; }, "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); object.angle = THREE.MathUtils.degToRad(data.angle ? data.angle : 45); 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 let type = data.type ? data.type : "Mesh"; let object = (objects[name] = objectConstructors[type](data)); 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; if (data.animation) object.animation = data.animation; // add children to parent if (data.children) { for (let [key, value] of Object.entries(data.children)) { object.add(createObject(value, key)); } } return object; } for (let [key, value] of Object.entries(data.objects)) { _scene.add(createObject(value, key)); } return _scene; } }; const fov = 75; const near = 0.1; const far = 10000; const rotateSpeed = 5.0; const panSpeed = 1.0; const loop = true; let canvas, renderer, scene, camera, controls, clock; init().then(loop && animate()); async function init() { canvas = document.querySelector("#canvas"); renderer = new THREE.WebGLRenderer({ antialias: true, canvas: canvas, alpha: true }); renderer.shadowMap.enabled = true; renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor("black"); 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; clock = new THREE.Clock(); 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); render(); } 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(); let delta = clock.getDelta(); let time = clock.getElapsedTime(); scene.traverse((element)=>{ if (element.animation) { (() => { eval(element.animation); }) .call({ element: element, delta: delta, time: time }); } }) render(); } function render() { renderer.render(scene, camera); } </script> </body> </html>