资讯详情

资讯详情

deck.gl CameraLight 详解:让点光源始终跟随相机位置的实验性光源

deck.gl CameraLight 详解让点光源始终跟随相机位置的实验性光源【免费下载链接】deck.glWebGL2 powered visualization framework项目地址: https://gitcode.com/GitHub_Trending/de/deck.glCameraLight 是 deck.gl 核心模块中一类特殊的点光源PointLight它的独特之处在于光源永远从当前相机位置发出无论视图如何旋转、平移或缩放光照方向都会自动跟随视角。本文将以 camera-light.md 为骨架结合源码实现与测试用例讲解 CameraLight 的构造函数参数、工作原理、接入LightingEffect的完整流程并给出 JavaScript 与 pydeck 两种语言的实战示例帮助你在 3D 柱状图、拉伸多边形、点云等图层上快速获得随视角移动的动态光照效果。CameraLight 是什么CameraLight 是 deck.gl 为光照系统提供的一种特殊 PointLight 变体。普通点光源需要你手动指定一个固定的position例如[0, 0, 200]而 CameraLight 不需要指定位置——它会在每次渲染时从当前 viewport相机的位置取样把光源贴在相机上因此光源与相机永远保持相对静止。在源码 modules/core/src/effects/lighting/camera-light.ts 中它的定义极为精简export default class CameraLight extends PointLight { getProjectedLight({layer}: {layer: Layer}): PointLight { const {projectedLight} this; const viewport layer.context.viewport; const {coordinateSystem, coordinateOrigin, modelMatrix} layer.props; const {cameraPosition} getUniformsFromViewport({ viewport, modelMatrix: modelMatrix as NumberArray16, coordinateSystem, coordinateOrigin }); projectedLight.color this.color; projectedLight.intensity this.intensity; projectedLight.position cameraPosition; return projectedLight; } }核心逻辑只有一件事覆写基类的getProjectedLight()通过getUniformsFromViewport取出当前相机在场景中的三维坐标cameraPosition再把它赋给投影后的光源position。也就是说CameraLight 本身不保存position属性位置完全由相机姿态实时决定。需要特别注意CameraLight 目前标记为Experimental实验性其导入路径带下划线前缀import {_CameraLight as CameraLight} from deck.gl/core;该导出定义在 modules/core/src/index.ts 中export {default as _CameraLight} from ./effects/lighting/camera-light;。CHANGELOG 中记录过 Move CameraLight export (#2957)说明其导出位置经历了调整API 仍可能在未来版本发生变化生产环境使用前请留意版本更新说明。快速上手创建一个 CameraLight最基础的创建方式与普通点光源一致只需传入颜色与强度import {_CameraLight as CameraLight} from deck.gl/core; const cameraLight new CameraLight({ color: [255, 255, 255], // RGB 颜色默认 [255, 255, 255] intensity: 1 // 光强默认 1.0 });在 3D 场景中光源本身不会产生任何视觉效果它必须通过LightingEffect挂载到Deck实例上才会参与渲染。完整的最小可运行示例import {Deck, _CameraLight as CameraLight, LightingEffect, MapView} from deck.gl/core; import {ColumnLayer} from deck.gl/layers; const cameraLight new CameraLight({ color: [210, 230, 255], intensity: 2.5 }); const lightingEffect new LightingEffect({cameraLight}); const deck new Deck({ initialViewState: {longitude: 0, latitude: 0, zoom: 5.8, pitch: 48, bearing: -20}, controller: true, views: new MapView(), effects: [lightingEffect], layers: [ new ColumnLayer({ id: columns, data: [{position: [0, 0], elevation: 120000}], getPosition: d d.position, getElevation: d d.elevation, radius: 55000, extruded: true, material: true // 关键只有设置了 material 的图层才会受光照影响 }) ] });构造函数参数详解CameraLight 的构造函数签名与 PointLight 保持一致因为它继承自 PointLight但在 CameraLight 场景下部分参数的含义有所差异const cameraLight new CameraLight({color, intensity});参数类型默认值说明colornumber[3][255, 255, 255]光源的 RGB 颜色每个通道取值 0–255intensitynumber1.0光源强度数值越大越亮idstring自动生成如point-0光源标识用于调试与去重positionnumber[3][0, 0, 1]对 CameraLight 无效。虽然从 PointLight 继承而来但会被getProjectedLight中取到的cameraPosition覆盖无需也不应设置attenuationnumber[3][1, 0, 0]衰减系数[C_constant, C_linear, C_quadratic]含义见下文参数默认值定义在 modules/core/src/effects/lighting/point-light.ts 顶部DEFAULT_LIGHT_COLOR [255, 255, 255]、DEFAULT_LIGHT_INTENSITY 1.0、DEFAULT_ATTENUATION [1, 0, 0]、DEFAULT_LIGHT_POSITION [0.0, 0.0, 1.0]。关于 attenuation衰减系数从 PointLight 继承的attenuation参数在 CameraLight 上同样生效。它按如下公式随光源距离D削减光强Intensity Intensity / (C_constant C_linear * D C_quadratic * D * D)默认值[1, 0, 0]表示光强不随距离衰减近似物理正确的衰减可设置为[1, 0, n]二次项衰减由于 CameraLight 与相机距离始终为 0衰减对它的实际影响有限但在非地理坐标系如正交视图中光源到图元的距离仍可能大于 0此时衰减会起作用。工作原理光源如何贴在相机上要理解 CameraLight关键在两点getProjectedLight()的调用时机以及getUniformsFromViewport返回的相机坐标。调用链光照系统由 LightingEffect 统一管理。在 modules/core/src/effects/lighting/lighting-effect.ts 的setProps()中光源按type分类存储switch (lightSource.type) { case ambient: this.ambientLight lightSource; break; case directional: this.directionalLights.push(lightSource); break; case point: this.pointLights.push(lightSource); // CameraLight 的 type 继承自 PointLight为 point break; default: }LightingEffect维护pointLights: PointLight[]数组CameraLight 作为 PointLight 的子类被放入其中。渲染时getShaderModuleProps(layer)调用_getLights(layer)对每个点光源执行pointLight.getProjectedLight({layer})——这里发生了多态分发如果光源是 CameraLight就会进入上文展示的覆写实现把位置替换为相机坐标如果是普通 PointLight则走基类实现用projectPosition把用户指定的position投影到当前坐标系统。相机坐标的来源getUniformsFromViewport是投影着色器模块shaderlib/project/viewport-uniforms提供的能力。它根据 viewport、图层的coordinateSystem、coordinateOrigin与modelMatrix计算出投影所需的 uniform其中就包含cameraPosition相机在 common space 中的位置。这意味着 CameraLight 的位置会随 viewport 变化缩放、旋转、平移实时更新会考虑图层自身的modelMatrix变换保证光源坐标与图层处于同一空间。测试验证仓库测试 test/modules/core/effects/lighting-effect.spec.ts 直接验证了这一行为const cameraLight new CameraLight(); const lightingEffect new LightingEffect({cameraLight, pointLight}); // ... 构造 PolygonLayer 与 MapView(longitude: -122, latitude: 37, zoom: 13) expect( equals(lighting.lights[0].position, [0, 0, 0.018310546875]), Camera light projection is ok ).toBeTruthy();测试断言在经度 -122、纬度 37、缩放级别 13 的 MapView 下CameraLight 投影后的位置恰好等于该相机在 common space 中的坐标[0, 0, 0.018310546875]证明光源位置 相机位置这一核心行为是被测试用例固化的契约而非文档的随意描述。与 LightingEffect 的完整集成CameraLight 不能单独使用必须包装在LightingEffect中并传给Deck的effects属性。LightingEffect的构造函数接收一个光源集合普通对象key 为任意标识const lightingEffect new LightingEffect({cameraLight});多个光源可以共存例如在保留环境光的同时使用 CameraLight 作为主光源import {Deck, AmbientLight, _CameraLight as CameraLight, LightingEffect} from deck.gl/core; const ambientLight new AmbientLight({color: [255, 255, 255], intensity: 0.6}); const cameraLight new CameraLight({color: [255, 255, 255], intensity: 1.5}); const lightingEffect new LightingEffect({ambientLight, cameraLight});需要留意的行为差异依据 lighting-effect.ts 源码默认光源的替代关系_applyDefaultLights()表明只有当你完全没有提供任何 ambient/point/directional 光源时LightingEffect才会注入默认的 1 个环境光 2 个方向光。因此一旦你显式传入 CameraLight就不会再获得默认的方向光场景明暗完全由你配置的光源决定必要时请自行补一个 AmbientLight 避免暗部过黑。阴影不支持阴影_shadow功能只对DirectionalLight与SunLight生效见 using-effects.md 的 Shadows 小节CameraLight 属于点光源不参与阴影投射。光源数量限制文档对点光源的说明是At most 5 directional lights can be supported对应 point-light.md实际使用中请控制总光源数量以保证渲染性能。光照的生效前提material 属性CameraLight 并不是对任何图层都生效。根据 using-effects.md 的说明光照只作用于 2.5D如拉伸的HexagonLayer、PolygonLayer或 3D如PointCloudLayer、SimpleMeshLayer图层且大多数此类图层需要通过material属性声明如何与全局光照交互。material是一个普通对象字段如下字段类型默认值说明ambientnumber0.35环境光系数0–1diffusenumber0.6漫反射系数0–1shininessnumber32高光锐度越大越亮越集中specularColornumber[3][0.15, 0.15, 0.15]高光颜色每通道 0–1将material设为true等价于全部使用默认值。示例new GeoJsonLayer({ id: geojson-layer, data: /path/to/data.geo.json, extruded: true, // 光照只作用于拉伸的多边形 getElevation: f f.properties.height, material: { ambient: 0.8, specularColor: [0.3, 0.1, 0.2] } });ScenegraphLayer、Tile3DLayer等图层则使用 glTF 文件内部定义的材质无需也不能通过material属性配置。pydeck 中的 CameraLight 实战CameraLight 同样暴露给 Python 绑定 pydeck。官方示例 camera_light.py 演示了完整的用法先通过pdk.Effect(CameraLight, color..., intensity...)创建光源再包装进pdk.Effect(LightingEffect, gallery_lightlight)最后传给pdk.Deck的effects参数import pydeck as pdk columns [ {position: [-1.3, -0.8], elevation: 70000, color: [255, 99, 71]}, {position: [0, 0.2], elevation: 120000, color: [64, 224, 208]}, {position: [1.3, -0.4], elevation: 90000, color: [255, 215, 0]}, ] ground [[[-2.7, -1.8], [2.7, -1.8], [2.7, 1.8], [-2.7, 1.8]]] layers [ pdk.Layer( PolygonLayer, dataground, get_polygon-, get_fill_color[45, 52, 64], materialTrue, ), pdk.Layer( ColumnLayer, datacolumns, get_positionposition, get_elevationelevation, get_fill_colorcolor, radius55000, disk_resolution6, extrudedTrue, materialTrue, ), ] initial_view_state pdk.ViewState(latitude0, longitude0, zoom5.8, pitch48, bearing-20) light pdk.Effect(CameraLight, color[210, 230, 255], intensity2.5) lighting pdk.Effect(LightingEffect, gallery_lightlight) deck pdk.Deck( layerslayers, effects[lighting], initial_view_stateinitial_view_state, map_providerNone, show_errorTrue, ) deck.to_html(camera_light.html, css_background_color#111827)该示例在无底图map_providerNone的暗色背景上渲染三根彩色柱子与一块地面多边形所有图层都开启了materialTrue。注意 CameraLight 在这里被命名为gallery_light传入LightingEffectEffect的 key 可以任意命名渲染时会按类型自动归类。典型使用场景与注意事项适合 CameraLight 的场景数据探查视角希望高光始终照亮观察者正对的方向让用户旋转视角时始终看清物体朝向相机的表面无底图/暗背景可视化如上面的 pydeck 示例用随相机移动的点光源替代固定的方向光营造手电筒跟随的沉浸感与固定光源叠加AmbientLight 保证整体亮度CameraLight 提供随视角变化的动态高光。注意事项清单实验性 API需使用_CameraLight别名导入未来可能调整请参考 CHANGELOG.md 与升级指南确认版本兼容性不能设置 position位置完全由相机决定手写的position会被覆盖不参与阴影阴影只支持 DirectionalLight / SunLight替代默认光照显式传入 CameraLight 后默认方向光消失建议同时配置环境光图层需 material确认目标图层为 2.5D/3D 且设置了material或 glTF 内置材质否则光照无效果坐标空间一致性CameraLight 的位置会结合图层的coordinateSystem、coordinateOrigin、modelMatrix计算混合使用不同坐标系统的图层时光照位置会按各自图层的投影分别计算。延伸阅读光源基类PointLight含attenuation衰减公式与position坐标系统说明光照容器LightingEffect光照系统总览Using Effects含 material 设置、阴影、默认光源规则源码实现camera-light.ts、point-light.ts、lighting-effect.ts测试用例lighting-effect.spec.ts验证光源投影位置Python 示例camera_light.py【免费下载链接】deck.glWebGL2 powered visualization framework项目地址: https://gitcode.com/GitHub_Trending/de/deck.gl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →