Feat/map-environment #6
@@ -4,16 +4,11 @@ import {
|
||||
MAP_INSTANCING_ASSET_TYPES,
|
||||
type MapInstancingAssetType,
|
||||
} from "@/data/world/mapInstancingConfig";
|
||||
import type { MapNode } from "@/types/map/mapScene";
|
||||
import {
|
||||
type MapNodeInstanceTransform,
|
||||
mapNodeToInstanceTransform,
|
||||
} from "@/utils/map/mapInstanceTransform";
|
||||
import type { MapAssetInstance, MapNode } from "@/types/map/mapScene";
|
||||
import { mapNodeToInstanceTransform } from "@/utils/map/mapInstanceTransform";
|
||||
import { logger } from "@/utils/core/Logger";
|
||||
import { getMapNodes, loadMapSceneData } from "@/utils/map/loadMapSceneData";
|
||||
|
||||
export type MapAssetInstance = MapNodeInstanceTransform;
|
||||
|
||||
export type MapInstancingData = Map<MapInstancingAssetType, MapAssetInstance[]>;
|
||||
|
||||
function extractMapInstancingData(mapNodes: MapNode[]): MapInstancingData {
|
||||
@@ -65,6 +60,11 @@ export function useMapInstancingData(): {
|
||||
logger.error("MapInstancing", "Failed to load map instancing data", {
|
||||
error: error instanceof Error ? error : String(error),
|
||||
});
|
||||
if (!cancelled) {
|
||||
setData(null);
|
||||
setIsLoading(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const nodes = getMapNodes();
|
||||
|
||||
@@ -7,12 +7,13 @@ import {
|
||||
normalizeMapScale,
|
||||
useTerrainHeightSampler,
|
||||
} from "@/hooks/three/useTerrainHeight";
|
||||
import type { MapAssetInstance } from "@/hooks/world/useMapInstancingData";
|
||||
import type { MapAssetInstance } from "@/types/map/mapScene";
|
||||
import { optimizeGLTFSceneTextures } from "@/utils/three/optimizeGLTFScene";
|
||||
|
||||
interface InstancedMapAssetProps {
|
||||
modelPath: string;
|
||||
instances: MapAssetInstance[];
|
||||
scaleMultiplier: number;
|
||||
castShadow: boolean;
|
||||
receiveShadow: boolean;
|
||||
}
|
||||
@@ -133,6 +134,7 @@ function extractMeshes(scene: THREE.Group): MeshData[] {
|
||||
function setInstanceMatrices(
|
||||
instancedMesh: THREE.InstancedMesh,
|
||||
instances: MapAssetInstance[],
|
||||
scaleMultiplier: number,
|
||||
geometryBottomY: number,
|
||||
): void {
|
||||
const position = new THREE.Vector3();
|
||||
@@ -148,7 +150,11 @@ function setInstanceMatrices(
|
||||
position.set(...instance.position);
|
||||
rotation.set(...instance.rotation);
|
||||
quaternion.setFromEuler(rotation);
|
||||
scale.set(...instance.scale);
|
||||
scale.set(
|
||||
instance.scale[0] * scaleMultiplier,
|
||||
instance.scale[1] * scaleMultiplier,
|
||||
instance.scale[2] * scaleMultiplier,
|
||||
);
|
||||
position.y += -geometryBottomY * scale.y;
|
||||
matrix.compose(position, quaternion, scale);
|
||||
instancedMesh.setMatrixAt(i, matrix);
|
||||
@@ -174,6 +180,7 @@ function getMeshBottomY(meshDataList: MeshData[]): number {
|
||||
export function InstancedMapAsset({
|
||||
modelPath,
|
||||
instances,
|
||||
scaleMultiplier,
|
||||
castShadow,
|
||||
receiveShadow,
|
||||
}: InstancedMapAssetProps): React.JSX.Element | null {
|
||||
@@ -219,7 +226,12 @@ export function InstancedMapAsset({
|
||||
groundedInstances.length,
|
||||
);
|
||||
|
||||
setInstanceMatrices(instancedMesh, groundedInstances, geometryBottomY);
|
||||
setInstanceMatrices(
|
||||
instancedMesh,
|
||||
groundedInstances,
|
||||
scaleMultiplier,
|
||||
geometryBottomY,
|
||||
);
|
||||
instancedMesh.castShadow = castShadow;
|
||||
instancedMesh.receiveShadow = receiveShadow;
|
||||
instancedMesh.name = `instanced-map-asset-${index}`;
|
||||
@@ -239,7 +251,13 @@ export function InstancedMapAsset({
|
||||
disposeInstancedMapMesh(mesh);
|
||||
}
|
||||
};
|
||||
}, [castShadow, groundedInstances, meshDataList, receiveShadow]);
|
||||
}, [
|
||||
castShadow,
|
||||
groundedInstances,
|
||||
meshDataList,
|
||||
receiveShadow,
|
||||
scaleMultiplier,
|
||||
]);
|
||||
|
||||
if (instances.length === 0) {
|
||||
return null;
|
||||
|
||||
@@ -14,10 +14,13 @@ import {
|
||||
type MapInstancingAssetConfig,
|
||||
type MapInstancingAssetType,
|
||||
} from "@/data/world/mapInstancingConfig";
|
||||
import {
|
||||
type MapAssetInstance,
|
||||
useMapInstancingData,
|
||||
} from "@/hooks/world/useMapInstancingData";
|
||||
import { useMapInstancingData } from "@/hooks/world/useMapInstancingData";
|
||||
import type { MapAssetInstance } from "@/types/map/mapScene";
|
||||
|
||||
interface MapInstancingSystemProps {
|
||||
onlyModelName?: string | null;
|
||||
streaming?: boolean;
|
||||
}
|
||||
|
||||
interface MapAssetChunk {
|
||||
key: string;
|
||||
@@ -72,14 +75,20 @@ function createMapAssetChunks(
|
||||
});
|
||||
}
|
||||
|
||||
export function MapInstancingSystem(): React.JSX.Element | null {
|
||||
export function MapInstancingSystem({
|
||||
onlyModelName = null,
|
||||
streaming = true,
|
||||
}: MapInstancingSystemProps): React.JSX.Element | null {
|
||||
const cameraMode = useCameraMode();
|
||||
const sceneMode = useSceneMode();
|
||||
const groups = useMapPerformanceStore((state) => state.groups);
|
||||
const models = useMapPerformanceStore((state) => state.models);
|
||||
const { data, isLoading } = useMapInstancingData();
|
||||
const streamingEnabled =
|
||||
CHUNK_CONFIG.enabled && sceneMode === "game" && cameraMode === "player";
|
||||
streaming &&
|
||||
CHUNK_CONFIG.enabled &&
|
||||
sceneMode === "game" &&
|
||||
cameraMode === "player";
|
||||
|
||||
const chunks = useMemo(() => {
|
||||
if (!data) return [];
|
||||
@@ -87,6 +96,8 @@ export function MapInstancingSystem(): React.JSX.Element | null {
|
||||
return MAP_INSTANCING_ASSET_TYPES.flatMap((type) => {
|
||||
const config = MAP_INSTANCING_ASSETS[type];
|
||||
|
||||
if (onlyModelName && config.mapName !== onlyModelName) return [];
|
||||
|
||||
if (
|
||||
!config.enabled ||
|
||||
!isMapModelVisible(config.mapName, { groups, models })
|
||||
@@ -99,7 +110,7 @@ export function MapInstancingSystem(): React.JSX.Element | null {
|
||||
|
||||
return createMapAssetChunks(type, config, instances);
|
||||
});
|
||||
}, [data, groups, models]);
|
||||
}, [data, groups, models, onlyModelName]);
|
||||
|
||||
const visibleChunks = useVisibleWorldChunks(chunks, streamingEnabled);
|
||||
|
||||
@@ -114,6 +125,7 @@ export function MapInstancingSystem(): React.JSX.Element | null {
|
||||
<InstancedMapAsset
|
||||
modelPath={chunk.config.modelPath}
|
||||
instances={chunk.instances}
|
||||
scaleMultiplier={chunk.config.scaleMultiplier}
|
||||
castShadow={chunk.config.castShadow}
|
||||
receiveShadow={chunk.config.receiveShadow}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user