JSAPIThree 渲染系统学习笔记:让场景动起来

作为一个刚开始学习 mapvthree 的小白,今天要学习渲染系统了!听说这个系统可以控制场景的渲染方式,还能开启动画循环、配置渲染特效等!想想就激动!

第一次听说渲染系统

今天在文档里看到了 engine.rendering 这个词,一开始我还以为是用来画图的,结果查了一下才知道,原来这是用来控制场景渲染的模块!

文档说渲染系统可以:

  • 控制动画循环
  • 配置渲染特效(如 Bloom、抗锯齿等)
  • 监听渲染事件
  • 监控渲染性能
  • 控制渲染质量

我的理解:简单说就是控制"怎么渲染场景",比如要不要每帧都渲染、用什么特效、怎么优化性能等!

第一步:发现引擎的渲染属性

作为一个初学者,我习惯先看看引擎有哪些属性。文档说 engine.rendering 就是渲染管理器!

我的发现:原来引擎创建后,就自动有了一个渲染管理器对象!不需要手动创建,直接用就行!

js 复制代码
import * as mapvthree from '@baidumap/mapv-three';

const container = document.getElementById('container');
const engine = new mapvthree.Engine(container);

// 渲染管理器已经自动创建了!
console.log(engine.rendering); // 可以访问渲染管理器

我的理解engine.rendering 就是渲染系统的入口,所有渲染相关的操作都通过它来完成。

第二步:开启循环渲染

文档说可以通过 engine.rendering.enableAnimationLoop 来开启循环渲染。我试了试:

js 复制代码
// 开启循环渲染
engine.rendering.enableAnimationLoop = true;

我的疑问:什么是循环渲染?为什么要开启?

看了文档才知道,默认情况下,引擎只在需要时渲染(比如拖动地图时)。开启循环渲染后,引擎会每帧都渲染,适合有动画的场景。

我的尝试:我写了个简单的测试:

js 复制代码
import * as mapvthree from '@baidumap/mapv-three';

const container = document.getElementById('container');

const engine = new mapvthree.Engine(container, {
    map: {
        center: [116.404, 39.915],
        range: 1000,
    },
    rendering: {
        enableAnimationLoop: true, // 开启循环渲染
    },
});

我的发现:开启后,如果有动画效果(比如飞线、粒子等),会持续播放!

我的理解

  • 默认关闭:只在需要时渲染,节省性能
  • 开启后:每帧都渲染,适合有动画的场景

我的注意:如果场景没有动画,建议不要开启,可以节省性能!

第三步:设置帧率

看到循环渲染后,我开始好奇:能不能控制渲染的帧率?

文档说可以通过 engine.rendering.animationLoopFrameTime 来设置帧时间间隔!

js 复制代码
// 设置帧时间间隔为 16 毫秒(约 60 FPS)
engine.rendering.animationLoopFrameTime = 16;

我的理解animationLoopFrameTime 是每帧之间的时间间隔(毫秒),默认是 16 毫秒,约等于 60 FPS。

我的尝试

js 复制代码
// 60 FPS(默认)
engine.rendering.animationLoopFrameTime = 16;

// 30 FPS
engine.rendering.animationLoopFrameTime = 33;

// 120 FPS(更快,但更耗性能)
engine.rendering.animationLoopFrameTime = 8;

我的发现

  • 16:约 60 FPS,流畅
  • 33:约 30 FPS,稍慢但省性能
  • 8:约 120 FPS,很快但耗性能

我的想法:如果做性能优化,可以降低帧率来节省性能!

第四步:监听渲染事件

看到循环渲染后,我想:能不能在渲染时执行一些操作?

文档说可以用 engine.rendering.addPrepareRenderListener() 来监听渲染事件!

js 复制代码
engine.rendering.addPrepareRenderListener((engine, renderState) => {
    // 每帧渲染前都会执行这里的代码
    console.log('正在渲染...');
});

我的理解addPrepareRenderListener() 会在每帧渲染前调用,可以在这里执行一些操作。

我的尝试

js 复制代码
// 监听渲染事件
engine.rendering.addPrepareRenderListener((engine, renderState) => {
    // 获取当前视野距离
    const range = engine.map.getRange();
    
    // 根据视野距离控制模型的显示隐藏
    if (range > 1000) {
        // 视野太远,隐藏模型
        mesh.visible = false;
    } else {
        // 视野较近,显示模型
        mesh.visible = true;
    }
});

