github地址:https://github.com/xjf7711/decoration
装饰应用(Decoration)是一个基于TypeScript和Three.js构建的交互式3D全景室内装饰查看器,采用TypeDom框架作为UI基础,实现了用户与3D场景的无缝交互。该应用通过组件化架构设计,将复杂的3D渲染与直观的用户界面有机结合,提供了浏览不同室内设计风格、探索房间位置、导航全景视图等功能。其核心架构围绕AppRoot、House View、Three.js模型和UI组件四大模块展开,通过事件驱动和状态管理实现各模块间的高效协同。
装饰应用采用模块化设计,各组件职责明确且相互协作。AppRoot作为应用的入口点和根组件,继承自TypeDom的TypeRoot类,负责初始化路由系统、挂载到DOM元素并启动整个应用。在代码实现中,AppRoot会创建RouterView实例并添加到子组件中,通过mount方法将应用挂载到指定的DOM元素上。例如:
export class AppRoot extends TypeRoot {
constructor(option?: TypeProps) {
super();
this routerView = new RouterView();
this.addChild(this routerView);
this mount(option?.el || document.body);
}
}
House View组件是应用的核心控制器,承担着管理3D模型、处理用户交互和协调UI组件与3D渲染系统之间的通信职责。它通过事件监听接收来自菜单、工具栏等UI组件的用户选择,并更新内部状态以驱动3D场景的变化。在TypeDom框架中,House View可能作为路由组件被加载,如HomeView,通过属性传递和事件监听机制与AppRoot及其他组件交互。
Three.js模型组件负责具体的3D渲染工作,包括场景、相机、渲染器的创建与管理,以及全景纹理加载、模型动画控制和音频播放等。UI组件库则提供用户界面元素,如菜单、工具栏、导航按钮和数字面板等,通过TypeDom的框架实现与3D场景的交互。
这种组件划分遵循了关注点分离的设计原则,使各模块职责清晰,便于维护和扩展。AppRoot负责整体应用的初始化与路由管理,House View作为核心控制器协调各模块工作,Three.js处理3D渲染逻辑,UI组件库则专注于用户界面的呈现与交互。
装饰应用利用Three.js强大的3D渲染能力,实现了全景室内装饰的沉浸式体验。在全景纹理加载方面,应用采用了两种主流技术:球面全景图(Equirectangular)和立方体贴图(CubeTexture)。
对于球面全景图,应用使用SphereGeometry创建一个球体,并通过MeshBasicMaterial将全景纹理映射到球体表面。为实现用户在球体内部观察全景效果,应用会将球体几何体反转:
const geometry = new THREE.SphereGeometry(500, 60, 40);
geometry.scale(-1, 1, 1); // 反转球体以正确显示全景图
const material = new THREE MeshBasicMaterial({ map: texture });
const sphere = new THREE Mesh(geometry, material);
scene.add(sphere);
对于立方体贴图全景图,应用使用CubeTextureLoader加载六个面的纹理图片,并将其设置为场景的背景:
const textureLoader = new THREE.CubeTextureLoader();
const textures = textureLoader.load([
'posx.jpg', 'negx.jpg',
'posy.jpg', 'negy.jpg',
'posz.jpg', 'negz.jpg'
]);
scene.background = textures;
在模型加载与管理方面,应用根据用户选择的室内设计风格和房间位置,动态加载对应的3D模型。这通常通过GLTFLoader或OBJLoader实现,并采用事件驱动的方式处理模型加载过程:
const loader = new GLTFLoader();
loader.load(
'/models/chinese_living_room.glb',
(gltf) => {
scene.add(gltf.scene);
// 处理模型加载完成后的初始化
},
(xhr) => {
// 更新加载进度
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
(error) => {
// 处理加载错误
console.error('Error loading model:', error);
}
);
动画循环是Three.js应用的核心,装饰应用通过requestAnimationFrame实现每秒60帧的流畅渲染:
function animate() {
requestAnimationFrame(animate);
// 更新场景状态(如旋转、物体位置等)
controls.update();
renderer.render(scene, camera);
}
animate();
此外,应用还可能使用OrbitControls或类似库提供相机的交互式控制,使用户能够通过鼠标或触摸屏旋转、缩放和移动视角,探索全景场景中的不同区域。
装饰应用将TypeDom框架作为UI基础,与Three.js的3D渲染能力相结合,实现了前后端逻辑的高效协同。TypeDom是一个基于Web Components的UI框架,支持通过自定义元素和属性/事件系统构建组件。
在UI组件与Three.js渲染器的集成方面,应用可能通过以下方式实现:
首先,创建一个专门用于容纳Three.js渲染器的TypeDom组件:
import { TypeDiv } from '@type-dom/framework';
export class ThreeCanvas extends TypeDiv {
private renderer: THREE.WebGLRenderer;
private scene: THREE.Scene;
private camera: THREE.PerspectiveCamera;
constructor() {
super();
// 初始化Three.js场景、相机和渲染器
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
this.scene.position.z = 5;
this.scene = new THREE.Scene();
this.renderer = new THREE.WebGLRenderer();
this.renderer.setSize(window.innerWidth, window.innerHeight);
// 将Three.js渲染器的domElement添加到TypeDom组件中
this.appendChild(this.renderer.domElement);
}
// 更新渲染的方法
update() {
// 更新场景状态
// ...
this.renderer.render(this.scene, this.camera);
}
}
其次,UI组件通过属性绑定和事件监听与Three.js模型交互。例如,菜单组件可能通过设置属性来改变当前选择的室内风格或房间位置:
import { TypeButton } from '@type-dom/ui';
export class StyleMenu extends TypeButton {
static style: string;
constructor(option?: TypeProps) {
super(option);
this.addEventListener('click', () => {
// 触发风格选择事件
this.dispatchEvent(new CustomEvent('styleSelected', { detail: { style: 'chinese' } }));
});
}
}
House View组件则监听这些事件并更新Three.js场景:
import { HouseView } from './house-view';
export class AppRoot extends TypeRoot {
constructor(option?: TypeProps) {
super(option);
// 创建UI组件
const styleMenu = new StyleMenu();
this.appendChild(styleMenu);
// 创建Three.js组件
const threeCanvas = new ThreeCanvas();
this.appendChild(threeCanvas);
// 监听UI组件事件
styleMenu.addEventListener('styleSelected', (event) => {
const style = event.detail.style;
// 更新Three.js场景
threeCanvas.updateStyle(style);
});
}
}
这种集成方式充分利用了TypeDom的组件化特性和Three.js的3D渲染能力,使UI交互能够直接驱动3D场景的变化,同时保持代码结构的清晰和可维护性。
装饰应用的数据流和控制流设计遵循事件驱动架构,确保用户交互能够高效地驱动系统状态变化。整个应用的控制流从AppRoot开始,向下传递到各个UI组件和Three.js渲染组件,再通过事件监听机制实现双向通信。
用户交互流程如下:
这种事件驱动架构使应用能够灵活响应用户操作,同时避免了直接操作DOM带来的性能问题。通过RxJS等响应式编程库,应用可以进一步优化事件处理逻辑,实现异步操作的高效管理。
数据流方面,应用采用分层设计:
这种分层设计使数据能够单向流动,确保系统状态的一致性和可预测性。同时,通过事件机制实现层间的通信,保持了各模块的独立性和灵活性。
装饰应用在实现过程中采用了多种优化策略,以确保3D渲染的流畅性和用户体验的流畅性。在模型加载方面,应用可能使用GLTFLoader或类似工具加载高效的3D模型格式,并采用DRACOLoader等压缩工具减少模型文件大小,提高加载速度。
对于大型模型,应用可能采用分块加载或LOD(细节层次)技术,根据用户视角动态调整模型细节级别,优化渲染性能。例如:
// 使用LOD技术优化渲染性能
const lod0 = new THREE Mesh GEOMETRY, MATERIAL);
lod0 scale set(1, 1, 1);
const lod1 = new THREE Mesh GEOMETRY, MATERIAL);
lod1 scale set(0.5, 0.5, 0.5);
const lod2 = new THREE Mesh GEOMETRY, MATERIAL);
lod2 scale set(0.25, 0.25, 0.25);
const lod = new THREE LOD();
lod addLevel(lod0, 0); // 最近距离显示最细节级别
lod addLevel(lod1, 100); // 中等距离显示中等细节级别
lod addLevel(lod2, 200); // 远距离显示低细节级别
scene add(lod);
在资源管理方面,应用可能使用Three.js的LoadingManager跟踪加载进度,并提供用户反馈:
const loadingManager = new THREE.LoadingManager();
loadingManager.onProgress = (item, loaded, total) => {
console.log(`加载中... ${loaded} / ${total}`);
};
const textureLoader = new THREE TextureLoader(loadingManager);
const materialLoader = new THREE MaterialLoader(loadingManager);
对于音频播放,应用可能使用Three.js的Audio库或Web Audio API,通过House View组件控制音频的播放、暂停和音量调整:
import { Audio, AudioLoader } from 'three';
export class HouseView {
private audio: Audio;
private audioLoader: AudioLoader;
constructor() {
this(audioLoader = new AudioLoader();
this loadAudio();
}
private loadAudio() {
this.audioLoader.load('/audio背景音乐.mp3', (buffer) => {
this.audio = new Audio(buffer);
scene.add(this.audio);
});
}
// 控制音频播放的方法
toggleAudio() {
this.audio.enabled ? this.audio.close() : this.audio.start();
}
adjustVolume(volume: number) {
this.audio.volume = volume;
}
}
在性能优化方面,应用可能采用以下策略:
这些优化策略确保了应用在不同设备和浏览器上的良好表现,为用户提供流畅的3D全景室内装饰体验。
装饰应用选择了TypeScript作为类型安全的编程语言,Three.js作为3D渲染库,@type-dom/framework作为组件化UI框架,以及RxJS作为响应式编程库。这种技术栈组合提供了强大的类型检查能力、高效的3D渲染性能和灵活的UI组件系统。
TypeScript的选择使应用能够更好地处理复杂的3D渲染逻辑和UI交互,减少运行时错误,提高代码质量和可维护性。Three.js提供了丰富的3D渲染功能,包括场景构建、相机控制、模型加载和动画循环等。@type-dom/framework框架则简化了UI组件的开发和管理,提供了声明式编程范式和组件生命周期管理。
项目结构方面,应用采用清晰的目录划分:
这种结构使各模块职责清晰,便于开发和维护。应用的初始化流程从DOMContentLoaded事件开始,在main.ts中实例化AppRoot类并挂载到DOM元素,然后创建House View组件和UI组件,最后初始化Three.js场景和启动动画循环。
开发工作流程方面,应用提供了多个npm脚本:
这些脚本简化了开发、测试和部署流程,提高了开发效率。
装饰应用通过精心设计的架构,实现了TypeDom框架与Three.js的高效协同。AppRoot作为应用的入口点,负责整体应用的初始化与路由管理;House View作为核心控制器,协调UI组件与3D渲染系统之间的交互;Three.js模型组件负责具体的3D渲染工作;UI组件库则专注于用户界面的呈现与交互。
这种协同设计使应用能够灵活响应用户操作,同时保持代码结构的清晰和可维护性。例如,当用户选择不同的室内设计风格时,菜单组件会触发自定义事件,House View组件监听到事件后,更新内部状态并调用Three.js模型组件加载新的3D模型。Three.js模型组件加载完成后,会更新场景状态并通过动画循环渲染到用户界面中。
未来扩展方向可能包括:
这些扩展方向将进一步增强应用的功能和用户体验,使其成为更全面的室内装饰设计工具。
该应用通过精心设计的架构,成功地将TypeDom框架的UI组件系统与Three.js的3D渲染能力相结合,实现了一个交互式3D全景室内装饰查看器。AppRoot作为应用的入口点,负责整体应用的初始化与路由管理;House View作为核心控制器,协调UI组件与3D渲染系统之间的交互;Three.js模型组件负责具体的3D渲染工作;UI组件库则专注于用户界面的呈现与交互。
这种架构设计提供了清晰的组件划分和明确的职责分工,使应用能够灵活响应用户操作,同时保持代码结构的清晰和可维护性。事件驱动的交互机制确保了UI组件与3D渲染系统之间的高效通信,而RxJS等响应式编程库则进一步优化了异步操作的管理。
装饰应用的实现为类似的3D全景应用开发提供了有益的参考。它展示了如何将现代UI框架与3D渲染库相结合,创造出既美观又功能强大的应用。同时,它也强调了组件化设计和关注点分离的重要性,这些原则对于构建复杂的应用系统至关重要。
对于未来的3D应用开发,装饰应用的架构设计提供了以下启示:
这些启示不仅适用于3D全景室内装饰应用,也适用于更广泛的Web 3D应用开发领域,为构建高效、灵活和可维护的3D应用提供了有益的指导。