作为一个刚开始学习 mapvthree 的小白,今天要学习渲染系统了!听说这个系统可以控制场景的渲染方式,还能开启动画循环、配置渲染特效等!想想就激动!
今天在文档里看到了 engine.rendering 这个词,一开始我还以为是用来画图的,结果查了一下才知道,原来这是用来控制场景渲染的模块!
文档说渲染系统可以:
我的理解:简单说就是控制"怎么渲染场景",比如要不要每帧都渲染、用什么特效、怎么优化性能等!
作为一个初学者,我习惯先看看引擎有哪些属性。文档说 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 泛光
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,使用低质量缓冲区我的尝试:
// 开启高质量缓冲区
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,
},
},
},
});我的发现:初始化时就配置好了,代码更简洁!
学到这里,我开始想:渲染系统能用在什么地方呢?
如果场景中有动画效果(如飞线、粒子等),需要开启循环渲染:
engine.rendering.enableAnimationLoop = true;我的想法:这样动画才能持续播放!
如果场景性能不好,可以优化渲染设置:
// 降低帧率
engine.rendering.animationLoopFrameTime = 33;
// 降低像素比
engine.rendering.pixelRatio = 1.0;
// 关闭不必要的特效
engine.rendering.features.bloom.enabled = false;我的想法:这样可以提升性能,让场景更流畅!
如果场景中有很多模型,可以根据视野距离控制显示:
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;
}
}
});我的感受:写一个完整的示例,把学到的都用上,感觉很有成就感!
我的发现:
虽然代码还很简单,但是已经能做出一个基本的渲染控制系统了!
作为一个初学者,我踩了不少坑,记录下来避免再犯:
原因:没有开启循环渲染。
解决:设置 engine.rendering.enableAnimationLoop = true。
原因:开启了循环渲染但没有动画,或者像素比太高。
解决:
原因:没有开启循环渲染,或者需要手动请求渲染。
解决:
engine.requestRender() 手动请求渲染原因:没有检查 viewChanged,导致每次渲染都执行。
解决:配合 renderState.viewChanged 检查,只在视野变化时执行。
原因:开启了高质量缓冲区但没有必要。
解决:只有在需要高质量画面或使用高级渲染特性时才开启。
原因:没有开启 preserveDrawingBuffer。
解决:在初始化时设置 contextParameters.preserveDrawingBuffer = true。
原因:没有检查 viewChanged,导致每次渲染都执行。
解决:配合 renderState.viewChanged 检查,只在视野变化时执行。
经过这一天的学习,我掌握了:
enableAnimationLoop 开启animationLoopFrameTime 设置addPrepareRenderListener 监听features 配置 Bloom、抗锯齿等contextParameters.preserveDrawingBuffer 开启renderer、scene、camera 等属性访问renderState 获取渲染状态信息我的感受:渲染系统真的很强大!虽然功能很多,但是用起来其实不难。关键是要理解每个功能的作用,然后根据需求合理配置!
下一步计划:
学习笔记就到这里啦!作为一个初学者,我觉得渲染系统虽然功能很多,但是用起来其实不难。关键是要理解每个功能的作用,然后根据需求合理配置!希望我的笔记能帮到其他初学者!大家一起加油!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。