Cesium Entity Billboard 属性完整指南

570 阅读5分钟

Billboard 是 Cesium 中最常用的实体类型之一,用于在地球表面显示图标、图片或文本标签。以下是 Billboard 属性的完整详解和示例。

属性分类属性名称 (Type)默认值描述
核心样式show (Propertyboolean)true是否显示该广告牌12。
image (Propertystring)广告牌图像的 URI,或 Canvas 的 ID12。支持 Data URI、Blob URL 等。
color (PropertyColor)Color.WHITE与图像相乘的颜色1。可用于着色或设置透明度。
scale (Propertynumber)1.0应用于图像大小的统一缩放比例1。
rotation (Propertynumber)0.0旋转角度(弧度) ,逆时针方向12。
alignedAxis (PropertyCartesian3)Cartesian3.ZERO指定的旋转轴(单位向量)。默认为零向量,表示绕屏幕法线旋转12。
尺寸控制width (Propertynumber)广告牌的宽度(像素) ,覆盖图像原始宽度12。
height (Propertynumber)广告牌的高度(像素) ,覆盖图像原始高度12。
sizeInMeters (Propertyboolean)false广告牌大小是否以米为单位(而非像素)1。
位置偏移pixelOffset (PropertyCartesian2)Cartesian2.ZERO屏幕空间的像素偏移12。原点为广告牌初始位置,X向右为正,Y向下为正。
eyeOffset (PropertyCartesian3)Cartesian3.ZERO眼睛坐标(视图空间)的偏移(米) 12。相对于广告牌附着点。
对齐方式horizontalOrigin (PropertyHorizontalOrigin)HorizontalOrigin.CENTER水平对齐原点12。可选 LEFTCENTERRIGHT
verticalOrigin (PropertyVerticalOrigin)VerticalOrigin.CENTER垂直对齐原点12。可选 TOPCENTERBOTTOMBASELINE
高级效果scaleByDistance (PropertyNearFarScalar)根据与相机的距离缩放广告牌12。
translucencyByDistance (PropertyNearFarScalar)根据与相机的距离改变广告牌透明度12。
pixelOffsetScaleByDistance (PropertyNearFarScalar)根据与相机的距离缩放 pixelOffset1。
imageSubRegion (PropertyBoundingRectangle)定义使用图像的特定区域(像素单位,从左下角开始)1。
显示控制distanceDisplayCondition (PropertyDistanceDisplayCondition)指定广告牌可见的距离范围12。
disableDepthTestDistance (Propertynumber)0.0禁用深度测试的距离12。例如,设置为 Number.POSITIVE_INFINITY 可防止被地形或其他实体遮挡。
heightReference (PropertyHeightReference)HeightReference.NONE高度参考1。可选 NONE(绝对高度), CLAMP_TO_GROUND(贴地), RELATIVE_TO_GROUND(相对地面高度)。

基本属性

1. 核心显示属性

const entity = viewer.entities.add({
    position: Cesium.Cartesian3.fromDegrees(116.404, 39.915),
    billboard: {
        // 必需属性:图片URL或Canvas
        image: 'path/to/icon.png',
        
        // 尺寸控制
        width: 50,          // 宽度(像素)
        height: 50,         // 高度(像素)
        scale: 1.0,         // 整体缩放比例
        scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5),
        
        // 颜色和透明度
        color: Cesium.Color.WHITE,
        eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0),
        
        // 显示控制
        show: true,
        distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000),
        
        // 对齐和位置
        verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
        horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
        pixelOffset: new Cesium.Cartesian2(0, 0),
        
        // 旋转
        rotation: 0, // 弧度
        alignedAxis: Cesium.Cartesian3.ZERO,
        
        // 大小模式
        sizeInMeters: false,
        heightReference: Cesium.HeightReference.NONE,
        
        // 透明度裁剪
        translucencyByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.2),
        pixelOffsetScaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.0),
        
        // 禁用深度检测
        disableDepthTestDistance: 0.0
    }
});

详细属性说明

1. 图片相关属性

billboard: {
    // 图片源(支持URL、Canvas、DataURL)
    image: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMzIiIGhlaWdodD0iMzIiIHZpZXdCb3g9IjAgMCAzMiAzMiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iMTYiIGN5PSIxNiIgcj0iMTQiIGZpbGw9IiNGRjAwMDAiLz4KPC9zdmc+',
    
    // 或者使用Canvas
    image: createCustomCanvas(),
    
    // 图片子区域(sprite sheet)
    imageSubRegion: new Cesium.BoundingRectangle(0, 0, 32, 32)
}

function createCustomCanvas() {
    const canvas = document.createElement('canvas');
    canvas.width = 64;
    canvas.height = 64;
    const ctx = canvas.getContext('2d');
    
    // 绘制自定义图形
    ctx.fillStyle = '#ff0000';
    ctx.beginPath();
    ctx.arc(32, 32, 30, 0, Math.PI * 2);
    ctx.fill();
    
    return canvas;
}

2. 尺寸和缩放控制

billboard: {
    image: 'icon.png',
    
    // 固定尺寸
    width: 40,
    height: 40,
    
    // 动态缩放(基于距离)
    scaleByDistance: new Cesium.NearFarScalar(
        100,    // 近距离(米)
        2.0,    // 近距离缩放
        5000,   // 远距离(米)
        0.5     // 远距离缩放
    ),
    
    // 基于眼睛距离的透明度变化
    translucencyByDistance: new Cesium.NearFarScalar(
        100,    // 近距离
        1.0,    // 完全不透明
        5000,   // 远距离
        0.3     // 30%透明度
    ),
    
    // 物理尺寸模式(true时width/height单位为米)
    sizeInMeters: false
}