我的发现:可以在渲染时根据场景状态动态调整物体!

我的想法:如果做性能优化,可以用这个方法来根据视野距离控制模型的显示!

检查视野是否变化

文档说可以用 renderState.viewChanged 来判断视野是否变化!

js 复制代码
engine.rendering.addPrepareRenderListener((engine, renderState) => {
    if (renderState.viewChanged) {
        // 只有视野变化时才执行
        console.log('视野变化了!');
    }
});

我的理解viewChanged 可以判断视野是否变化,避免不必要的操作。

我的发现 :配合 viewChanged 使用,可以减少无效的回调调用,提升性能!

我的建议 :使用 addPrepareRenderListener 时,建议配合 viewChanged 检查,避免无效回调!

第五步:了解渲染特性

看到渲染监听后,我开始好奇:什么是渲染特性?

文档说可以通过 engine.rendering.features 来配置渲染特性,比如抗锯齿、Bloom 等!

开启抗锯齿

js 复制代码
// 开启抗锯齿
engine.rendering.features.antialias.enabled = true;
engine.rendering.features.antialias.method = 'smaa';

我的理解:抗锯齿可以让画面更平滑,减少锯齿感。

我的发现:默认是开启的,所以一般不需要手动设置。

开启 Bloom 泛光

js 复制代码
// 开启 Bloom 泛光
engine.rendering.features.bloom.enabled = true;
engine.rendering.features.bloom.strength = 0.1;
engine.rendering.features.bloom.threshold = 1;
engine.rendering.features.bloom.radius = 0;

我的理解:Bloom 可以让亮的地方更亮,产生泛光效果。

我的发现:这个功能我在之前的 Bloom 学习笔记里学过,这里可以统一配置!

第六步:设置像素比

看到渲染特性后,我想:能不能控制渲染的分辨率?

文档说可以通过 engine.rendering.pixelRatio 来设置设备像素比!

js 复制代码
// 设置像素比
engine.rendering.pixelRatio = 1.0;

我的理解pixelRatio 控制渲染的分辨率,默认是 window.devicePixelRatio

我的尝试

js 复制代码
// 正常分辨率(默认)
engine.rendering.pixelRatio = window.devicePixelRatio;

// 降低分辨率(节省性能)
engine.rendering.pixelRatio = 1.0;

// 提高分辨率(更清晰,但更耗性能)
engine.rendering.pixelRatio = 2.0;

我的发现

  • 1.0:标准分辨率,性能好
  • 2.0:高分辨率,更清晰但耗性能
  • window.devicePixelRatio:根据设备自动调整(默认)

我的想法:如果做性能优化,可以降低像素比来提升性能!

第七步:使用高质量缓冲区

看到像素比后,我开始好奇:什么是高质量缓冲区?

文档说可以通过 engine.rendering.useHighPrecisionBuffer 来开启高质量缓冲区!

js 复制代码
// 开启高质量缓冲区
engine.rendering.useHighPrecisionBuffer = true;

我的理解:高质量缓冲区可以提升画面质量,但会增加性能开销。

我的发现

  • 默认是 false,使用低质量缓冲区
  • 开启后使用高质量缓冲区,画面更清晰
  • 某些渲染特性(如 Bloom、反射)会自动开启

我的尝试

js 复制代码
// 开启高质量缓冲区
engine.rendering.useHighPrecisionBuffer = true;

我的发现:开启后,画面质量确实提升了,但是性能也下降了。

我的建议:只有在需要高质量画面或使用高级渲染特性时才开启!

第八步:使用调试模式

看到高质量缓冲区后,我想:有没有调试模式?

文档说可以用 engine.rendering.debugMode 来开启调试模式!

js 复制代码
// 开启调试模式
engine.rendering.debugMode = 1; // DEBUG_MODE_MESH

我的理解:调试模式可以显示渲染的详细信息,方便调试。

我的发现

  • 0:无调试模式(默认)
  • 1:网格调试模式
  • 2:材质调试模式
  • 3:物体调试模式

我的尝试

js 复制代码
// 开启网格调试模式
engine.rendering.debugMode = 1;

我的发现:开启后,可以看到网格的详细信息,方便调试!

我的注意:调试模式主要用于开发,生产环境建议关闭!

第九步:冻结更新

看到调试模式后,我想:能不能暂停渲染更新?

文档说可以用 engine.rendering.freezeUpdate 来冻结更新!

