ThingJS开发从入门到精通:构建三维物联网可视化应用的完整指南

发布于:2025-07-20 ⋅ 阅读:(16) ⋅ 点赞:(0)

第一部分:ThingJS基础入门

在这里插入图片描述

第一章 ThingJS概述与技术架构

1.1 ThingJS平台简介

ThingJS是优锘科技推出的面向物联网的三维可视化开发平台,基于WebGL技术构建,专注于解决物联网应用中的"最后一公里"可视化问题。该平台自2016年发布以来,已广泛应用于智慧城市、工业互联网、园区管理、电力能源等众多领域。

核心特点

  • 低代码开发:提供可视化编排工具和丰富的API,降低3D可视化开发门槛
  • 跨平台支持:基于Web标准,一次开发可运行于PC、移动端及大屏设备
  • 性能优化:采用层级细节(LOD)技术和智能加载机制,支持大规模场景渲染
  • 生态完善:拥有模型市场、插件系统和开发者社区支持
1.2 技术架构解析

整体架构

[应用层] ←→ [ThingJS API] ←→ [核心引擎] ←→ [渲染层]
                   ↑                ↑
               [扩展插件]       [资源管理系统]

核心组件

  1. 场景图系统(Scene Graph):基于树状结构管理所有3D对象
  2. 实体组件系统(ECS):通过组件化方式扩展对象功能
  3. 材质系统:支持PBR(物理渲染)和传统材质
  4. 动画系统:包含骨骼动画、变形动画和粒子系统
  5. 物理引擎:集成轻量级碰撞检测系统
1.3 开发环境配置

基础环境准备

# 推荐开发环境
Node.js 14+ (LTS版本)
Visual Studio Code 或 WebStorm
Chrome/Firefox最新版

# 安装ThingJS CLI工具
npm install -g @thingjs/cli

# 创建新项目
thingjs create my-first-project
cd my-first-project
npm install
npm run serve

项目目录结构

├── public/                # 静态资源
├── src/
│   ├── assets/            # 项目资源
│   ├── components/        # 自定义组件
│   ├── configs/           # 配置文件
│   ├── scenes/            # 场景脚本
│   ├── styles/            # 样式文件
│   ├── utils/             # 工具函数
│   └── main.js            # 应用入口
├── thingjs.config.js      # 构建配置
└── package.json

第二章 基础概念与核心API

2.1 核心对象模型

对象层次结构

App → Scene → Camera → Controller
       ↑
     Object3D
       ↑
   (Mesh, Light, Helper...)

关键类说明

  • THING.App:应用入口,管理应用生命周期
  • THING.Scene:场景容器,管理所有3D对象
  • THING.Camera:视图控制器,决定观察视角
  • THING.Object3D:所有3D对象的基类
2.2 场景创建与管理

基础场景创建

const app = new THING.App({
    background: '#000000',  // 背景色
    skyBox: 'SkyBox1',      // 天空盒
    env: 'env1'             // 环境光
});

// 创建地面
const ground = app.create({
    type: 'Ground',
    name: 'myGround',
    position: [0, 0, 0],
    style: {
        texture: 'gradient',
        size: [100, 100]
    }
});

// 加载园区场景
app.load('/scenes/building').then((scene) => {
    console.log('场景加载完成');
});

场景生命周期

app.on('load', function(ev) {
    // 场景加载完成
});

app.on('update', function(ev) {
    // 每帧更新
});

app.on('destroy', function(ev) {
    // 场景销毁
});
2.3 对象操作基础

创建与操作3D对象

// 创建立方体
const box = app.create({
    type: 'Box',
    name: 'myBox',
    position: [0, 5, 0],
    size: [2, 2, 2],
    style: {
        color: '#FF0000',
        opacity: 0.8
    }
});

// 对象变换
box.position = [10, 0, 5];  // 设置位置
box.scale = [1.5, 1.5, 1.5]; // 缩放
box.rotation = [0, 45, 0];  // 旋转(欧拉角)

// 动画移动
box.moveTo([15, 5, 10], {
    time: 2000,  // 毫秒
    easing: 'Quadratic.InOut'
});

对象查询

// 通过名称查询
const obj = app.query('myBox')[0];

// 通过类型查询
const lights = app.query(/Light/);

// 通过条件查询
const bigObjects = app.query({
    type: 'Mesh',
    condition: 'object.scale.x > 1.5'
});