3. 位置和对齐

billboard: {
    image: 'icon.png',
    
    // 垂直对齐方式
    verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // TOP, CENTER, BOTTOM
    
    // 水平对齐方式  
    horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // LEFT, CENTER, RIGHT
    
    // 像素偏移(屏幕坐标)
    pixelOffset: new Cesium.Cartesian2(0, -20), // 向下偏移20像素
    
    // 基于距离的像素偏移缩放
    pixelOffsetScaleByDistance: new Cesium.NearFarScalar(
        100, 1.0,  // 近距离正常偏移
        5000, 0.5  // 远距离偏移减半
    ),
    
    // 眼睛偏移(世界坐标)
    eyeOffset: new Cesium.Cartesian3(0, 0, 100), // 沿Z轴偏移100米
}

4. 旋转和方向

billboard: {
    image: 'arrow.png',
    
    // 旋转角度(弧度)
    rotation: Cesium.Math.toRadians(45), // 旋转45度
    
    // 对齐轴(3D旋转)
    alignedAxis: Cesium.Cartesian3.UNIT_Z, // 围绕Z轴旋转
    
    // 朝向相机(billboard始终面向相机)
    // 默认就是朝向相机的,alignedAxis用于特殊旋转需求
}

5. 显示控制

billboard: {
    image: 'icon.png',
    
    // 显示/隐藏
    show: true,
    
    // 距离显示条件
    distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
        100,    // 最小距离(米)
        5000    // 最大距离(米)
    ),
    
    // 高度参考
    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, // NONE, CLAMP_TO_GROUND, RELATIVE_TO_GROUND
    
    // 禁用深度测试距离
    disableDepthTestDistance: 1000.0 // 1000米内禁用深度测试
}

完整示例

1. 创建自定义标记

function createCustomBillboard(viewer, lon, lat, options = {}) {
    const {
        image = 'default-icon.png',
        color = Cesium.Color.WHITE,
        scale = 1.0,
        label = '',
        verticalOffset = 0
    } = options;

    return viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(lon, lat),
        billboard: {
            image: image,
            width: 32,
            height: 32,
            scale: scale,
            color: color,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
            pixelOffset: new Cesium.Cartesian2(0, verticalOffset),
            scaleByDistance: new Cesium.NearFarScalar(100, 1.5, 2000, 0.8)
        },
        label: {
            text: label,
            font: '14pt monospace',
            pixelOffset: new Cesium.Cartesian2(0, -40),
            fillColor: Cesium.Color.WHITE,
            outlineColor: Cesium.Color.BLACK,
            outlineWidth: 2,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE
        }
    });
}

// 使用示例
const marker = createCustomBillboard(viewer, 116.404, 39.915, {
    image: 'custom-marker.png',
    color: Cesium.Color.RED.withAlpha(0.8),
    scale: 1.2,
    label: '北京',
    verticalOffset: -20
});

2. 动态更新 Billboard

// 获取entity引用
const entity = viewer.entities.add({/*...*/});

// 动态更新属性
entity.billboard.image = 'new-icon.png';
entity.billboard.scale = 2.0;
entity.billboard.color = Cesium.Color.BLUE;
entity.billboard.show = false; // 隐藏

// 使用回调函数创建动态内容
entity.billboard.image = new Cesium.CallbackProperty(function(time, result) {
    // 根据时间或其他条件返回不同的图片
    const hour = new Date().getHours();
    return hour < 12 ? 'day-icon.png' : 'night-icon.png';
}, false);

3. 性能优化示例

// 批量创建billboards
const positions = [
    { lon: 116.404, lat: 39.915, type: 'type1' },
    { lon: 121.473, lat: 31.230, type: 'type2' },
    // ...更多位置
];

const billboards = positions.map(pos => {
    return viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
        billboard: {
            image: getIconForType(pos.type),
            width: 24,
            height: 24,
            scaleByDistance: new Cesium.NearFarScalar(100, 1.0, 5000, 0.6),
            distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000)
        }
    });
});

function getIconForType(type) {
    const icons = {
        type1: 'red-dot.png',
        type2: 'blue-dot.png',
        type3: 'green-dot.png'
    };
    return icons[type] || 'default.png';
}

常见问题解决方案

1. 图片跨域问题

billboard: {
    image: new Cesium.Resource({
        url: 'https://other-domain.com/icon.png',
        headers: {
            'Accept': 'image/*'
        }
    })
}

2. 图片加载失败处理

const billboard = entity.billboard;
billboard.image.addEventListener(Cesium.ImageryState.FAILED, function() {
    console.error('图片加载失败');
    billboard.image = 'fallback-icon.png';
});

3. 性能优化建议

// 对于大量billboard,使用相同的image可以共享纹理
const sharedImage = 'shared-icon.png';

positions.forEach(pos => {
    viewer.entities.add({
        position: Cesium.Cartesian3.fromDegrees(pos.lon, pos.lat),
        billboard: {
            image: sharedImage, // 共享纹理
            width: 16,
            height: 16
        }
    });
});