【cesium知识梳理】4.Entity绘制实体、贴地、材质

4,450 阅读10分钟

之前零零碎碎学过、用过cesium,但也没做记录,现在重新整理一下,方便学习回顾。

在Cesium中绘制几何图形,有两种不同类型的API:

1.Entity API

特点:较为高级的,不需要使用者对计算机图形学有很深的理解,可以直接拿来使用的API。

2.Primitive API

向图形开发人员的,更为复杂的API。

Entity API本质上是对Primitive API的二次封装,目的是让使用者不必对计算机图

形学有多么高深的理解,就能轻松绘制出各式各样的几何图形。

本文主要介绍如何用Entity API绘制基本图形

1.entity绘制基本图形

entity实体,一般都要用viewer.entities.add({})来添加。

(1)点 point

//绘制点
var Point = viewer.entities.add({
        id: "point",
        name: "点",
        show: true,
        position: Cesium.Cartesian3.fromDegrees(118, 32, 0.0),
        //设置点的具体参数
        point: {
                //点的颜色
                color: Cesium.Color.BLUE,
                //点的像素大小
                pixelSize: 30,
                //点的轮廓颜色
                outlineColor: Cesium.Color.WHITE,
                //点的轮廓宽度
                outlineWidth: 5,
        },
});

//相机飞到点
viewer.flyTo(Point);

image.png

(2)线 polyline

polyline,意思是折线

var Line = viewer.entities.add({
        id: "line",
        name: "线",
        show: true,
        //线的具体参数
        polyline: {
            //线的坐标
            positions: Cesium.Cartesian3.fromDegreesArray([
                    118, 30, 119, 32, 116, 35,
            ]),
            //线的颜色
            color: Cesium.Color.RED,
            //线的宽度
            width: 8,
            //线的材质
            material: Cesium.Color.RED.withAlpha(0.5),
            //线贴在地表
            clampToGround: true,
        },
});

viewer.flyTo(Line);

在polyline对象中,positions是一个数组,代表着坐标点,点可以有多个,前两个坐标点位置定义了一条线段,之后的每一个坐标点位置都根据前一个坐标点位置定义一条线段,

image.png

(3)面 polygon

polygon,意思是多边形。

//面
var Polygon = {
        id: "polygon",
        name: "面",
        show: true,
        polygon: {
                hierarchy: Cesium.Cartesian3.fromDegreesArray([
                        118, 30, 119, 32, 116, 32, 116, 30,
                ]),
                //面的材质
                material: Cesium.Color.RED.withAlpha(0.4),
        },
};

在Polygon中有一个名为hierarchy的属性,其值是一个Cartesian3类型的对象。这个对象使用经度(longitude)和纬度(latitude)的数组来表示一个一系列的坐标点。

具体来说,Cesium.Cartesian3.fromDegreesArray()方法接受一个包含经度和纬度值的数组,并将其转换为一组Cartesian3对象。每两个连续的数组元素表示一个坐标点的经度和纬度。

在这个例子中,通过传递[118,  30,  119,  32,  116,  32,  116,  30]作为参数给fromDegreesArray()方法,将会生成一组包含四个坐标点的Cartesian3对象。

这四个坐标点的经纬度分别是:
1.  经度  118,纬度  30
2.  经度  119,纬度  32
3.  经度  116,纬度  32
4.  经度  116,纬度  30

这个hierarchy属性通常用于定义一个闭合的或非闭合的多边形的形状,或者是一个路径的路线。这些坐标点将在Cesium的渲染过程中被使用,用于绘制多边形或路径。

image.png

(4)矩形 Rectangle

创建一个对象Rectangle,在其中加入相应的配置项:

//矩形
var addRectangle =viewer.entities.add({
        id: "rectangle",
        name: "矩形",
        show: true,
        rectangle: {
            coordinates: Cesium.Rectangle.fromDegrees(
                    80.0,
                    30.0,
                    100.0,
                    35.0
            ),
            material: Cesium.Color.BLUE.withAlpha(0.5),
    },
});

