| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- import * as THREE from 'three'
- /**
- * 坐标系转换工具
- * 处理不同3D软件导出的模型坐标系差异
- */
- export type CoordinateSystem =
- | 'y-up' // Three.js 默认: Y轴朝上,Z轴向前
- | 'z-up' // Blender/3ds Max 默认: Z轴朝上,Y轴向前
- | 'z-up-forward-x' // 某些CAD软件: Z轴朝上,X轴向前
- /**
- * 转换模型坐标系
- * @param model - Three.js 3D对象
- * @param from - 源坐标系
- * @param to - 目标坐标系 (默认为 Three.js 的 y-up)
- * @param rotationOption - 旋转选项 (默认: standard, 可选: flipped, 180)
- * @returns 转换后的模型
- */
- export function convertCoordinateSystem(
- model: THREE.Object3D,
- from: CoordinateSystem,
- to: CoordinateSystem = 'y-up',
- rotationOption: 'standard' | 'flipped' | '180' = 'standard'
- ): THREE.Object3D {
- if (from === to) return model
- // 定义坐标系转换矩阵
- const conversionMatrices: Record<string, THREE.Matrix4> = {
- // Z-up (Blender) -> Y-up (Three.js)
- 'z-up_to_y-up_standard': new THREE.Matrix4().makeRotationX(-Math.PI / 2),
- 'z-up_to_y-up_flipped': new THREE.Matrix4().makeRotationX(Math.PI / 2),
- 'z-up_to_y-up_180': new THREE.Matrix4().makeRotationX(Math.PI),
-
- // Y-up (Three.js) -> Z-up (Blender)
- 'y-up_to_z-up_standard': new THREE.Matrix4().makeRotationX(Math.PI / 2),
- 'y-up_to_z-up_flipped': new THREE.Matrix4().makeRotationX(-Math.PI / 2),
-
- // Z-up-forward-x -> Y-up
- 'z-up-forward-x_to_y-up_standard': new THREE.Matrix4()
- .makeRotationX(-Math.PI / 2)
- .multiply(new THREE.Matrix4().makeRotationZ(Math.PI / 2)),
- }
- const key = `${from}_to_${to}_${rotationOption}`
- const matrix = conversionMatrices[key]
- if (!matrix) {
- console.warn(`不支持的坐标系转换: ${from} -> ${to} (${rotationOption})`)
- return model
- }
- // 应用转换矩阵
- model.applyMatrix4(matrix)
- return model
- }
- /**
- * 自动检测并转换模型坐标系
- * @param model - Three.js 3D对象
- * @returns 转换后的模型
- */
- export function autoConvertModelCoordinates(model: THREE.Object3D): THREE.Object3D {
- // 计算模型的包围盒
- const box = new THREE.Box3().setFromObject(model)
- const size = box.getSize(new THREE.Vector3())
- const center = box.getCenter(new THREE.Vector3())
- console.log(`[坐标系转换] 模型尺寸: (${size.x.toFixed(2)}, ${size.y.toFixed(2)}, ${size.z.toFixed(2)})`)
- console.log(`[坐标系转换] 包围盒中心: (${center.x.toFixed(2)}, ${center.y.toFixed(2)}, ${center.z.toFixed(2)})`)
- // 判断坐标系:如果 Z 轴尺寸最大且 Y 轴较小,可能是 Z-up 坐标系
- const isZUp = size.z > size.y && size.z > size.x
-
- if (isZUp) {
- console.log(`[坐标系转换] 检测到 Z-up 坐标系,转换为 Y-up`)
- return convertCoordinateSystem(model, 'z-up', 'y-up')
- } else {
- console.log(`[坐标系转换] 检测到 Y-up 坐标系,无需转换`)
- return model
- }
- }
- /**
- * 创建坐标系参考轴
- * @param size - 轴的长度
- * @returns 坐标系参考轴对象
- */
- export function createCoordinateAxes(size: number = 10): THREE.Group {
- const group = new THREE.Group()
-
- // X轴 (红色)
- const xAxis = new THREE.ArrowHelper(
- new THREE.Vector3(1, 0, 0),
- new THREE.Vector3(0, 0, 0),
- size,
- 0xff0000,
- size * 0.2,
- size * 0.1
- )
-
- // Y轴 (绿色)
- const yAxis = new THREE.ArrowHelper(
- new THREE.Vector3(0, 1, 0),
- new THREE.Vector3(0, 0, 0),
- size,
- 0x00ff00,
- size * 0.2,
- size * 0.1
- )
-
- // Z轴 (蓝色)
- const zAxis = new THREE.ArrowHelper(
- new THREE.Vector3(0, 0, 1),
- new THREE.Vector3(0, 0, 0),
- size,
- 0x0000ff,
- size * 0.2,
- size * 0.1
- )
-
- group.add(xAxis)
- group.add(yAxis)
- group.add(zAxis)
-
- return group
- }
- /**
- * 坐标系转换配置接口
- */
- export interface CoordinateConversionConfig {
- sourceSystem: CoordinateSystem
- targetSystem?: CoordinateSystem
- autoDetect?: boolean
- showAxes?: boolean
- axesSize?: number
- }
- /**
- * 应用坐标系转换到模型组
- */
- export function applyCoordinateConversion(
- modelGroup: THREE.Group,
- config: CoordinateConversionConfig
- ): THREE.Group {
- const {
- sourceSystem,
- targetSystem = 'y-up',
- autoDetect = false,
- showAxes = false,
- axesSize = 10
- } = config
- let convertedModel: THREE.Object3D
- if (autoDetect) {
- convertedModel = autoConvertModelCoordinates(modelGroup)
- } else {
- convertedModel = convertCoordinateSystem(modelGroup, sourceSystem, targetSystem)
- }
- // 创建新的组来包含转换后的模型
- const resultGroup = new THREE.Group()
-
- if (convertedModel instanceof THREE.Group) {
- // 如果转换后还是组,直接添加所有子对象
- convertedModel.children.forEach(child => {
- resultGroup.add(child.clone())
- })
- } else {
- resultGroup.add(convertedModel)
- }
- // 可选:添加坐标系参考轴
- if (showAxes) {
- const axes = createCoordinateAxes(axesSize)
- resultGroup.add(axes)
- }
- return resultGroup
- }
|