第三章 基础开发实战

3.1 第一个ThingJS应用

完整示例:智慧园区监控

// 初始化应用
const app = new THING.App({
    background: '#F0F0F0',
    skyBox: 'SkyBox1'
});

// 加载园区场景
app.load('/scenes/smart-park').then((scene) => {
    // 创建监控摄像头
    const camera = app.create({
        type: 'Camera',
        name: 'surveillance-cam',
        position: [50, 20, 0],
        target: [0, 0, 0]
    });
    
    // 添加设备标签
    camera.addComponent({
        type: 'Tag',
        text: '监控点#01',
        style: {
            color: '#FFFFFF',
            backgroundColor: '#3366FF'
        }
    });
    
    // 点击事件
    camera.on('click', (ev) => {
        app.camera.flyTo({
            target: camera,
            time: 1000,
            complete: function() {
                showCameraFeed(camera);
            }
        });
    });
});

function showCameraFeed(camera) {
    // 显示监控画面逻辑
    const panel = new THING.widget.Panel({
        title: '实时监控',
        width: '300px',
        height: '200px'
    });
    
    panel.addString('摄像头ID', camera.name).captionStyle({
        color: '#333'
    });
    
    // 模拟视频流
    const video = document.createElement('video');
    video.src = '/assets/videos/sample.mp4';
    video.autoplay = true;
    panel.addDOM(video);
}
3.2 事件系统详解

事件类型

  • 鼠标事件:click, dblclick, mouseenter, mouseleave
  • 触摸事件:touchstart, touchmove, touchend
  • 对象生命周期:create, destroy, show, hide
  • 自定义事件:可任意定义和触发

事件绑定与解绑

// 绑定事件
obj.on('click', function(ev) {
    console.log('对象被点击', ev.object);
});

// 一次性事件
obj.once('click', function(ev) {
    console.log('只会触发一次');
});

// 事件解绑
const handler = function(ev) { /*...*/ };
obj.on('click', handler);
obj.off('click', handler);

// 触发自定义事件
obj.trigger('alarm', {
    level: 'high',
    message: '温度过高!'
});

事件冒泡与拦截

// 事件冒泡示例
parent.on('click', function(ev) {
    console.log('父对象收到事件', ev.target);
});

child.on('click', function(ev) {
    console.log('子对象事件');
    ev.stopPropagation(); // 阻止冒泡
});

// 事件拦截
app.on('click', function(ev) {
    if (shouldIgnore(ev)) {
        ev.preventDefault(); // 阻止默认行为
    }
});
3.3 基础动画实现

变换动画

// 移动动画
obj.moveTo([x, y, z], {
    time: 1000,       // 持续时间(ms)
    easing: 'Linear', // 缓动函数
    complete: function() {
        console.log('移动完成');
    }
});

// 旋转动画
obj.rotateTo([x, y, z], {
    time: 2000,
    easing: 'Elastic.Out'
});

// 缩放动画
obj.scaleTo([x, y, z], {
    time: 500
});

关键帧动画

// 创建动画剪辑
const clip = new THING.AnimationClip({
    name: 'moveAndRotate',
    duration: 3000,
    tracks: [
        {
            type: 'position',
            keys: [
                { time: 0, value: [0, 0, 0] },
                { time: 1000, value: [10, 0, 0] },
                { time: 3000, value: [10, 5, 10] }
            ]
        },
        {
            type: 'rotation',
            keys: [
                { time: 0, value: [0, 0, 0] },
                { time: 3000, value: [0, 360, 0] }
            ]
        }
    ]
});

// 播放动画
const mixer = new THING.AnimationMixer(obj);
const action = mixer.clipAction(clip);
action.play();

第二部分:ThingJS中级开发

第四章 场景设计与优化

4.1 复杂场景构建

分层加载策略

// 分步加载大型场景
async function loadLargeScene() {
    // 1. 先加载基础结构
    await app.load('/scenes/base-structure');
    
    // 2. 加载建筑外观
    await app.load('/scenes/buildings-exterior');
    
    // 3. 加载室内场景(按需)
    app.on('click', '.building', (ev) => {
        ev.object.load('/scenes/interior/' + ev.object.name);
    });
    
    // 4. 最后加载动态元素
    loadDynamicElements();
}

场景组织技巧

// 使用空对象作为容器
const floor1 = app.create({
    type: 'Object3D',
    name: 'floor1-container'
});