js 复制代码
// 冻结更新
engine.rendering.freezeUpdate = true;

// 恢复更新
engine.rendering.freezeUpdate = false;

我的理解:冻结更新后,场景不会更新,但可以继续交互。

我的尝试

js 复制代码
// 冻结更新
engine.rendering.freezeUpdate = true;

// 做一些操作...

// 恢复更新
engine.rendering.freezeUpdate = false;

我的发现:冻结后,场景会停止更新,适合做批量操作!

我的想法:如果做批量更新,可以先冻结,更新完再恢复,可以提升性能!

第十步:获取渲染对象

看到这么多属性后,我想:能不能直接访问底层的渲染对象?

文档说可以通过 engine.rendering.rendererengine.rendering.sceneengine.rendering.camera 来访问底层对象!

js 复制代码
// 获取渲染器
const renderer = engine.rendering.renderer;

// 获取场景
const scene = engine.rendering.scene;

// 获取相机
const camera = engine.rendering.camera;

我的理解:这些是 Three.js 的底层对象,可以直接操作。

我的发现:可以直接访问 Three.js 对象,可以做更底层的操作!

我的注意:直接操作底层对象需要了解 Three.js,建议谨慎使用!

获取渲染分辨率

文档说可以用 engine.rendering.resolution 来获取渲染分辨率!

js 复制代码
// 获取渲染分辨率
const resolution = engine.rendering.resolution;
console.log(resolution); // 分辨率信息

我的发现:可以获取当前渲染的分辨率,方便做适配!

获取动画管理器

文档说可以用 engine.rendering.animation 来获取动画管理器!

js 复制代码
// 获取动画管理器
const animation = engine.rendering.animation;

我的理解:动画管理器可以用来控制场景中的动画效果。

我的发现:可以通过动画管理器来统一管理场景中的动画!

获取标签实例

文档说可以用 engine.rendering.label 来获取标签实例!

js 复制代码
// 获取标签实例
const label = engine.rendering.label;

我的理解:标签实例可以用来管理场景中的标签。

我的发现:可以通过标签实例来统一管理场景中的标签!

获取拾取器实例

文档说可以用 engine.rendering.picking 来获取拾取器实例!

js 复制代码
// 获取拾取器实例
const picking = engine.rendering.picking;

我的理解:拾取器可以用来检测鼠标点击的对象。

我的发现:可以通过拾取器来实现点击交互功能!

获取天气实例

文档说可以用 engine.rendering.weather 来获取天气实例!

js 复制代码
// 获取天气实例
const weather = engine.rendering.weather;

我的理解:如果场景中有天气效果,可以通过这个属性访问。

我的发现:可以获取天气实例,然后控制天气效果!

获取天空实例

文档说可以用 engine.rendering.sky 来获取天空实例!

js 复制代码
// 获取天空实例
const sky = engine.rendering.sky;

我的理解:如果场景中有天空,可以通过这个属性访问。

我的发现:可以获取天空实例,然后控制天空效果!

第十一步:获取渲染状态

看到底层对象后,我想:能不能获取渲染状态?

文档说可以用 engine.rendering.renderState 来获取渲染状态!

js 复制代码
// 获取渲染状态
const renderState = engine.rendering.renderState;

// 检查视野是否变化
if (renderState.viewChanged) {
    console.log('视野变化了!');
}

我的理解renderState 保存了渲染状态信息,比如视野变化、相机位置等。

我的发现 :可以在渲染监听中使用 renderState 来获取状态信息!

第十二步:自动偏移相机和场景

看到渲染状态后,我想:什么是自动偏移?

文档说可以通过 engine.rendering.autoOffsetRelativeCenter 来设置自动偏移!

js 复制代码
// 开启自动偏移
engine.rendering.autoOffsetRelativeCenter = true;

我的理解:自动偏移可以让相机和场景自动偏移,使 worldMatrix 偏移量较小,提升精度。

我的发现:开启后,可以提升坐标精度,适合大范围场景!

我的注意:这个功能主要用于大范围场景,一般场景不需要开启!

第十三步:保留绘图缓冲区

看到自动偏移后,我想:什么是保留绘图缓冲区?

文档说可以通过 contextParameters.preserveDrawingBuffer 来设置保留绘图缓冲区!

js 复制代码
const engine = new mapvthree.Engine(container, {
    rendering: {
        contextParameters: {
            preserveDrawingBuffer: true, // 开启保留绘图缓冲区
        },
    },
});