rectangle  是包含矩形属性的对象。
coordinates  用于定义矩形的坐标范围。通过Cesium.Rectangle.fromDegrees()方法创建一个矩形,传入四个参数,分别代表矩形的最小经度、最小纬度、最大经度、最大纬度,这里设置为(80.0,  30.0,  100.0,  35.0),表示一个经度范围为80.0至100.0,纬度范围为30.0至35.0的矩形。 因为使用经纬度来约束的矩形边界,当矩形范围较大时,可以看到矩形有一些【弯曲】

image.png

当然,我们也可以加入更多的配置项,来个性化设置,例如设置厚度、高度、边框

rectangle: {
        coordinates: Cesium.Rectangle.fromDegrees(
                80.0,
                30.0,
                100.0,
                35.0
        ),
        material: Cesium.Color.BLUE.withAlpha(0.5),
        // 设置矩形的厚度,单位为米
        extrudedHeight: 20000,
        // 设置矩形的高度,单位为米
        height: 100000,
        //设置外边框的颜色、宽度
        outline: true,
        outlineWidth: 10,
        outlineColor: Cesium.Color.YELLOW,
},

image.png

想加入多个矩形时,可以用数组承接,然后循环绘制:

//矩形
var RectangleArr = [
{
    id: "rectangle",
    name: "矩形",
    show: true,
    rectangle: {
            coordinates: Cesium.Rectangle.fromDegrees(
                    80.0,
                    30.0,
                    100.0,
                    35.0
            ),
            material: Cesium.Color.BLUE.withAlpha(0.5),
            // 设置矩形的厚度,单位为米
            extrudedHeight: 20000,
            // 设置矩形的高度,单位为米
            height: 100000,
            //设置外边框的颜色、宽度
            outline: true,
            outlineWidth: 10,
            outlineColor: Cesium.Color.YELLOW,
    },
},
{
    id: "rectangle1",
    name: "矩形",
    show: true,
    rectangle: {
            coordinates: Cesium.Rectangle.fromDegrees(
                    80.0,
                    35.0,
                    100.0,
                    40.0
            ),
            material: Cesium.Color.YELLOW.withAlpha(0.9),

            // 设置矩形的高度,单位为米
            height: 100000,
    },
},
];

RectangleArr.forEach(item => {
viewer.entities.add(item);
});

image.png

(5)椭圆 Ellipse

在 ellipse对象中,需要配置好椭圆的semiMinorAxis 短半轴 和 semiMajorAxis长半轴,如果长短半轴一样,那绘制出来的就是一个圆形。

//椭圆
var ellipse = viewer.entities.add({
        id: "ellipse",
        name: "Ellipse",
        show: true,
        position: Cesium.Cartesian3.fromDegrees(116.39, 39.91),
        ellipse: {
                semiMinorAxis: 250000.0, //短半轴
                semiMajorAxis: 400000.0, //长半轴
                material: Cesium.Color.RED.withAlpha(0.5),
        },
});

viewer.flyTo(ellipse);

image.png

(6)Cylinder 圆柱体

//圆柱体
var addCylinder = viewer.entities.add({
        id: "cylinder",
        name: "圆柱体",
        show: true,
        //位置
        position: Cesium.Cartesian3.fromDegrees(100.0, 40.0, 200000.0),
        cylinder: {
                length: 400000.0, //圆柱长度
                topRadius: 200000.0, //顶面半径
                bottomRadius: 200000.0, //底面半径
                material: Cesium.Color.GREEN.withAlpha(0.6),
                outline: false,
                outlineColor: Cesium.Color.DARK_GREEN,
        },
});
viewer.flyTo(addCylinder);

position, 用于指定圆柱体柱心所在的位置,此处通过Cesium.Cartesian3.fromDegrees(100.0,40.0, 200000.0)将经纬度坐标转换为笛卡儿空间直角坐标,柱心高度为200000.0。

cylinder,用于描述圆柱体,并为cylinder对象添加 属性length,值为“400000.0”,用于指定圆柱体高度,这样柱心的高度刚好为200000.0,能够 保证圆柱体刚好贴地;