// 将相关对象添加到容器
const desk1 = createDesk();
const chair1 = createChair();
floor1.add(desk1);
floor1.add(chair1);

// 整体操作
floor1.position = [0, 3, 0]; // 移动整个楼层
4.2 性能优化策略

渲染性能优化

  1. LOD(层级细节)
app.create({
    type: 'LOD',
    levels: [
        { distance: 0, object: highDetailModel },
        { distance: 50, object: mediumDetailModel },
        { distance: 100, object: lowDetailModel }
    ]
});
  1. 视锥裁剪
// 在thingjs.config.js中配置
module.exports = {
    renderer: {
        frustumCulling: true, // 启用视锥裁剪
        maxRenderDistance: 500 // 最大渲染距离
    }
};

内存优化

// 对象池管理
const objectPool = {
    desks: [],
    init(count) {
        for (let i = 0; i < count; i++) {
            this.desks.push(createDesk());
            this.desks[i].visible = false;
        }
    },
    getDesk() {
        const desk = this.desks.find(d => !d.visible);
        if (desk) {
            desk.visible = true;
            return desk;
        }
        return createDesk();
    }
};

第五章 高级交互实现

5.1 复杂事件处理

手势识别

let touchStartTime;
let startPosition;

obj.on('touchstart', (ev) => {
    touchStartTime = Date.now();
    startPosition = obj.position.clone();
});

obj.on('touchmove', (ev) => {
    // 计算移动距离
    const delta = ev.deltaPosition;
    obj.position = [
        startPosition[0] + delta[0],
        startPosition[1],
        startPosition[2] + delta[1]
    ];
});

obj.on('touchend', (ev) => {
    // 判断快速滑动
    if (Date.now() - touchStartTime < 300) {
        const speed = ev.speed;
        // 添加惯性移动效果
        addInertiaMovement(speed);
    }
});

射线检测

app.on('click', (ev) => {
    const rayCaster = new THING.Raycaster();
    const ray = rayCaster.setFromCamera(ev.screenPosition, app.camera);
    
    const intersects = rayCaster.intersectObjects(scene.children);
    if (intersects.length > 0) {
        console.log('击中的对象:', intersects[0].object);
    }
});
5.2 UI系统集成

原生UI组件

// 创建控制面板
const panel = new THING.widget.Panel({
    title: '设备控制',
    width: '300px',
    height: 'auto',
    position: [20, 20]
});

// 添加控件
panel.addBoolean('开启照明', false).onChange((value) => {
    toggleLights(value);
});

panel.addSlider('温度调节', 22, 16, 30, 1).onChange((value) => {
    setTemperature(value);
});

// 自定义HTML内容
panel.addHTML('<div class="alert">警告区域</div>');

与外部UI框架集成

// Vue集成示例
const vueApp = new Vue({
    el: '#vue-ui-container',
    data: {
        deviceStatus: {}
    },
    methods: {
        handleControl(command) {
            // 调用ThingJS接口
            app.query(command.target).forEach(obj => {
                obj[command.method](...command.args);
            });
        }
    }
});

// ThingJS事件触发Vue更新
app.on('deviceUpdate', (ev) => {
    vueApp.deviceStatus = ev.data;
});

第六章 数据可视化

6.1 数据驱动场景

数据绑定示例

// 模拟设备数据
const devices = [
    { id: 'device1', type: 'sensor', position: [10, 2, 5], value: 25.6 },
    { id: 'device2', type: 'camera', position: [15, 3, -8], status: 'online' }
];

// 数据绑定到3D对象
function bindDataToObjects() {
    devices.forEach(device => {
        const obj = app.create({
            type: device.type === 'sensor' ? 'Sphere' : 'Camera',
            name: device.id,
            position: device.position,
            size: [1, 1, 1]
        });
        
        // 存储原始数据
        obj.userData = device;
        
        // 根据数据更新状态
        updateObjectByData(obj);
    });
}

// 数据更新处理
function onDataUpdate(newData) {
    const obj = app.query(newData.id)[0];
    if (obj) {
        Object.assign(obj.userData, newData);
        updateObjectByData(obj);
    }
}

function updateObjectByData(obj) {
    const data = obj.userData;
    if (data.type === 'sensor') {
        // 根据值改变颜色
        const color = data.value > 30 ? '#FF0000' : '#00FF00';
        obj.style.color = color;
        
        // 更新标签
        obj.getComponent('Tag').text = `${data.value}°C`;
    }
}
6.2 高级可视化技术

