diff --git a/src/components/VrmViewer.tsx b/src/components/VrmViewer.tsx
index 9a25d4d..14169e0 100644
--- a/src/components/VrmViewer.tsx
+++ b/src/components/VrmViewer.tsx
@@ -2,7 +2,9 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { Viewer } from '@/features/vrmViewer/viewer';
import AvatarSample_A from '../assets/AvatarSample_A.vrm';
import { loadVRMAnimation } from '@/lib/VRMAnimation/loadVRMAnimation';
-import { Button } from '@charcoal-ui/react';
+import { IconButton } from '@charcoal-ui/react';
+import '@/icons';
+import { useAnimationFrame } from '@/utils/useAnimationFrame';
interface VRMViewerProps {
blobURL: string | null;
@@ -10,7 +12,10 @@ interface VRMViewerProps {
export default function VrmViewer(props: VRMViewerProps) {
const [viewer] = useState
(new Viewer());
const [loadFlag, setLoadFlag] = useState(false);
+ const [isPlaying, setPlaying] = useState(false);
+ const refDivProgress = useRef(null);
const blobURL = props.blobURL;
+
const canvasRef = useCallback(
async (canvas: HTMLCanvasElement) => {
if (canvas) {
@@ -21,29 +26,69 @@ export default function VrmViewer(props: VRMViewerProps) {
},
[viewer]
);
+
+ const pauseAnimation = useCallback(() => {
+ if (viewer.model) {
+ viewer.model.pauseAction();
+ setPlaying(false);
+ }
+ }, []);
+
+ const playAnimation = useCallback(() => {
+ if (viewer.model) {
+ viewer.model.playAction();
+ setPlaying(true);
+ }
+ }, []);
+
+ const handlePointerDownProgress = useCallback((event: React.MouseEvent) => {
+ const target = event.nativeEvent.target as HTMLDivElement;
+ const rect = target.getBoundingClientRect();
+
+ const u = (event.clientX - rect.left) / rect.width;
+ console.log(event.clientX, rect.left, rect.width);
+ viewer.model?.setProgress(u);
+ }, []);
+
useEffect(() => {
(async () => {
if (blobURL) {
const VRMAnimation = await loadVRMAnimation(blobURL);
if (VRMAnimation && loadFlag && viewer.model) {
await viewer.model.loadAnimation(VRMAnimation);
+ playAnimation();
}
}
})();
}, [blobURL, loadFlag, viewer.model]);
- const playAnimation = () => {
- if (viewer.model) {
- viewer.model.playAction();
+ useAnimationFrame(() => {
+ const divProgress = refDivProgress.current;
+ if (divProgress != null) {
+ divProgress.style.width = `${100.0 * (viewer.model?.progress ?? 0.0)}%`;
}
- };
+ }, []);
return (
-
-
+
);
}
diff --git a/src/features/vrmViewer/Model.ts b/src/features/vrmViewer/Model.ts
index 81e2799..c3bf32b 100644
--- a/src/features/vrmViewer/Model.ts
+++ b/src/features/vrmViewer/Model.ts
@@ -24,6 +24,16 @@ export class Model {
this.mixer = new THREE.AnimationMixer(vrm.scene);
}
+ public get progress(): number {
+ const action = this.currentAction;
+
+ if (action != null) {
+ return action.time / action.getClip().duration;
+ } else {
+ return 0.0;
+ }
+ }
+
public async loadAnimation(vrmAnimation: VRMAnimation): Promise
{
const { vrm, mixer } = this;
if (vrm == null || mixer == null) {
@@ -39,10 +49,21 @@ export class Model {
public playAction() {
if (this.currentAction && this.mixer) {
- this.mixer.addEventListener('loop', () => {
- this.currentAction?.stop();
- });
this.currentAction.play();
+ this.currentAction.paused = false;
+ }
+ }
+
+ public pauseAction() {
+ if (this.currentAction && this.mixer) {
+ this.currentAction.paused = true;
+ }
+ }
+
+ public setProgress(progress: number) {
+ if (this.currentAction && this.mixer) {
+ const duration = this.currentAction.getClip().duration;
+ this.currentAction.time = duration * progress;
}
}
diff --git a/src/icons/PlayAlt.svg b/src/icons/PlayAlt.svg
new file mode 100644
index 0000000..d0bbfa0
--- /dev/null
+++ b/src/icons/PlayAlt.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/icons/index.ts b/src/icons/index.ts
new file mode 100644
index 0000000..5bce393
--- /dev/null
+++ b/src/icons/index.ts
@@ -0,0 +1,12 @@
+import { PixivIcon } from '@charcoal-ui/icons';
+import PlayAlt from './PlayAlt.svg';
+
+PixivIcon.extend({
+ '24/PlayAlt': PlayAlt.src,
+});
+
+declare module '@charcoal-ui/icons' {
+ export interface KnownIconType {
+ '24/PlayAlt': unknown,
+ }
+}
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index ea4862b..f4618b6 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -11,14 +11,14 @@ export default function Home() {
return (
-
-
+
+
{blobURL ? (
<>
-
diff --git a/src/utils/useAnimationFrame.ts b/src/utils/useAnimationFrame.ts
new file mode 100644
index 0000000..5265ff3
--- /dev/null
+++ b/src/utils/useAnimationFrame.ts
@@ -0,0 +1,27 @@
+import { DependencyList, useEffect, useRef } from 'react';
+
+export function useAnimationFrame(
+ callback: (delta: number) => void,
+ deps: DependencyList
+): void {
+ const refPrev = useRef
(0);
+
+ useEffect(() => {
+ let halt = false;
+ const update = (): void => {
+ if (halt) { return; }
+
+ const now = Date.now();
+ callback(0.001 * (now - refPrev.current));
+ refPrev.current = now;
+
+ requestAnimationFrame(update);
+ };
+ update();
+
+ return () => {
+ halt = true;
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [ callback, ...deps ]);
+}
From 4137979249d5efb49e2eb15286eb63f9be6bb40c Mon Sep 17 00:00:00 2001
From: 0b5vr <0b5vr@0b5vr.com>
Date: Fri, 21 Jul 2023 15:32:27 +0900
Subject: [PATCH 2/3] ui: tweak color of progress bar
text4 -> text3-disabled
---
src/components/VrmViewer.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/VrmViewer.tsx b/src/components/VrmViewer.tsx
index 14169e0..688d544 100644
--- a/src/components/VrmViewer.tsx
+++ b/src/components/VrmViewer.tsx
@@ -84,7 +84,7 @@ export default function VrmViewer(props: VRMViewerProps) {
className="flex w-full h-full grow items-center cursor-pointer"
onPointerDown={handlePointerDownProgress}
>
-
From 6fad8b410144badfd474376e6e2c8defc36bdfa1 Mon Sep 17 00:00:00 2001
From: 0b5vr <0b5vr@0b5vr.com>
Date: Fri, 21 Jul 2023 15:33:40 +0900
Subject: [PATCH 3/3] =?UTF-8?q?fix:=20Fix=20wording,=20=E5=A4=89=E6=9B=B4?=
=?UTF-8?q?=E3=81=8C=E5=AE=8C=E4=BA=86=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?=
=?UTF-8?q?=20=E2=86=92=20=E5=A4=89=E6=8F=9B=E3=81=8C=E5=AE=8C=E4=BA=86?=
=?UTF-8?q?=E3=81=97=E3=81=BE=E3=81=97=E3=81=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/LoadBVH.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/LoadBVH.tsx b/src/components/LoadBVH.tsx
index e156679..77b5069 100644
--- a/src/components/LoadBVH.tsx
+++ b/src/components/LoadBVH.tsx
@@ -108,7 +108,7 @@ const LoadBVH = (props: LoadBVHProps) => {
- 変更が完了しました
+ 変換が完了しました