topRadius,值为“200000.0”,用于指定圆柱体顶面半径;

bottomRadius,值为“200000.0”,用于指定圆柱体底面半径;

当底面半径或者顶面半 径为0时,绘制出来的实体为圆锥体。

image.png

image.png

(7)Corridor 走廊

//走廊
var addCorridor = viewer.entities.add({
        id: "corridor",
        name: "走廊",
        show: true,
        corridor: {
                //起点,中间点,终点
                positions: Cesium.Cartesian3.fromDegreesArray([
                        100.0, 40.0, 105.0, 40.0, 105.0, 35.0, 108, 36,
                ]),
                //宽度
                width: 30000.0,
                material: Cesium.Color.YELLOW.withAlpha(0.5),
        },
});

image.png

我们还可以加入更多参数,例如拐角样式(ROUNDED是圆角,MITERED是直角,BEVELED是剪切角),还有实体高度等。

//走廊
var addCorridor = viewer.entities.add({
        id: "corridor",
        name: "走廊",
        show: true,
        corridor: {
                //起点,中间点,终点
                positions: Cesium.Cartesian3.fromDegreesArray([
                        100.0, 40.0, 105.0, 40.0, 105.0, 35.0, 108, 36,
                ]),
                //宽度
                width: 30000.0,
                material: Cesium.Color.YELLOW.withAlpha(0.5),

                //设置矩形的厚度,单位为米
                extrudedHeight: 200000,
                //定义拐角样式,ROUNDED圆角,MITERED直角,BEVELED剪切角
                cornerType: Cesium.CornerType.MITERED, 
        },
});

image.png

(8)墙 Wall

wall是专门用来实现墙的效果的,注意,positions中传入的坐标,是需要带高度的,Cesium.Cartesian3.fromDegreesArrayHeights()用来将多个带高度的经纬度坐标转为Cartesian3坐标。

var addWall = {
    id: "wall",
    name: "墙",
    show: true,
    wall: {
        positions: Cesium.Cartesian3.fromDegreesArrayHeights([
                107.0, 43.0, 200000.0, 97.0, 43.0, 100000.0, 97.0, 40.0,
                100000.0, 107.0, 40.0, 100000.0, 107.0, 43.0, 100000.0,
        ]),
        material: Cesium.Color.GREEN,
    },
};

image.png

(9)盒子 Box

position指定方盒的中心点位置,dimensions指定长、宽、高。

//方盒
var addBox = viewer.entities.add({
        id: "box",
        name: "方盒",
        show: true,
        position: Cesium.Cartesian3.fromDegrees(110, 35, 200000.0),
        box: {
                dimensions: new Cesium.Cartesian3(
                        400000.0,
                        300000.0,
                        400000.0
                ), //指定框的长度,宽度和高度
                material: Cesium.Color.BLUE,
        },
});

viewer.flyTo(addBox);

image.png

(10)椭球体 Ellipsoid

position指定椭球体中心的位置,radii 定义了椭球体的X轴半径,Y轴半径,Z轴半径。

//球体
var addEllipsoid = viewer.entities.add({
    id: "ellipsoid",
    name: "椭球体",
    show: true,
    position: Cesium.Cartesian3.fromDegrees(107.0, 40.0, 300000.0),
    ellipsoid: {
        radii: new Cesium.Cartesian3(200000.0, 200000.0, 300000.0), //椭球的半径
        material: Cesium.Color.BLUE.withAlpha(0.5),
        //外轮廓线
        outline: true,
        outlineColor: Cesium.Color.WHITE,
    },
});
viewer.flyTo(addEllipsoid);

image.png

(11)模型加载

首先,定义变量heading、pitch及roll,分别代表模型航向(围绕负Z

轴)、俯仰角(围绕负Y轴)及翻滚角(围绕正X轴)。

然后创建变量hpr,用new Cesium.HeadingPitchRoll(heading, pitch, roll);创建对象,这个对象是用来表示物体在三维空间中的方向和姿态的。