热力图实现

function createHeatmap(points, options = {}) {
    const { radius = 10, max = 100 } = options;
    const geometry = new THING.HeatmapGeometry({
        points: points.map(p => ({
            position: p.position,
            intensity: p.value / max
        })),
        radius
    });
    
    const material = new THING.HeatmapMaterial({
        gradient: {
            0.0: '#0000FF',
            0.5: '#00FF00',
            1.0: '#FF0000'
        }
    });
    
    return new THING.Mesh(geometry, material);
}

// 使用示例
const sensorData = [
    { position: [0, 0, 0], value: 30 },
    { position: [5, 0, 3], value: 45 },
    // 更多数据点...
];

const heatmap = createHeatmap(sensorData, { radius: 15 });
app.scene.add(heatmap);

动态路径可视化

class DynamicPath {
    constructor(points, options = {}) {
        this.options = {
            width: 0.5,
            color: '#00FFFF',
            dash: [1, 0.5],
            speed: 1,
            ...options
        };
        
        this.line = createLine(points);
        this.animateFlow();
    }
    
    createLine(points) {
        const geometry = new THING.BufferGeometry().setFromPoints(points);
        const material = new THING.LineDashedMaterial({
            color: this.options.color,
            linewidth: this.options.width,
            dashSize: this.options.dash[0],
            gapSize: this.options.dash[1]
        });
        
        return new THING.Line(geometry, material);
    }
    
    animateFlow() {
        let offset = 0;
        app.on('update', () => {
            offset += 0.01 * this.options.speed;
            this.line.material.dashOffset = -offset;
        });
    }
}

第三部分:ThingJS高级精通

第七章 自定义扩展开发

7.1 自定义组件开发

组件开发规范

// 温度传感器组件
THING.Component.register('TemperatureSensor', {
    // 组件属性
    properties: {
        warningThreshold: 30,
        criticalThreshold: 40,
        unit: '°C'
    },
    
    // 生命周期
    onAttach: function() {
        // 组件附加到对象时调用
        this.object.style.color = '#00FF00';
        this.label = this.object.addComponent('Tag', {
            text: this.getDisplayText()
        });
        
        // 定时更新
        this.timer = setInterval(() => this.updateReading(), 5000);
    },
    
    onDetach: function() {
        // 组件移除时清理
        clearInterval(this.timer);
        this.object.removeComponent(this.label);
    },
    
    // 自定义方法
    updateReading: function() {
        // 模拟数据更新
        const newValue = 25 + Math.random() * 20;
        this.object.userData.temperature = newValue;
        
        // 更新显示
        this.label.text = this.getDisplayText();
        
        // 触发事件
        if (newValue > this.warningThreshold) {
            this.object.trigger('temperatureWarning', {
                value: newValue,
                status: newValue > this.criticalThreshold ? 'critical' : 'warning'
            });
        }
    },
    
    getDisplayText: function() {
        return `${this.object.userData.temperature.toFixed(1)}${this.unit}`;
    }
});

// 使用组件
const sensor = app.create({ type: 'Sphere' });
sensor.addComponent('TemperatureSensor', {
    warningThreshold: 28,
    criticalThreshold: 35
});
7.2 着色器开发

自定义材质示例

// 创建自定义着色器材质
const customShader = {
    uniforms: {
        time: { value: 0 },
        mainColor: { value: new THING.Color(0x00ff00) },
        waveSpeed: { value: 1.0 }
    },
    
    vertexShader: `
        varying vec2 vUv;
        void main() {
            vUv = uv;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
    `,
    
    fragmentShader: `
        uniform float time;
        uniform vec3 mainColor;
        uniform float waveSpeed;
        varying vec2 vUv;
        
        void main() {
            float wave = sin(vUv.x * 10.0 + time * waveSpeed) * 0.5 + 0.5;
            vec3 color = mix(mainColor, vec3(1.0), wave * 0.3);
            gl_FragColor = vec4(color, 1.0);
        }
    `
};

// 使用自定义材质
const material = new THING.ShaderMaterial(customShader);
const mesh = new THING.Mesh(new THING.BoxGeometry(), material);

// 更新uniforms
app.on('update', () => {
    material.uniforms.time.value += 0.01;
});

第八章 项目架构与工程化

