let scene, renderer, camera, mesh, helper; let ready = false; const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; const clock = new THREE.Clock(); function getQueryStringValue(key) { const urlParams = new URLSearchParams(window.location.search); return urlParams.get(key);} const pmx = getQueryStringValue('pmx'); const stage = getQueryStringValue('stage'); let Pmx; let Stage; if (pmx) {Pmx = `./pmx/pronama/${pmx.trim()}`; } else {console.log("No PMX selected.");} if (stage) {Stage = `./stages${stage.trim()}`; } else { console.log("No stage selected.");} if (!Pmx) {Pmx = `./pmx/pronama/AoiZaizen/AoiZaizen.pmx`;} if (!Stage) {Stage = "./stages/sorclair/sorclair.pmx";} const MotionObjects = [ {id: "001", pose: "001", VmdClip: null, AudioClip: false }, { id: "002", pose: "002", VmdClip: null, AudioClip: false }, { id: "003", pose: "003", VmdClip: null, AudioClip: false },]; window.onload = () => { Init(); LoadModeler(); Render();}; function Init() { document.getElementById("moveLeftButton").addEventListener("click", moveCameraLeft); document.getElementById("moveRightButton").addEventListener("click", moveCameraRight); document.getElementById("moveUpButton").addEventListener("click", moveCameraUp); document.getElementById("moveDownButton").addEventListener("click", moveCameraDown); document.getElementById("rotaterightButton").addEventListener("click", rotateCameraRight); document.getElementById("rotateleftButton").addEventListener("click", rotateCameraLeft); function moveCameraLeft() {camera.position.x -= 1;} function moveCameraRight() {camera.position.x += 1;} function moveCameraUp() {camera.position.y += 1;} function moveCameraDown() {camera.position.y -= 1;} function rotateCameraRight() {mesh.rotateY(Math.PI / 4);} function rotateCameraLeft() {mesh.rotateY(-Math.PI / 4);} 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(100, windowWidth / windowHeight, 1, 1000); //camera.position.set(0, 19, 20); camera.position.set(0, 19, 20);} async function LoadModeler() { const loader = new THREE.MMDLoader(); //Attempt at alt vmd laoder for pmx model/characters (declaring pmx is wrong ?) function LoadPMX() { return new Promise(resolve => { loader.load(Pmx, object => { mesh = object; scene.add(mesh); resolve(true); },);});} function LoadVMD(id) { return new Promise(resolve => { const path = "./vmd/" + id + ".vmd"; const val = MotionObjects.findIndex(MotionObject => MotionObject.id == id); loader.loadAnimation(path, mesh, vmd => { vmd.name = id; MotionObjects[val].VmdClip = vmd; resolve(true); },);});} function LoadAudio(id) { return new Promise(resolve => { const path = "./audio/" + id + ".mp3"; const val = MotionObjects.findIndex(MotionObject => MotionObject.id == id); if (MotionObjects[val].AudioClip) { new THREE.AudioLoader().load(path, buffer => { const listener = new THREE.AudioListener(); const audio = new THREE.Audio(listener).setBuffer(buffer); MotionObjects[val].AudioClip = audio; resolve(true); },); } else { resolve(false);}});} const urlParams = new URLSearchParams(window.location.search); object = "/pmx/pronama/" + (urlParams.get('pmx') || ''); function LoadVMDFile(filePath, object) { return new Promise((resolve, reject) => { loader.loadAnimation(filePath, object, animationClip => { createMixer(); playAnimation(animationClip); resolve(true); });});} objectReference = object; objectToAnimate = object; const loadButton = document.querySelector('#loadButton'); loadButton.addEventListener('click', function(event) { const vmdFilePath = event.target.value; object = objectReference; console.log(vmdFilePath); console.log('Object Reference:', objectReference); LoadVMDFile(vmdFilePath, objectToAnimate); }); function handleClick() { const loadButton = document.getElementById("loadButton"); const filePath = loadButton.value; LoadVMDFile(filePath) .then(result => { console.log(result);});} document.getElementById("loadButton").addEventListener("click", handleClick); const loadAdditionalPMX = () => { return new Promise(resolve => { loader.load(Stage, object => { const additionalMesh = object; scene.add(additionalMesh); resolve(true); const loadAdditionalPMX = () => { return new Promise(resolve => { loader.load(Stage, object => { const additionalMesh = object; scene.add(additionalMesh); resolve(true); });});}; let path; //preperations for 001.vmd and 002.vmd try {path = `./stages${stage.trim()}`;} catch (e) { path = '/default/default';} const lastIndex = path.lastIndexOf("/"); const basePath = path.substring(0, lastIndex); const vmd1 = `${basePath}/001.vmd`; const vmd2 = `${basePath}/002.vmd`; console.log(vmd1); console.log(vmd2); //Load Stage vmd animation let mixer; const url = window.location.href; const isAnimated = url.indexOf('animated') !== -1; if (isAnimated) { // Load Animation function createMixer() {mixer = new THREE.AnimationMixer(object);} function playAnimation(animationClip) { const action = mixer.clipAction(animationClip); action.play();} loader.loadAnimation(vmd1, object, (animationClip) => { createMixer(); playAnimation(animationClip);}); loader.loadAnimation(vmd2, object, (animationClip) => { playAnimation(animationClip);}); function animate() { requestAnimationFrame(animate); const deltaTime = clock.getDelta(); if (mixer) { mixer.update(deltaTime);} renderer.render(scene, camera);} animate();} },);});}; await Promise.all([loadAdditionalPMX()]); await LoadPMX(); await Promise.all(MotionObjects.map(async (MotionObject) => {return await LoadVMD(MotionObject.id);})); await Promise.all(MotionObjects.map(async (MotionObject) => {return await LoadAudio(MotionObject.id);})); VmdControl("loop", true);} VmdControl = (id, loop) => {const index = MotionObjects.findIndex(MotionObject => MotionObject.id == id); if (index === -1) {console.log("not Found ID");return;} ready = false; helper = new THREE.MMDAnimationHelper({ afterglow: 2.0, resetPhysicsOnLoop: true }); helper.add(mesh, { animation: MotionObjects[index].VmdClip, physics: false}); if (MotionObjects[index].AudioClip) { MotionObjects[index].AudioClip.play();} const mixer = helper.objects.get(mesh).mixer; if (!loop) { mixer.existingAction(MotionObjects[index].VmdClip).setLoop(THREE.LoopOnce);} mixer.addEventListener("loop", (event) => { console.log("loop");}); mixer.addEventListener("finished", (event) => { console.log("finished"); VmdControl("loop", 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());}} //Old-hardcoded--Pose-ClickEvent //PoseClickEvent = (id) => { // switch (id) { // case "pose1": // VmdControl("001", true); // break; // case "pose2": // VmdControl("002", false); // break; // case "pose3": // VmdControl("003", false); // break; // default: // VmdControl("001", true); // break;}} //New-autogenerated--from--MotionObject-Array-Pose-ClickEvent const generatePoseClickEvent = (motionObjects) => { const functionBody = motionObjects.map(function (motion) { return "case '" + motion.pose + "':\n" + " VmdControl('" + motion.id + "', " + (motion.pose === "pose1") + ");\n" + " break;\n"; }).join(""); const poseClickEventFunction = new Function("id", "switch (id) { " + functionBody + " default: VmdControl('001', true); break; }"); return poseClickEventFunction; }; const PoseClickEvent = generatePoseClickEvent(MotionObjects);