因为Cesium中都是以弧度的形式来进行计算的,所以我们需要将模型航向 Cesium.Math.toRadians(0)转换为弧度后进行使用。

// 定义参数,用于模型的摆位
var heading = Cesium.Math.toRadians(0); //航向
var pitch = 0; //俯仰角
var roll = 0; //翻滚角
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

var addModel = {
    id: "model", //id唯一
    name: "小车模型", // 名称
    show: true, //显示
    position: Cesium.Cartesian3.fromDegrees(118, 30, 5000), // 小车位置


    orientation: Cesium.Transforms.headingPitchRollQuaternion(
        Cesium.Cartesian3.fromDegrees(118, 30, 5000),
        hpr
    ), 

    model: {
        uri: "./3D格式数据/glTF/CesiumMilkTruck.gltf",
        minimumPixelSize: 300, //模型最小
        maximumScale: 50000, //模型最大
        scale: 30000, //当前比例
    },
};

var modd = viewer.entities.add(addModel);
viewer.flyTo(modd);

orientation,用于指定实体的方向,值是四元数 (Quaternion)类型的一组四维坐标。

Cesium.Transforms.headingPitchRollQuaternion()可以计算得出四元数。该方法需要传入两个参数:

第一个参数为本地参考系的中心点,此处取模型的位置作为中心点;

第二个参数为HeadingPitchRoll类型,用于描述模型航 向、俯仰角及翻滚角,此处取前面计算得来的hpr。

image.png

我们可以试着只修改一下heading, pitch, roll,来看看效果:

image.png

image.png

image.png

  • 航向角 (Heading) :航向角表示物体相对于北方的旋转角度,通常被定义为在水平面上的旋转角度。在航空和导航领域,航向角也被称为方位角。它通常从北方开始顺时针测量,0度表示正北,90度表示正东,180度表示正南,270度表示正西,依此类推。在代码中,heading是一个角度值,通过Cesium.Math.toRadians函数将其转换为弧度,以便与Cesium中的其他角度值一致。
  • 俯仰角 (Pitch) :俯仰角描述物体的上下旋转角度,通常在垂直平面内测量。正的俯仰角表示物体朝向地面,负的俯仰角表示物体朝向天空。在飞行和摄影术中,俯仰角用于确定物体视野的倾斜程度。在代码中,pitch是一个角度值,表示物体上下方向的倾斜。
  • 翻滚角 (Roll) :翻滚角描述物体绕其自身前后轴旋转的角度,通常在物体的轴线方向上测量。正的翻滚角表示物体向右翻滚,负的翻滚角表示物体向左翻滚。在航空和船舶领域,翻滚角也被称为滚转角。在代码中,roll是一个角度值,表示物体绕自身轴线旋转的角度。

(12)广告牌 Billboard

广告牌里面可以做的事情有很多,可以支持自定义,这里就先简单加载一个图片。

//广告牌
var addBillboard = viewer.entities.add({
        id: "billboard",
        name: "广告牌",
        show: true,
        position: Cesium.Cartesian3.fromDegrees(108, 30, 50),
        billboard: {
                image: "./智慧大楼.png",
                scale: 0.3, //比例
        },
});

viewer.flyTo(addBillboard);

image.png

2.entity 贴地

在实际需求中,经常会遇到这种情况,绘制出的实体(一般是平面的)需要紧贴在山坡、山脉等地形上,或者是贴在倾斜摄影模型的表面上,cesium也有相应的API来实现。

通常是使用heightReference或者classificationType 来实现贴地

image.png

image.png

(1)点 贴地

var addPoint = {
    id: "point",
    name: "点",
    show: true, //显示.
    position: Cesium.Cartesian3.fromDegrees(118, 32),
    point: {
            color: Cesium.Color.BLUE, //颜色
            pixelSize: 50, //点大小
            disableDepthTestDistance: Number.POSITIVE_INFINITY,
            
            //贴地
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND, 
    },
};

image.png

(2)线 贴地

线的贴地比较特殊,需要设置clampToGround: true, 没有用到上面说的classificationType和heightReference。