我的理解:保留绘图缓冲区可以让截图功能正常工作。

我的发现:如果要做截图功能,需要开启这个选项!

我的尝试

js 复制代码
const engine = new mapvthree.Engine(container, {
    rendering: {
        contextParameters: {
            preserveDrawingBuffer: true, // 开启截图功能
        },
    },
});

// 截图
const dataURL = engine.rendering.renderer.domElement.toDataURL();

我的发现:开启后,可以正常截图了!

我的注意:开启后会稍微影响性能,只在需要截图时开启!

第十四步:初始化时配置渲染

看到这么多属性后,我想:能不能在创建引擎时就配置渲染?

文档说可以在引擎初始化时通过 rendering 配置项来设置渲染参数!

js 复制代码
const engine = new mapvthree.Engine(container, {
    map: {
        center: [116.404, 39.915],
        range: 1000,
    },
    rendering: {
        enableAnimationLoop: true,
        animationLoopFrameTime: 16,
        pixelRatio: 1.0,
        features: {
            antialias: {
                enabled: true,
                method: 'smaa',
            },
            bloom: {
                enabled: true,
                strength: 0.1,
                threshold: 1,
                radius: 0,
            },
        },
    },
});

我的发现:可以在初始化时一次性配置所有渲染参数,更方便!

我的理解

  • enableAnimationLoop:是否开启循环渲染
  • animationLoopFrameTime:帧时间间隔
  • pixelRatio:像素比
  • features:渲染特性配置

我的尝试

js 复制代码
const engine = new mapvthree.Engine(container, {
    map: {
        center: [116.404, 39.915],
        range: 1000,
    },
    rendering: {
        enableAnimationLoop: true,
        animationLoopFrameTime: 16,
        features: {
            bloom: {
                enabled: true,
            },
        },
    },
});

我的发现:初始化时就配置好了,代码更简洁!

第十五步:实际应用场景

学到这里,我开始想:渲染系统能用在什么地方呢?

场景 1:动画场景

如果场景中有动画效果(如飞线、粒子等),需要开启循环渲染:

js 复制代码
engine.rendering.enableAnimationLoop = true;

我的想法:这样动画才能持续播放!

场景 2:性能优化

如果场景性能不好,可以优化渲染设置:

js 复制代码
// 降低帧率
engine.rendering.animationLoopFrameTime = 33;

// 降低像素比
engine.rendering.pixelRatio = 1.0;

// 关闭不必要的特效
engine.rendering.features.bloom.enabled = false;

我的想法:这样可以提升性能,让场景更流畅!

场景 3:根据视野控制显示

如果场景中有很多模型,可以根据视野距离控制显示:

js 复制代码
engine.rendering.addPrepareRenderListener((engine, renderState) => {
    if (renderState.viewChanged) {
        const range = engine.map.getRange();
        
        // 根据视野距离控制模型显示
        models.forEach(model => {
            model.visible = range < 5000;
        });
    }
});

我的想法:这样可以根据视野距离动态控制模型,提升性能!

第十六步:做一个完整的示例

我想写一个完整的示例,把学到的都用上:

js 复制代码
import * as mapvthree from '@baidumap/mapv-three';
import {Mesh, BoxGeometry, MeshStandardMaterial, Color} from 'three';

const container = document.getElementById('container');

const engine = new mapvthree.Engine(container, {
    map: {
        center: [116.404, 39.915],
        range: 1000,
        pitch: 60,
    },
    rendering: {
        enableAnimationLoop: true,
        animationLoopFrameTime: 16,
        pixelRatio: 1.0,
        features: {
            bloom: {
                enabled: true,
                strength: 0.1,
            },
        },
    },
});

// 创建一个模型
const geometry = new BoxGeometry(50, 50, 50);
const material = new MeshStandardMaterial({
    color: new Color(2, 2, 0),
});
const mesh = new Mesh(geometry, material);
engine.add(mesh);

const position = engine.map.projectArrayCoordinate([116.404, 39.915]);
mesh.position.set(position[0], position[1], 0);

// 监听视野变化,控制模型显示
engine.rendering.addPrepareRenderListener((engine, renderState) => {
    if (renderState.viewChanged) {
        const range = engine.map.getRange();
        
        // 视野太远时隐藏模型
        if (range > 1000) {
            mesh.visible = false;
        } else {
            mesh.visible = true;
        }
    }
});

