added gpu validater and frame limiter

This commit is contained in:
2025-09-09 12:29:30 +05:30
parent 775b151364
commit 24a38e47c3
6 changed files with 110 additions and 39 deletions

View File

@@ -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));
}
});

View File

@@ -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";

View 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;

View File

@@ -0,0 +1,9 @@
import { useDetectGPU } from "@react-three/drei";
function GpuValidater() {
const GPUTier = useDetectGPU();
return null;
}
export default GpuValidater;

View File

@@ -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;

View File

@@ -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 <></>;
}