added gpu validater and frame limiter
This commit is contained in:
@@ -1,19 +1,17 @@
|
||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import * as THREE from 'three';
|
||||
import { useFrame } from '@react-three/fiber';
|
||||
import { useSceneContext } from '../../../../../scene/sceneContext';
|
||||
import useModuleStore from '../../../../../../store/ui/useModuleStore';
|
||||
import { usePauseButtonStore, useAnimationPlaySpeed } from '../../../../../../store/ui/usePlayButtonStore';
|
||||
import { useEffect, useRef, useCallback, useState } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { useSceneContext } from "../../../../../scene/sceneContext";
|
||||
import useModuleStore from "../../../../../../store/ui/useModuleStore";
|
||||
import { usePauseButtonStore, useAnimationPlaySpeed } from "../../../../../../store/ui/usePlayButtonStore";
|
||||
|
||||
interface ModelAnimatorProps {
|
||||
asset: Asset;
|
||||
gltfScene: THREE.Object3D;
|
||||
}
|
||||
|
||||
export function ModelAnimator({
|
||||
asset,
|
||||
gltfScene,
|
||||
}: ModelAnimatorProps) {
|
||||
export function ModelAnimator({ asset, gltfScene }: ModelAnimatorProps) {
|
||||
const clockRef = useRef(new THREE.Clock());
|
||||
const mixerRef = useRef<THREE.AnimationMixer>();
|
||||
const actions = useRef<{ [name: string]: THREE.AnimationAction }>({});
|
||||
const [previousAnimation, setPreviousAnimation] = useState<string | null>(null);
|
||||
@@ -43,7 +41,7 @@ export function ModelAnimator({
|
||||
actions.current[clip.name] = action;
|
||||
});
|
||||
|
||||
const animationNames = gltfScene.animations.map(clip => clip.name);
|
||||
const animationNames = gltfScene.animations.map((clip) => clip.name);
|
||||
setAnimations(asset.modelUuid, animationNames);
|
||||
|
||||
return () => {
|
||||
@@ -71,7 +69,7 @@ export function ModelAnimator({
|
||||
}
|
||||
|
||||
currentAction.play();
|
||||
mixerRef.current.addEventListener('finished', handleAnimationComplete);
|
||||
mixerRef.current.addEventListener("finished", handleAnimationComplete);
|
||||
setPreviousAnimation(current);
|
||||
} else {
|
||||
Object.values(actions.current).forEach((action) => action.stop());
|
||||
@@ -79,14 +77,15 @@ export function ModelAnimator({
|
||||
|
||||
return () => {
|
||||
if (mixerRef.current) {
|
||||
mixerRef.current.removeEventListener('finished', handleAnimationComplete);
|
||||
mixerRef.current.removeEventListener("finished", handleAnimationComplete);
|
||||
}
|
||||
};
|
||||
}, [asset.animationState?.current, asset.animationState?.isCompleted, asset.animationState?.isPlaying, isPaused, activeModule]);
|
||||
|
||||
useFrame((_, delta) => {
|
||||
if (mixerRef.current) {
|
||||
mixerRef.current.update(delta * (activeModule === 'simulation' ? speed : 1));
|
||||
useFrame(() => {
|
||||
if (mixerRef.current && !isPaused) {
|
||||
const delta = clockRef.current.getDelta();
|
||||
mixerRef.current.update(delta * (activeModule === "simulation" ? speed : 1));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CameraControls } from "@react-three/drei";
|
||||
import { useRef, useEffect, useState } from "react";
|
||||
import { useRef, useEffect } from "react";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import * as THREE from "three";
|
||||
import * as CONSTANTS from "../../../types/world/worldConstants";
|
||||
|
||||
40
app/src/modules/scene/helpers/frameLimiter.tsx
Normal file
40
app/src/modules/scene/helpers/frameLimiter.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Stats } from "@react-three/drei";
|
||||
import { useThree } from "@react-three/fiber";
|
||||
import { useLayoutEffect } from "react";
|
||||
import { useControls } from "leva";
|
||||
|
||||
function FPSLimiter() {
|
||||
const { advance, set, frameloop } = useThree();
|
||||
|
||||
const { fps } = useControls("Performance", {
|
||||
fps: { value: 30, min: 1, max: 60, step: 1 },
|
||||
});
|
||||
|
||||
useLayoutEffect(() => {
|
||||
let then = 0;
|
||||
let raf: number;
|
||||
const interval = 1000 / fps;
|
||||
|
||||
function tick(t: number) {
|
||||
raf = requestAnimationFrame(tick);
|
||||
const elapsed = t - then;
|
||||
|
||||
if (elapsed > interval) {
|
||||
advance(t, true);
|
||||
then = t - (elapsed % interval);
|
||||
}
|
||||
}
|
||||
|
||||
set({ frameloop: "never" });
|
||||
raf = requestAnimationFrame(tick);
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(raf);
|
||||
set({ frameloop });
|
||||
};
|
||||
}, [fps, advance, set, frameloop]);
|
||||
|
||||
return <Stats />;
|
||||
}
|
||||
|
||||
export default FPSLimiter;
|
||||
9
app/src/modules/scene/helpers/gpuValidater.tsx
Normal file
9
app/src/modules/scene/helpers/gpuValidater.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import { useDetectGPU } from "@react-three/drei";
|
||||
|
||||
function GpuValidater() {
|
||||
const GPUTier = useDetectGPU();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export default GpuValidater;
|
||||
@@ -1,10 +1,13 @@
|
||||
import Sun from '../environment/sky'
|
||||
import Shadows from '../environment/shadow'
|
||||
import Sun from "../environment/sky";
|
||||
import Shadows from "../environment/shadow";
|
||||
// import Clouds from '../clouds/clouds';
|
||||
import PostProcessing from '../postProcessing/postProcessing'
|
||||
import StatsHelper from '../helpers/StatsHelper';
|
||||
import Controls from '../controls/controls';
|
||||
import { AdaptiveDpr, AdaptiveEvents, Environment } from '@react-three/drei'
|
||||
import PostProcessing from "../postProcessing/postProcessing";
|
||||
import StatsHelper from "../helpers/StatsHelper";
|
||||
// import AutoRotate from "../tools/autoRotate";
|
||||
import Controls from "../controls/controls";
|
||||
import FPSLimiter from "../helpers/frameLimiter";
|
||||
import GpuValidater from "../helpers/gpuValidater";
|
||||
import { AdaptiveDpr, AdaptiveEvents, Environment } from "@react-three/drei";
|
||||
|
||||
import background from "../../../assets/textures/hdr/mudroadpuresky2k.hdr";
|
||||
|
||||
@@ -23,13 +26,19 @@ function Setup() {
|
||||
|
||||
<Environment files={background} environmentIntensity={1.5} />
|
||||
|
||||
{/* <AutoRotate /> */}
|
||||
|
||||
<FPSLimiter />
|
||||
|
||||
<GpuValidater />
|
||||
|
||||
<StatsHelper />
|
||||
|
||||
<AdaptiveEvents />
|
||||
|
||||
<AdaptiveDpr pixelated />
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default Setup;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import * as THREE from "three";
|
||||
import { useFrame, useThree } from "@react-three/fiber";
|
||||
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from "../../../../../store/ui/usePlayButtonStore";
|
||||
@@ -28,6 +28,7 @@ function PillarJibAnimator({
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { isReset } = useResetButtonStore();
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const clockRef = useRef(new THREE.Clock());
|
||||
|
||||
const [clampedPoints, setClampedPoints] = useState<[THREE.Vector3, THREE.Vector3]>();
|
||||
|
||||
@@ -66,7 +67,11 @@ function PillarJibAnimator({
|
||||
const humanAction = getActionByUuid(selectedProduct.productUuid, action?.triggers[0].triggeredAsset?.triggeredAction?.actionUuid || "");
|
||||
|
||||
if (humanAction) {
|
||||
const point = getPointByUuid(selectedProduct.productUuid, humanAction.triggers[0].triggeredAsset?.triggeredModel?.modelUuid || "", humanAction.triggers[0].triggeredAsset?.triggeredPoint?.pointUuid || "");
|
||||
const point = getPointByUuid(
|
||||
selectedProduct.productUuid,
|
||||
humanAction.triggers[0].triggeredAsset?.triggeredModel?.modelUuid || "",
|
||||
humanAction.triggers[0].triggeredAsset?.triggeredPoint?.pointUuid || ""
|
||||
);
|
||||
const eventModel = scene.getObjectByProperty("uuid", humanAction.triggers[0].triggeredAsset?.triggeredModel?.modelUuid);
|
||||
if (point && eventModel) {
|
||||
const pointLocal = new THREE.Vector3(...point.position);
|
||||
@@ -149,8 +154,13 @@ function PillarJibAnimator({
|
||||
useFrame(() => {
|
||||
if (!isPlaying || isPaused || !points || !clampedPoints || animationPhase === "idle") return;
|
||||
|
||||
const delta = clockRef.current.getDelta();
|
||||
stepCrane(delta * speed);
|
||||
});
|
||||
|
||||
function stepCrane(dt: number) {
|
||||
const model = scene.getObjectByProperty("uuid", crane.modelUuid);
|
||||
if (!model) return;
|
||||
if (!model || !clampedPoints) return;
|
||||
|
||||
const base = model.getObjectByName("base");
|
||||
const trolley = model.getObjectByName("trolley");
|
||||
@@ -164,9 +174,13 @@ function PillarJibAnimator({
|
||||
const hookWorld = new THREE.Vector3();
|
||||
hook.getWorldPosition(hookWorld);
|
||||
|
||||
const hookSpeed = (model.userData.hookSpeed || 0.01) * speed;
|
||||
const rotationSpeed = (model.userData.rotationSpeed || 0.005) * speed;
|
||||
const trolleySpeed = (model.userData.trolleySpeed || 0.01) * speed;
|
||||
const hookSpeed = (model.userData.fieldData.hookSpeed || 0.1) * speed;
|
||||
const rotationSpeed = (model.userData.fieldData.rotationSpeed || 0.25) * speed;
|
||||
const trolleySpeed = (model.userData.fieldData.trolleySpeed || 0.1) * speed;
|
||||
|
||||
const hookStep = hookSpeed * dt;
|
||||
const rotationStep = rotationSpeed * dt;
|
||||
const trolleyStep = trolleySpeed * dt;
|
||||
|
||||
const threshold = Math.max(0.01, 0.05 / speed);
|
||||
|
||||
@@ -179,7 +193,7 @@ function PillarJibAnimator({
|
||||
const diff = targetY - hookWorld.y;
|
||||
|
||||
if (Math.abs(diff) > threshold) {
|
||||
const step = Math.sign(diff) * hookSpeed;
|
||||
const step = Math.sign(diff) * hookStep;
|
||||
if (Math.abs(step) > Math.abs(diff)) {
|
||||
const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone());
|
||||
hook.position.y = localTarget.y;
|
||||
@@ -215,7 +229,7 @@ function PillarJibAnimator({
|
||||
angleDiff = Math.atan2(Math.sin(angleDiff), Math.cos(angleDiff));
|
||||
|
||||
if (parseFloat(Math.abs(angleDiff).toFixed(2)) > 0.05) {
|
||||
const step = Math.sign(angleDiff) * rotationSpeed;
|
||||
const step = Math.sign(angleDiff) * rotationStep;
|
||||
|
||||
if (Math.abs(step) > Math.abs(angleDiff)) {
|
||||
base.rotation.y += angleDiff;
|
||||
@@ -240,7 +254,7 @@ function PillarJibAnimator({
|
||||
const diff = localTarget.x - trolley.position.x;
|
||||
|
||||
if (Math.abs(diff) > threshold) {
|
||||
const step = Math.sign(diff) * trolleySpeed;
|
||||
const step = Math.sign(diff) * trolleyStep;
|
||||
if (Math.abs(step) > Math.abs(diff)) {
|
||||
trolley.position.x = localTarget.x;
|
||||
setAnimationPhase("init-final-hook-adjust");
|
||||
@@ -262,7 +276,7 @@ function PillarJibAnimator({
|
||||
const diff = targetY - hookWorld.y;
|
||||
|
||||
if (Math.abs(diff) > threshold) {
|
||||
const step = Math.sign(diff) * hookSpeed;
|
||||
const step = Math.sign(diff) * hookStep;
|
||||
if (Math.abs(step) > Math.abs(diff)) {
|
||||
const localTarget = hook.parent.worldToLocal(clampedPoints[0].clone());
|
||||
hook.position.y = localTarget.y;
|
||||
@@ -287,7 +301,7 @@ function PillarJibAnimator({
|
||||
const diff = targetY - hookWorld.y;
|
||||
|
||||
if (Math.abs(diff) > threshold) {
|
||||
const step = Math.sign(diff) * hookSpeed;
|
||||
const step = Math.sign(diff) * hookStep;
|
||||
if (Math.abs(step) > Math.abs(diff)) {
|
||||
const localTarget = hook.parent.worldToLocal(targetWorld.clone());
|
||||
hook.position.y = localTarget.y;
|
||||
@@ -323,7 +337,7 @@ function PillarJibAnimator({
|
||||
angleDiff = Math.atan2(Math.sin(angleDiff), Math.cos(angleDiff));
|
||||
|
||||
if (parseFloat(Math.abs(angleDiff).toFixed(2)) > 0.05) {
|
||||
const step = Math.sign(angleDiff) * rotationSpeed;
|
||||
const step = Math.sign(angleDiff) * rotationStep;
|
||||
|
||||
if (Math.abs(step) > Math.abs(angleDiff)) {
|
||||
base.rotation.y += angleDiff;
|
||||
@@ -348,7 +362,7 @@ function PillarJibAnimator({
|
||||
const diff = localTarget.x - trolley.position.x;
|
||||
|
||||
if (Math.abs(diff) > threshold) {
|
||||
const step = Math.sign(diff) * trolleySpeed;
|
||||
const step = Math.sign(diff) * trolleyStep;
|
||||
if (Math.abs(step) > Math.abs(diff)) {
|
||||
trolley.position.x = localTarget.x;
|
||||
setAnimationPhase("first-final-hook-adjust");
|
||||
@@ -370,7 +384,7 @@ function PillarJibAnimator({
|
||||
const diff = targetY - hookWorld.y;
|
||||
|
||||
if (Math.abs(diff) > threshold) {
|
||||
const step = Math.sign(diff) * hookSpeed;
|
||||
const step = Math.sign(diff) * hookStep;
|
||||
if (Math.abs(step) > Math.abs(diff)) {
|
||||
const localTarget = hook.parent.worldToLocal(clampedPoints[1].clone());
|
||||
hook.position.y = localTarget.y;
|
||||
@@ -398,7 +412,7 @@ function PillarJibAnimator({
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return <></>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user