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

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

第一次听说渲染系统

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

文档说渲染系统可以:

控制动画循环

配置渲染特效(如 Bloom、抗锯齿等)

监听渲染事件

监控渲染性能

控制渲染质量

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

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

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

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

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 来开启循环渲染。我试了试:

// 开启循环渲染

engine.rendering.enableAnimationLoop = true;

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

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

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

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 来设置帧时间间隔!

// 设置帧时间间隔为 16 毫秒(约 60 FPS)

engine.rendering.animationLoopFrameTime = 16;

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

我的尝试:

// 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() 来监听渲染事件!

engine.rendering.addPrepareRenderListener((engine, renderState) => {

    // 每帧渲染前都会执行这里的代码

    console.log('正在渲染...');

});

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

我的尝试:

// 监听渲染事件

engine.rendering.addPrepareRenderListener((engine, renderState) => {

    // 获取当前视野距离

    const range = engine.map.getRange();


    // 根据视野距离控制模型的显示隐藏

    if (range > 1000) {

        // 视野太远,隐藏模型

        mesh.visible = false;

    } else {

        // 视野较近,显示模型

        mesh.visible = true;

    }

});

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

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

检查视野是否变化

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

engine.rendering.addPrepareRenderListener((engine, renderState) => {

    if (renderState.viewChanged) {

        // 只有视野变化时才执行

        console.log('视野变化了!');

    }

});

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

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

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

第五步:了解渲染特性

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

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

开启抗锯齿

// 开启抗锯齿

engine.rendering.features.antialias.enabled = true;

engine.rendering.features.antialias.method = 'smaa';

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

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

开启 Bloom 泛光

// 开启 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 来设置设备像素比!

// 设置像素比

engine.rendering.pixelRatio = 1.0;

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

我的尝试:

// 正常分辨率(默认)

engine.rendering.pixelRatio = window.devicePixelRatio;

// 降低分辨率(节省性能)

engine.rendering.pixelRatio = 1.0;

// 提高分辨率(更清晰,但更耗性能)

engine.rendering.pixelRatio = 2.0;

我的发现:

1.0:标准分辨率,性能好

2.0:高分辨率,更清晰但耗性能

window.devicePixelRatio:根据设备自动调整(默认)

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

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

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

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

// 开启高质量缓冲区

engine.rendering.useHighPrecisionBuffer = true;

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

我的发现:

默认是 false,使用低质量缓冲区

开启后使用高质量缓冲区,画面更清晰

某些渲染特性(如 Bloom、反射)会自动开启

我的尝试:

// 开启高质量缓冲区

engine.rendering.useHighPrecisionBuffer = true;

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

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

第八步:使用调试模式

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

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

// 开启调试模式

engine.rendering.debugMode = 1; // DEBUG_MODE_MESH

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

我的发现:

0:无调试模式(默认)

1:网格调试模式

2:材质调试模式

3:物体调试模式

我的尝试:

// 开启网格调试模式

engine.rendering.debugMode = 1;

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

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

第九步:冻结更新

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

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

// 冻结更新

engine.rendering.freezeUpdate = true;

// 恢复更新

engine.rendering.freezeUpdate = false;

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

我的尝试:

// 冻结更新

engine.rendering.freezeUpdate = true;

// 做一些操作...

// 恢复更新

engine.rendering.freezeUpdate = false;

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

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

第十步:获取渲染对象

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

文档说可以通过 engine.rendering.renderer、engine.rendering.scene、engine.rendering.camera 来访问底层对象!

// 获取渲染器

const renderer = engine.rendering.renderer;

// 获取场景

const scene = engine.rendering.scene;

// 获取相机

const camera = engine.rendering.camera;

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

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

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

获取渲染分辨率

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

// 获取渲染分辨率

const resolution = engine.rendering.resolution;

console.log(resolution); // 分辨率信息

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

获取动画管理器

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

// 获取动画管理器

const animation = engine.rendering.animation;

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

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

获取标签实例

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

// 获取标签实例

const label = engine.rendering.label;

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

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

获取拾取器实例

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

// 获取拾取器实例

const picking = engine.rendering.picking;

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

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

获取天气实例

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

// 获取天气实例

const weather = engine.rendering.weather;

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

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

获取天空实例

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

// 获取天空实例

const sky = engine.rendering.sky;

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

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

第十一步:获取渲染状态

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

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

// 获取渲染状态

const renderState = engine.rendering.renderState;

// 检查视野是否变化

if (renderState.viewChanged) {

    console.log('视野变化了!');

}

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

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

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

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

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

// 开启自动偏移

engine.rendering.autoOffsetRelativeCenter = true;

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

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

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

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

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

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

const engine = new mapvthree.Engine(container, {

    rendering: {

        contextParameters: {

            preserveDrawingBuffer: true, // 开启保留绘图缓冲区

        },

    },

});

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

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

我的尝试:

const engine = new mapvthree.Engine(container, {

    rendering: {

        contextParameters: {

            preserveDrawingBuffer: true, // 开启截图功能

        },

    },

});

// 截图

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

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

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

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

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

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

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:渲染特性配置

我的尝试:

const engine = new mapvthree.Engine(container, {

    map: {

        center: [116.404, 39.915],

        range: 1000,

    },

    rendering: {

        enableAnimationLoop: true,

        animationLoopFrameTime: 16,

        features: {

            bloom: {

                enabled: true,

            },

        },

    },

});

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

第十五步:实际应用场景

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

场景 1:动画场景

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

engine.rendering.enableAnimationLoop = true;

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

场景 2:性能优化

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

// 降低帧率

engine.rendering.animationLoopFrameTime = 33;

// 降低像素比

engine.rendering.pixelRatio = 1.0;

// 关闭不必要的特效

engine.rendering.features.bloom.enabled = false;

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

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

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

engine.rendering.addPrepareRenderListener((engine, renderState) => {

    if (renderState.viewChanged) {

        const range = engine.map.getRange();


        // 根据视野距离控制模型显示

        models.forEach(model => {

            model.visible = range < 5000;

        });

    }

});

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

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

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

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:性能不好

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

解决:

如果没有动画,不要开启循环渲染

降低像素比

降低帧率

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

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

解决:

开启循环渲染(如果有动画)

或者调用 engine.requestRender() 手动请求渲染

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

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

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

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

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

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

坑 6:截图功能不工作

原因:没有开启 preserveDrawingBuffer。

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

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

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

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

我的学习总结

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

渲染系统的作用:控制场景的渲染方式、动画循环、渲染特效等

如何开启循环渲染:通过 enableAnimationLoop 开启

如何设置帧率:通过 animationLoopFrameTime 设置

如何监听渲染事件:通过 addPrepareRenderListener 监听

如何配置渲染特性:通过 features 配置 Bloom、抗锯齿等

如何优化性能:通过调整像素比、帧率、关闭不必要的特效等

如何开启截图功能:通过 contextParameters.preserveDrawingBuffer 开启

如何获取渲染对象:通过 renderer、scene、camera 等属性访问

如何获取渲染状态:通过 renderState 获取渲染状态信息

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

下一步计划:

学习更多渲染特性的配置

尝试做性能优化

做一个完整的渲染控制项目

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

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容