8.1 大型项目组织

模块化架构

src/
├── core/               # 核心模块
│   ├── app.js          # 应用初始化
│   ├── scene-manager.js # 场景管理
│   └── event-bus.js    # 全局事件总线
├── modules/            # 功能模块
│   ├── equipment/      # 设备管理
│   ├── monitoring/     # 监控系统
│   └── analytics/      # 分析模块
├── assets/             # 资源管理
│   ├── models/         # 3D模型
│   ├── textures/       # 纹理贴图
│   └── configs/        # 配置文件
└── utils/              # 工具函数

状态管理实现

// 基于事件总线的状态管理
class StateManager {
    constructor() {
        this.state = {
            devices: {},
            alarms: [],
            viewMode: 'default'
        };
        
        this.eventBus = new THING.EventEmitter();
    }
    
    setState(path, value) {
        const parts = path.split('.');
        let current = this.state;
        
        for (let i = 0; i < parts.length - 1; i++) {
            current = current[parts[i]];
        }
        
        current[parts[parts.length - 1]] = value;
        this.eventBus.emit('stateChange', { path, value });
    }
    
    subscribe(path, callback) {
        this.eventBus.on('stateChange', ({ path: changedPath, value }) => {
            if (changedPath.startsWith(path)) {
                callback(this.getState(path));
            }
        });
    }
    
    getState(path) {
        return path.split('.').reduce((obj, key) => obj[key], this.state);
    }
}

// 使用示例
const state = new StateManager();
state.setState('viewMode', 'expert');
state.subscribe('devices', (devices) => {
    updateDeviceVisualization(devices);
});
8.2 性能分析与调优

性能分析工具

class PerformanceMonitor {
    constructor() {
        this.stats = {
            fps: 0,
            renderTime: 0,
            objectCount: 0
        };
        
        this.frames = 0;
        this.lastTime = performance.now();
        
        app.on('update', this.update.bind(this));
    }
    
    update() {
        this.frames++;
        const now = performance.now();
        
        // 每秒计算一次FPS
        if (now >= this.lastTime + 1000) {
            this.stats.fps = Math.round(
                (this.frames * 1000) / (now - this.lastTime)
            );
            this.frames = 0;
            this.lastTime = now;
            
            // 收集其他指标
            this.stats.objectCount = app.scene.children.length;
            this.stats.renderTime = app.renderer.info.render.time;
            
            console.table(this.stats);
        }
    }
    
    startProfiling(name) {
        console.time(name);
    }
    
    endProfiling(name) {
        console.timeEnd(name);
    }
}

// 使用示例
const monitor = new PerformanceMonitor();
monitor.startProfiling('SceneLoad');
app.load('/scenes/large-scene').then(() => {
    monitor.endProfiling('SceneLoad');
});

第九章 实战项目:智慧园区综合管理系统

9.1 项目需求分析

核心功能需求

  1. 三维场景展示:完整呈现园区建筑、设施和设备的3D模型
  2. 设备监控:实时显示IoT设备状态和数据(温湿度、能耗等)
  3. 告警管理:可视化呈现设备告警及定位
  4. 人员管理:展示人员位置和移动轨迹
  5. 数据分析:多维度的数据统计和可视化

技术指标

  • 支持同时展示1000+设备对象
  • 数据更新延迟<1秒
  • 主流浏览器60FPS流畅运行
  • 场景加载时间<5秒(首次)
9.2 系统实现

架构设计

[前端]
  ├── ThingJS 3D引擎
  ├── Vue.js 管理后台
  └── ECharts 数据可视化

[后端]
  ├── Node.js API网关
  ├── Kafka 消息队列
  └── 时序数据库

核心实现代码

// 主应用入口
class SmartCampusApp {
    constructor() {
        this.app = new THING.App({
            background: '#F5F5F5',
            skyBox: 'SkyBox2'
        });
        
        this.initModules();
        this.setupEventHandlers();
    }
    
    initModules() {
        this.sceneManager = new SceneManager(this.app);
        this.deviceManager = new DeviceManager(this.app);
        this.alarmSystem = new AlarmSystem(this.app);
        this.dataAnalytics = new DataAnalytics(this.app);
    }
    
