| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8" /> |
| <title>Character Viewer</title> |
| <style> |
| body { margin: 0; overflow: hidden; background: #000; } |
| canvas { display: block; } |
| #loading { |
| position: fixed; |
| top: 50%; left: 50%; |
| transform: translate(-50%, -50%); |
| color: white; |
| background: rgba(0,0,0,0.7); |
| padding: 20px 30px; |
| border-radius: 10px; |
| font-family: sans-serif; |
| } |
| </style> |
| </head> |
| <body> |
| <div id="loading">Loading character...</div> |
|
|
| <script type="importmap"> |
| { |
| "imports": { |
| "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js", |
| "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/" |
| } |
| } |
| </script> |
|
|
| <script type="module"> |
| import * as THREE from 'three'; |
| import { FBXLoader } from 'three/addons/loaders/FBXLoader.js'; |
| import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; |
| |
| let scene, camera, renderer, controls, model; |
| |
| init(); |
| animate(); |
| |
| function init() { |
| |
| scene = new THREE.Scene(); |
| scene.background = new THREE.Color(0x111111); |
| camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); |
| camera.position.set(0, 1.5, 3); |
| |
| |
| renderer = new THREE.WebGLRenderer({ antialias: true }); |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| renderer.outputEncoding = THREE.sRGBEncoding; |
| document.body.appendChild(renderer.domElement); |
| |
| |
| scene.add(new THREE.AmbientLight(0xffffff, 0.5)); |
| |
| const dirLight = new THREE.DirectionalLight(0xffffff, 1); |
| dirLight.position.set(2, 4, 2); |
| dirLight.castShadow = true; |
| scene.add(dirLight); |
| |
| const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444, 0.4); |
| hemiLight.position.set(0, 10, 0); |
| scene.add(hemiLight); |
| |
| |
| controls = new OrbitControls(camera, renderer.domElement); |
| controls.enableDamping = true; |
| |
| |
| const loader = new FBXLoader(); |
| loader.load('./character.fbx', (fbx) => { |
| model = fbx; |
| model.scale.set(0.01, 0.01, 0.01); |
| scene.add(model); |
| document.getElementById('loading').style.display = 'none'; |
| }, (xhr) => { |
| const percent = (xhr.loaded / xhr.total * 100).toFixed(1); |
| document.getElementById('loading').textContent = `Loading ${percent}%`; |
| }, (error) => { |
| document.getElementById('loading').textContent = 'Error loading character.fbx'; |
| console.error(error); |
| }); |
| |
| |
| window.addEventListener('resize', () => { |
| camera.aspect = window.innerWidth / window.innerHeight; |
| camera.updateProjectionMatrix(); |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| }); |
| } |
| |
| function animate() { |
| requestAnimationFrame(animate); |
| if (model) model.rotation.y += 0.005; |
| controls.update(); |
| renderer.render(scene, camera); |
| } |
| </script> |
| </body> |
| </html> |