我的感受:写一个完整的示例,把学到的都用上,感觉很有成就感!

我的发现

  • 可以控制渲染循环
  • 可以配置渲染特性
  • 可以监听渲染事件
  • 可以监控渲染性能

虽然代码还很简单,但是已经能做出一个基本的渲染控制系统了!

第十七步:踩过的坑

作为一个初学者,我踩了不少坑,记录下来避免再犯:

坑 1:动画不播放

原因:没有开启循环渲染。

解决 :设置 engine.rendering.enableAnimationLoop = true

坑 2:性能不好

原因:开启了循环渲染但没有动画,或者像素比太高。

解决

  1. 如果没有动画,不要开启循环渲染
  2. 降低像素比
  3. 降低帧率

坑 3:修改数据后场景不更新

原因:没有开启循环渲染,或者需要手动请求渲染。

解决

  1. 开启循环渲染(如果有动画)
  2. 或者调用 engine.requestRender() 手动请求渲染

坑 4:渲染监听回调执行太频繁

原因 :没有检查 viewChanged,导致每次渲染都执行。

解决 :配合 renderState.viewChanged 检查,只在视野变化时执行。

坑 5:高质量缓冲区影响性能

原因:开启了高质量缓冲区但没有必要。

解决:只有在需要高质量画面或使用高级渲染特性时才开启。

坑 6:截图功能不工作

原因 :没有开启 preserveDrawingBuffer

解决 :在初始化时设置 contextParameters.preserveDrawingBuffer = true

坑 7:渲染监听回调执行太频繁

原因 :没有检查 viewChanged,导致每次渲染都执行。

解决 :配合 renderState.viewChanged 检查,只在视野变化时执行。

我的学习总结

经过这一天的学习,我掌握了:

  1. 渲染系统的作用:控制场景的渲染方式、动画循环、渲染特效等
  2. 如何开启循环渲染 :通过 enableAnimationLoop 开启
  3. 如何设置帧率 :通过 animationLoopFrameTime 设置
  4. 如何监听渲染事件 :通过 addPrepareRenderListener 监听
  5. 如何配置渲染特性 :通过 features 配置 Bloom、抗锯齿等
  6. 如何优化性能:通过调整像素比、帧率、关闭不必要的特效等
  7. 如何开启截图功能 :通过 contextParameters.preserveDrawingBuffer 开启
  8. 如何获取渲染对象 :通过 rendererscenecamera 等属性访问
  9. 如何获取渲染状态 :通过 renderState 获取渲染状态信息

我的感受:渲染系统真的很强大!虽然功能很多,但是用起来其实不难。关键是要理解每个功能的作用,然后根据需求合理配置!

下一步计划

  1. 学习更多渲染特性的配置
  2. 尝试做性能优化
  3. 做一个完整的渲染控制项目

学习笔记就到这里啦!作为一个初学者,我觉得渲染系统虽然功能很多,但是用起来其实不难。关键是要理解每个功能的作用,然后根据需求合理配置!希望我的笔记能帮到其他初学者!大家一起加油!

相关推荐
矜辰所致1 天前
CH58x 蓝牙芯片 SysTick、RTC、TMRx
沁恒微·时钟·rtc·systick·ch58x
侯得山7 天前
批量坐标转换(Excel版)
excel·坐标转换·地理坐标·cgcs2000·直角坐标
休息一下接着来13 天前
笛卡尔坐标系转换(外参矩阵原理与用途)
坐标转换
普中科技1 个月前
【普中DSP28335开发攻略】-- 第 7 章 F28335时钟及控制系统
单片机·嵌入式硬件·时钟·dsp28335·普中科技
私人珍藏库1 个月前
[Android] Alarm Clock Pro 11.1.0一款经典简约个性的时钟
android·时钟
DebugKitty2 个月前
硬件开发2-ARM裸机开发3-I.MX6ULL - 时钟、定时器
arm开发·fpga开发·定时器·时钟
眰恦ゞLYF2 个月前
嵌入式硬件——IMX6ULL时钟配置
单片机·嵌入式硬件·时钟·imx6ull
sheepwjl2 个月前
《嵌入式硬件(十二):基于IMX6ULL的时钟操作》
汇编·arm开发·单片机·嵌入式硬件·时钟·.s编译
芯片小熊4 个月前
RTC时钟详解
单片机·嵌入式硬件·实时音视频·时钟·rtc