JSAPIThree 渲染系统学习笔记:让场景动起来
作为一个刚开始学习 mapvthree 的小白,今天要学习渲染系统了!听说这个系统可以控制场景的渲染方式,还能开启动画循环、配置渲染特效等!想想就激动!
第一次听说渲染系统
今天在文档里看到了 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获取渲染状态信息
我的感受:渲染系统真的很强大!虽然功能很多,但是用起来其实不难。关键是要理解每个功能的作用,然后根据需求合理配置!
下一步计划:
- 学习更多渲染特性的配置
- 尝试做性能优化
- 做一个完整的渲染控制项目
学习笔记就到这里啦!作为一个初学者,我觉得渲染系统虽然功能很多,但是用起来其实不难。关键是要理解每个功能的作用,然后根据需求合理配置!希望我的笔记能帮到其他初学者!大家一起加油!

浙公网安备 33010602011771号