// 线
var addLine = {

    id: "line",
    name: "线",
    show: true, //显示
    polyline: {
        positions: Cesium.Cartesian3.fromDegreesArray([
            118, 30, 119, 32, 116, 35,
        ]),
        width: 2, //线条粗细
        material: Cesium.Color.RED, //线条材质

        clampToGround: true, //贴地
    },
};

image.png

image.png

(3)面贴地

//面
var addPolygon = {
    id: "polygon",
    name: "面",
    show: true,
    polygon: {
            hierarchy: Cesium.Cartesian3.fromDegreesArray([
                    118, 30, 119, 32, 116, 32, 116, 30,
            ]),
            material: Cesium.Color.RED.withAlpha(0.4),
            
            classificationType: Cesium.ClassificationType.BOTH, 
    },
};

image.png

3.entity材质

材质,简单来说就是表面的样式,cesium默认的材质样式都很简单,难以满足个性化的需求,因此cesium提供了MaterialProperty类,以方便我们自定义材质。

MaterialProperty类是一个抽象类,不能直接实例化,只能实例化它的子类。

在cesium文档中搜索一下MaterialProperty,可以看到 image.png

(1)虚线 PolylineDashMaterialProperty

创建一个直线后,如果想实现虚线的效果,可以实例化PolylineDashMaterialProperty,用在material属性中,来实现虚线

var addLine = viewer.entities.add({
        id: "line",
        name: "线",
        show: true, //显示
        polyline: {
            positions: Cesium.Cartesian3.fromDegreesArray([
                    111, 40, 116, 45,
            ]),
            width: 6, //线条粗细
            followSurface: false, //取消弯曲
            
            //简单的红色材质
            // material: Cesium.Color.RED,  
            
            //虚线
             material: new Cesium.PolylineDashMaterialProperty({
             	color: Cesium.Color.BLUE,
             }),

        },
});

image.png

(2)箭头 PolylineArrowMaterialProperty

//箭头 
material: new Cesium.PolylineArrowMaterialProperty(
        Cesium.Color.CYAN,
        5.0 //箭头的宽度(相对于线宽)
),

image.png

(3)条纹 StripeMaterialProperty

首先创建一个普通的多边形

//面
var addPolygon = viewer.entities.add({
    id: "polygon",
    name: "面",
    polygon: {
        hierarchy: Cesium.Cartesian3.fromDegreesArray([
            108, 30, 108, 36, 100, 36, 100, 30,
        ]),
        height: 0,
        outline: false,
        
         material: Cesium.Color.RED.withAlpha(0.6),
    },
});

image.png

//条纹纹理
material: new Cesium.StripeMaterialProperty({
        
        evenColor: Cesium.Color.WHITE, //偶数行,白的
        oddColor: Cesium.Color.BLACK,  //奇数行,黑的
        repeat: 8,          //一共8行
}),

image.png

(4)棋盘 CheckerboardMaterialProperty

//棋盘纹理
material: new Cesium.CheckerboardMaterialProperty({
    evenColor: Cesium.Color.RED,
    oddColor: Cesium.Color.YELLOW,
    
    //4X4
    repeat: new Cesium.Cartesian2(4, 4), 
}),

image.png

(5)网格 GridMaterialProperty

// 网格纹理 

material: new Cesium.GridMaterialProperty({
    //网格快的颜色和透明度
    color: Cesium.Color.YELLOW,
    cellAlpha: 0.2,
    
    //4行4列
    lineCount: new Cesium.Cartesian2(4, 4),
    网格线,水平和垂直都是4的宽度
    lineThickness: new Cesium.Cartesian2(4.0, 4.0),

}),

image.png

(6)贴图 image

//贴图纹理
    material: new Cesium.ImageMaterialProperty({
            image: "./自己练习/智慧大楼.png",
            repeat: new Cesium.Cartesian2(2, 2),
    }),

image.png

(8)删除实体等方法

viewer.entities.remove(addEllipsoid); //直接移除实体

viewer.entities.removeById("ellipsoid");//根据ID移除实体

viewer.entities.removeAll();//移除集合中全部实体