import React, { useMemo, useRef } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
export const LOD_LEVELS = {
HIGH: 0,
MEDIUM: 1,
LOW: 2,
};
export const LOD_DISTANCES = {
HIGH: 5,
MEDIUM: 10,
};
const createSimplifiedDeviceMesh = (device, uHeight, rackDepth, deviceColor, statusColor) => {
const depth = rackDepth || 1.0;
const dHeight = device.height || device.u_height || 1;
const height = dHeight * uHeight;
const chassisWidth = 0.44;
const chassisDepth = 0.8;
const panelWidth = 0.4826;
const panelDepth = 0.02;
const frontZ = depth / 2 - 0.02;
const halfHeight = height / 2;
return (
);
};
const createMediumDeviceMesh = (device, uHeight, rackDepth, deviceColor, statusColor) => {
const depth = rackDepth || 1.0;
const dHeight = device.height || device.u_height || 1;
const height = dHeight * uHeight;
const chassisWidth = 0.44;
const chassisDepth = 0.8;
const panelWidth = 0.4826;
const panelDepth = 0.02;
const frontZ = depth / 2 - 0.02;
const is2U = height > 0.08;
const halfHeight = height / 2;
return (
{Array.from({ length: is2U ? 4 : 2 }).map((_, i) => (
))}
);
};
const LODManager = ({
device,
uHeight,
rackDepth,
position,
deviceColor,
statusColor,
children,
level = LOD_LEVELS.HIGH,
}) => {
const groupRef = useRef();
const highDetailRef = useRef();
const mediumDetailRef = useRef();
const lowDetailRef = useRef();
const { camera } = useThree();
// 使用 ref 存储 LOD 级别,避免 React 状态更新
const lodLevelRef = useRef(LOD_LEVELS.HIGH);
const distanceRef = useRef(0);
// 帧计数器,用于节流
const frameCount = useRef(0);
// 用于强制重新渲染的 state(仅在必要时更新)
const [, forceUpdate] = React.useReducer(x => x + 1, 0);
useFrame(() => {
if (!groupRef.current) return;
// 节流:每5帧检查一次
frameCount.current++;
if (frameCount.current % 5 !== 0) return;
const distance = camera.position.distanceTo(groupRef.current.position);
distanceRef.current = distance;
// 添加缓冲避免频繁切换(10% 缓冲)
const buffer = 0.1;
const highThreshold = LOD_DISTANCES.HIGH * (1 + buffer);
const mediumThreshold = LOD_DISTANCES.MEDIUM * (1 + buffer);
let newLevel = LOD_LEVELS.HIGH;
if (distance > mediumThreshold) {
newLevel = LOD_LEVELS.LOW;
} else if (distance > highThreshold) {
newLevel = LOD_LEVELS.MEDIUM;
}
// 只有当级别变化时才更新
if (newLevel !== lodLevelRef.current) {
lodLevelRef.current = newLevel;
// 直接操作 ref 切换可见性,避免频繁的 React 重渲染
if (highDetailRef.current) {
highDetailRef.current.visible = newLevel === LOD_LEVELS.HIGH;
}
if (mediumDetailRef.current) {
mediumDetailRef.current.visible = newLevel === LOD_LEVELS.MEDIUM;
}
if (lowDetailRef.current) {
lowDetailRef.current.visible = newLevel === LOD_LEVELS.LOW;
}
// 偶尔强制更新以确保同步(每30帧)
if (frameCount.current % 30 === 0) {
forceUpdate();
}
}
});
if (level !== LOD_LEVELS.HIGH) {
return children;
}
return (
{/* 高细节模型 - 默认显示 */}
{children}
{/* 中等细节模型 */}
{createMediumDeviceMesh(device, uHeight, rackDepth, deviceColor, statusColor)}
{/* 低细节模型 */}
{createSimplifiedDeviceMesh(device, uHeight, rackDepth, deviceColor, statusColor)}
);
};
export default LODManager;