feat(web-platform): release V0.8.1 常规地图优化
This commit is contained in:
@@ -24,7 +24,8 @@ import type {
|
||||
import { composePhysicalMap } from '../map/physicalMap';
|
||||
import { composeProjectMap } from '../map/MapComposer';
|
||||
import { resolveProjectMap } from '../map/MapLoader';
|
||||
import { DEFAULT_MAP_SELECTION, type MapSelection } from '../map/types';
|
||||
import { composePlacedMapAssets } from '../map/MapStackComposer';
|
||||
import { DEFAULT_MAP_SELECTION, type MapSelection, type PlacedMapAsset } from '../map/types';
|
||||
|
||||
export type UrdfLoadMode = 'mjcf' | 'native';
|
||||
export type { UrdfBaseMode, UrdfEnhancementOptions };
|
||||
@@ -38,7 +39,9 @@ export interface PhysicsLoadOptions {
|
||||
urdfMode?: UrdfLoadMode;
|
||||
baseMode?: UrdfBaseMode;
|
||||
enhancements?: UrdfEnhancementOptions;
|
||||
/** @deprecated 单地图兼容入口;新场景应使用 mapAssets。 */
|
||||
map?: MapSelection;
|
||||
mapAssets?: readonly PlacedMapAsset[];
|
||||
onProgress?: (progress: PhysicsLoadProgress) => void;
|
||||
}
|
||||
|
||||
@@ -126,6 +129,8 @@ export class MainThreadPhysicsAdapter implements PhysicsAdapter {
|
||||
sensorType: 'camera',
|
||||
};
|
||||
const mapSelection = options.map ?? DEFAULT_MAP_SELECTION;
|
||||
const placedMapAssets = options.mapAssets;
|
||||
const hasMaps = placedMapAssets ? placedMapAssets.length > 0 : mapSelection.kind !== 'none';
|
||||
const report = (value: number, label: string) => {
|
||||
if (!this.disposed && generation === this.loadGeneration)
|
||||
options.onProgress?.({ value, label });
|
||||
@@ -191,24 +196,31 @@ export class MainThreadPhysicsAdapter implements PhysicsAdapter {
|
||||
intermediate.dispose();
|
||||
}
|
||||
}
|
||||
if (mapSelection.kind !== 'none') {
|
||||
if (hasMaps) {
|
||||
report(0.72, '组合机器人与物理地图');
|
||||
if (entry?.format === 'urdf' && urdfMode === 'native')
|
||||
throw new Error('原生 URDF 模式暂不支持地图,请切换为转换模式');
|
||||
const slash = modelRelativePath.lastIndexOf('/');
|
||||
const directory = slash >= 0 ? modelRelativePath.slice(0, slash + 1) : '';
|
||||
const mapPath = `${directory}.__mujoco_map_scene_${manifest.id.replace(/[^a-zA-Z0-9_-]/g, '_')}.xml`;
|
||||
if (mapSelection.kind === 'builtin') {
|
||||
const composed = composePhysicalMap(
|
||||
new TextEncoder().encode(workspace.readText(modelRelativePath)),
|
||||
mapSelection.config,
|
||||
const source = new TextEncoder().encode(workspace.readText(modelRelativePath));
|
||||
if (placedMapAssets) {
|
||||
const composed = composePlacedMapAssets(
|
||||
source,
|
||||
mapPath,
|
||||
prepared.manifest,
|
||||
placedMapAssets,
|
||||
);
|
||||
workspace.writeGenerated(mapPath, composed.data);
|
||||
warnings.push(...composed.warnings);
|
||||
} else if (mapSelection.kind === 'builtin') {
|
||||
const composed = composePhysicalMap(source, mapSelection.config);
|
||||
workspace.writeGenerated(mapPath, composed.data);
|
||||
if (composed.summary) warnings.push(composed.summary);
|
||||
} else {
|
||||
} else if (mapSelection.kind === 'project') {
|
||||
const resolvedMap = resolveProjectMap(prepared.manifest, mapSelection.descriptorPath);
|
||||
const composed = composeProjectMap(
|
||||
new TextEncoder().encode(workspace.readText(modelRelativePath)),
|
||||
source,
|
||||
mapPath,
|
||||
prepared.manifest,
|
||||
resolvedMap,
|
||||
@@ -339,21 +351,41 @@ export class MainThreadPhysicsAdapter implements PhysicsAdapter {
|
||||
return this.supportFiles.map((file) => ({ ...file, data: file.data.slice() }));
|
||||
}
|
||||
releaseRetired(): void {
|
||||
this.retiredSession?.dispose();
|
||||
const retiredSession = this.retiredSession;
|
||||
const retiredWorkspace = this.retiredWorkspace;
|
||||
this.retiredSession = null;
|
||||
this.retiredWorkspace?.dispose();
|
||||
this.retiredWorkspace = null;
|
||||
this.retiredSupportFiles = [];
|
||||
try {
|
||||
retiredSession?.dispose();
|
||||
} catch (error) {
|
||||
console.warn('[MuJoCo] 释放旧仿真会话失败', error);
|
||||
}
|
||||
try {
|
||||
retiredWorkspace?.dispose();
|
||||
} catch (error) {
|
||||
console.warn('[MuJoCo] 释放旧内存工作区失败', error);
|
||||
}
|
||||
}
|
||||
rollbackRetired(): void {
|
||||
this.session?.dispose();
|
||||
this.workspace?.dispose();
|
||||
const failedSession = this.session;
|
||||
const failedWorkspace = this.workspace;
|
||||
this.session = this.retiredSession;
|
||||
this.workspace = this.retiredWorkspace;
|
||||
this.supportFiles = this.retiredSupportFiles;
|
||||
this.retiredSession = null;
|
||||
this.retiredWorkspace = null;
|
||||
this.retiredSupportFiles = [];
|
||||
try {
|
||||
failedSession?.dispose();
|
||||
} catch (error) {
|
||||
console.warn('[MuJoCo] 释放失败的候选仿真会话失败', error);
|
||||
}
|
||||
try {
|
||||
failedWorkspace?.dispose();
|
||||
} catch (error) {
|
||||
console.warn('[MuJoCo] 释放失败的候选内存工作区失败', error);
|
||||
}
|
||||
}
|
||||
exportMjcf(): Uint8Array {
|
||||
if (!this.session || !this.workspace) throw new Error('尚未加载可导出的模型');
|
||||
|
||||
Reference in New Issue
Block a user