    setupEventHandlers() {
        // 设备选择事件
        this.app.on('click', '.device', (ev) => {
            this.deviceManager.showDevicePanel(ev.object);
        });
        
        // 告警处理
        this.alarmSystem.on('newAlarm', (alarm) => {
            this.sceneManager.highlightObject(alarm.deviceId);
            this.showAlarmNotification(alarm);
        });
    }
}

// 设备管理模块
class DeviceManager {
    constructor(app) {
        this.app = app;
        this.devices = new Map();
        
        // 从API加载设备数据
        this.loadDevices();
    }
    
    async loadDevices() {
        const response = await fetch('/api/devices');
        const devices = await response.json();
        
        devices.forEach(device => {
            const obj = this.createDeviceObject(device);
            this.devices.set(device.id, obj);
        });
    }
    
    createDeviceObject(device) {
        const obj = this.app.create({
            type: this.getDeviceType(device),
            name: device.id,
            position: device.position,
            userData: device
        });
        
        // 添加状态指示器
        obj.addComponent('StatusIndicator', {
            getStatus: () => device.status
        });
        
        return obj;
    }
}

第四部分:扩展与未来

第十章 ThingJS高级主题

10.1 跨平台开发

移动端适配策略

// 响应式设计
function setupResponsive() {
    // 根据屏幕尺寸调整UI
    const updateUI = () => {
        const isMobile = window.innerWidth < 768;
        
        // 调整相机位置
        app.camera.position = isMobile 
            ? [0, 50, 100] 
            : [0, 30, 70];
            
        // 调整控制方式
        app.camera.controller.type = isMobile
            ? 'Orbit'
            : 'FirstPerson';
            
        // 调整UI尺寸
        panel.style.fontSize = isMobile ? '14px' : '16px';
    };
    
    window.addEventListener('resize', updateUI);
    updateUI();
}

// 触摸优化
function optimizeForTouch() {
    // 增大点击区域
    app.query('.device').forEach(obj => {
        obj.userData.clickableArea = 1.5;
    });
    
    // 简化交互
    app.camera.controller.touchZoomSensitivity = 0.5;
}
10.2 与GIS系统集成

地理坐标转换

class GISConverter {
    constructor(origin, scale = 1) {
        this.origin = origin;  // 地理坐标系原点
        this.scale = scale;    // 单位换算比例
    }
    
    // WGS84转场景坐标
    project(lng, lat) {
        // 简化的墨卡托投影
        const x = (lng - this.origin.lng) * this.scale;
        const y = (lat - this.origin.lat) * this.scale;
        return [x, 0, -y];  // Z轴取反
    }
    
    // 场景坐标转WGS84
    unproject(x, z) {
        const lng = x / this.scale + this.origin.lng;
        const lat = -z / this.scale + this.origin.lat;
        return { lng, lat };
    }
}

// 使用示例
const converter = new GISConverter(
    { lng: 116.404, lat: 39.915 },  // 天安门坐标
    1000  // 1度=1000单位
);

const scenePos = converter.project(116.408, 39.916);
const obj = app.create({
    type: 'Flag',
    position: scenePos
});

第十一章 最佳实践与常见问题

11.1 性能优化清单

关键优化策略

  1. 资源优化

    • 使用压缩纹理(.ktx2格式)
    • 模型面数控制在5万面以内
    • 使用Draco压缩的GLB模型
  2. 渲染优化

    // thingjs.config.js
    module.exports = {
        renderer: {
            antialias: true,
            shadowMap: {
                enabled: true,
                type: 'PCFSoft' // 柔和阴影
            },
            precision: 'mediump' // 移动端使用
        }
    };
    
  3. 内存管理

    // 释放不再使用的资源
    function cleanup() {
        // 销毁对象
        obj.destroy();
        
        // 释放纹理
        texture.dispose();
        
        // 清理几何体
        geometry.dispose();
    }
    
11.2 常见问题解决方案

典型问题与解决

  1. 场景加载慢

    • 使用THING.LoadingManager显示进度
    • 实现分块加载
    • 预加载关键资源
  2. 内存泄漏

    // 错误示例(会导致内存泄漏)
    app.on('update', function() {
        // 频繁创建对象
        const temp = new THING.Object3D();
    });
    
    // 正确做法
    const reusableObjects = [];
    function getTempObject() {
        return reusableObjects.pop() || new THING.Object3D();
    }
    
  3. 点击事件不触发

    • 检查对象visiblepickable属性
    • 确认没有其他对象遮挡
    • 检查事件冒泡是否被阻止

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到