Model URLs
Loading...
Src "0loader" <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> </head> <body> <button id="zoomInButton" style="position: absolute; top: 10px; right: 20px; font-size: 24px; padding: 20px; background-color: #f44336; color: white; border: none; border-radius: 10px;">-</button> <button id="zoomOutButton" style="position: absolute; top: 50px; right: 20px; font-size: 24px; padding: 20px; background-color: #008CBA; color: white; border: none; border-radius: 10px;">+</button> <!--<div class="pose"><input type="button" value="pose2" onclick="PoseClickEvent(this.value)"></div>--> <script src="./libs/three.js"></script> <!--<script src="https://cdn.jsdelivr.net/gh/mrdoob/three.js@r106/examples/js/libs/mmdparser.min.js"></script>--> <script src="./libs/mmdparser-obsolete.min.js"></script> <script src="./libs/ammo.min.js"></script> <script src="./libs/TGALoader.js"></script> <script src="./libs/MMDLoader.js"></script> <script src="./libs/MMDAnimationHelper.js"></script> <script src="./libs/CCDIKSolver.js"></script> <script src="./libs/MMDPhysics.js"></script> <script> let scene, renderer, camera, mesh, helper; let ready = false; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const clock = new THREE.Clock(); const urlParams = new URLSearchParams(window.location.search); const modelPath = urlParams.get('pmx') || './pmx/pronama/AoiZaizen/AoiZaizen.pmx'; // Default model path const vmdPath = urlParams.get('vmd') || 'bts-bestofme'; // Default VMD path (without extension) let isMouseDown = false; let previousMousePosition = { x: 0, y: 0 }; // Parameters for camera orbit let theta = Math.PI / 4; // Rotation angle (around Y axis) let phi = Math.PI / 4; // Rotation angle (around X axis) let radius = 50; // Camera distance from the origin (model) // Variables to store touch positions let isTouching = false; let touchStart = { x: 0, y: 0 }; // Variables for pinch-to-zoom let initialPinchDistance = null; window.onload = () => { Init(); LoadModeler(); Render(); // Set up zoom buttons document.getElementById("zoomInButton").addEventListener("click", () => { zoomCamera(1); // Zoom in }); document.getElementById("zoomOutButton").addEventListener("click", () => { zoomCamera(-1); // Zoom out }); }; Init = () => { scene = new THREE.Scene(); const ambient = new THREE.AmbientLight(0xeeeeee); scene.add(ambient); renderer = new THREE.WebGLRenderer({ alpha: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0xcccccc, 0); document.body.appendChild(renderer.domElement); camera = new THREE.PerspectiveCamera(40, windowWidth / windowHeight, 1, 1000); // Initial camera position updateCameraPosition(); // Mouse event listeners for rotation document.addEventListener('mousedown', onMouseDown, false); document.addEventListener('mousemove', onMouseMove, false); document.addEventListener('mouseup', onMouseUp, false); // Touch event listeners for rotation and pinch-to-zoom document.addEventListener('touchstart', onTouchStart, false); document.addEventListener('touchmove', onTouchMove, false); document.addEventListener('touchend', onTouchEnd, false); }; // Function to zoom the camera in or out zoomCamera = (direction) => { radius += direction * 5; // Adjust the zoom speed (5 units per button press) // Prevent zooming too close or too far radius = Math.max(10, Math.min(radius, 200)); // Adjust min/max zoom distance // Update camera position based on the new radius updateCameraPosition(); }; // Mouse interaction functions onMouseDown = (event) => { isMouseDown = true; previousMousePosition = { x: event.clientX, y: event.clientY }; }; onMouseMove = (event) => { if (!isMouseDown) return; const deltaX = event.clientX - previousMousePosition.x; const deltaY = event.clientY - previousMousePosition.y; // Update the angles based on mouse movement theta -= deltaX * 0.005; // Rotate around Y-axis phi -= deltaY * 0.005; // Invert rotation around X-axis (subtract instead of add) // Prevent the camera from flipping upside down phi = Math.max(Math.min(phi, Math.PI / 2), -Math.PI / 2); // Update camera position based on new angles updateCameraPosition(); // Update previous mouse position previousMousePosition = { x: event.clientX, y: event.clientY }; }; onMouseUp = () => { isMouseDown = false; }; // Touch interaction functions onTouchStart = (event) => { if (event.touches.length === 1) { // Start touch rotation isTouching = true; touchStart = { x: event.touches[0].clientX, y: event.touches[0].clientY }; } else if (event.touches.length === 2) { // Start pinch-to-zoom initialPinchDistance = getPinchDistance(event); } }; onTouchMove = (event) => { if (event.touches.length === 1 && isTouching) { // Rotate based on touch movement const deltaX = event.touches[0].clientX - touchStart.x; const deltaY = event.touches[0].clientY - touchStart.y; // Update the angles based on touch movement theta -= deltaX * 0.005; // Rotate around Y-axis phi -= deltaY * 0.005; // Invert rotation around X-axis (subtract instead of add) // Prevent the camera from flipping upside down phi = Math.max(Math.min(phi, Math.PI / 2), -Math.PI / 2); // Update camera position based on new angles updateCameraPosition(); // Update touch start position touchStart = { x: event.touches[0].clientX, y: event.touches[0].clientY }; } else if (event.touches.length === 2 && initialPinchDistance !== null) { // Pinch-to-zoom: Calculate new pinch distance const newPinchDistance = getPinchDistance(event); const distanceChange = newPinchDistance - initialPinchDistance; // Zoom in or out based on pinch distance change radius += distanceChange * 0.1; // Adjust zoom speed // Prevent zooming too close or too far radius = Math.max(10, Math.min(radius, 200)); // Update camera position based on new zoom (radius) updateCameraPosition(); // Update initial pinch distance for next move initialPinchDistance = newPinchDistance; } }; onTouchEnd = () => { isTouching = false; initialPinchDistance = null; }; // Helper function to calculate the distance between two touch points getPinchDistance = (event) => { const touch1 = event.touches[0]; const touch2 = event.touches[1]; const dx = touch2.clientX - touch1.clientX; const dy = touch2.clientY - touch1.clientY; return Math.sqrt(dx * dx + dy * dy); }; updateCameraPosition = () => { // Update camera position using spherical coordinates (radius, theta, phi) camera.position.x = radius * Math.sin(phi) * Math.cos(theta); camera.position.y = radius * Math.cos(phi); camera.position.z = radius * Math.sin(phi) * Math.sin(theta); // Make sure the camera always looks at the center of the scene (the origin) camera.lookAt(scene.position); }; LoadModeler = async () => { const loader = new THREE.MMDLoader(); LoadPMX = () => { return new Promise(resolve => { loader.load(modelPath, (object) => { mesh = object; // Move the model down along the Y-axis by a specific value (e.g., -10) mesh.position.y = -10; // Adjust this value to move the model down or up scene.add(mesh); resolve(true); }, onProgress, onError); }); } LoadVMD = (vmd) => { return new Promise(resolve => { const path = `./vmd/${vmd}.vmd`; // Correct VMD path format loader.loadAnimation(path, mesh, (vmdClip) => { vmdClip.name = vmd; VmdControl(vmd, vmdClip); resolve(true); }, onProgress, onError); }); } await LoadPMX(); await LoadVMD(vmdPath); } VmdControl = (id, vmdClip, loop = true) => { ready = false; helper = new THREE.MMDAnimationHelper({ afterglow: 2.0, resetPhysicsOnLoop: true }); helper.add(mesh, { animation: vmdClip, physics: false }); if (vmdClip) { const mixer = helper.objects.get(mesh).mixer; if (!loop) { mixer.existingAction(vmdClip).setLoop(THREE.LoopOnce); } mixer.addEventListener("loop", () => { console.log("loop"); }); mixer.addEventListener("finished", () => { console.log("finished"); VmdControl(id, vmdClip, true); }); } ready = true; } onProgress = (xhr) => { if (xhr.lengthComputable) { const percentComplete = (xhr.loaded / xhr.total) * 100; console.log(Math.round(percentComplete, 2) + '% downloaded'); } } onError = (xhr) => { console.log("ERROR"); } Render = () => { requestAnimationFrame(Render); renderer.clear(); renderer.render(scene, camera); if (ready) { helper.update(clock.getDelta()); } } </script>