• home > GIS > cesium >

    Cesium笔记(6): Primitive类下的图形Geometry与外观Appearance的设置

    Author:zhoulujun Date:

    使用Geometry和Appearance 具有以下优势:绘制大量Primitive时,可以将其合并为单个Geometry以减轻CPU负担、更好的使用GPU。合并Primitive由web worker线程执行,UI保持响应性。Geometry与Appearance解耦,两者可以分别进行修改

    https://cesium.com/docs/cesiumjs-ref-doc/Primitive.html,官方介绍:

    A primitive represents geometry in the Scene. The geometry can be from a single GeometryInstance as shown in example 1 below, or from an array of instances, even if the geometry is from different geometry types, e.g.

    我们可以通过Primitive API来操控几何图形及其外观,或者绘制各种特殊的形状

    var viewer = new Cesium.Viewer('cesiumContainer');
    var scene = viewer.scene;
    scene.primitives.add(new Cesium.RectanglePrimitive({
        //绘制矩形
        rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
        material : Cesium.Material.fromType('Dot')  //设置材质
    }));
    scene.primitives.add(new Cesium.Primitive({
      geometryInstances : new Cesium.GeometryInstance({
          geometry : Cesium.EllipsoidGeometry.createGeometry(new Cesium.EllipsoidGeometry({
            radii : new Cesium.Cartesian3(500000.0, 500000.0, 1000000.0),
            vertexFormat : Cesium.VertexFormat.POSITION_AND_NORMAL      })),
          modelMatrix : Cesium.Matrix4.multiplyByTranslation(Cesium.Transforms.eastNorthUpToFixedFrame(
            Cesium.Cartesian3.fromDegrees(-95.59777, 40.03883)), new Cesium.Cartesian3(0.0, 0.0, 500000.0), new Cesium.Matrix4()),
          id : 'ellipsoid',
          attributes : {
            color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.AQUA)
          }
      }),
      appearance : new Cesium.PerInstanceColorAppearance()}));

    Primitive由两个部分组成:

    • 几何形状(Geometry):定义了Primitive的结构,例如三角形、线条、点等

    • 外观(Appearance ):定义Primitive的着色(Sharding),包括GLSL(OpenGL着色语言,OpenGL Shading Language)顶点着色器和片段着色器( vertex and fragment shaders),以及渲染状态(render state)


    使用Geometry和Appearance 具有以下优势:

    1. 性能:绘制大量Primitive时,可以将其合并为单个Geometry以减轻CPU负担、更好的使用GPU。合并Primitive由web worker线程执行,UI保持响应性

    2. 灵活性:Geometry与Appearance 解耦,两者可以分别进行修改。我们可以添加与许多不同外观兼容的新几何体,反之亦然。

    3. 低级别访问:易于编写GLSL 顶点、片段着色器、使用自定义的渲染状态 

    具有以下劣势:

    1. 需要编写更多地代码,使用几何和外观直接需要更多的代码和更深入的了解图形。基元处于适用于映射应用程序的抽象级别; 几何和外观具有更接近传统3D引擎的抽象级别。

    2. 需要对图形编程有更多的理解,特别是OpenGL的知识,

    3. 组合几何对于静态数据是有效的,不一定是动态数据。

    几何形状(Geometry)

    Cesium支持以下几何图形:

    几何图形说明
    BoxGeometry立方体
    BoxOutlineGeometry仅有轮廓的立方体,只有外部线条的的盒子
    CircleGeometry圆形或者拉伸的圆形,圆圈或挤压圆
    CircleOutlineGeometry只有轮廓的圆形
    CorridorGeometry走廊:沿着地表的多段线(垂直于表面的折线),且具有一定的宽度,可以拉伸到一定的高度
    CorridorOutlineGeometry只有轮廓的走廊
    CylinderGeometry圆柱、圆锥或者截断的圆锥
    CylinderOutlineGeometry只有轮廓的圆柱、圆锥或者截断的圆锥
    EllipseGeometry椭圆或者拉伸的椭圆
    EllipseOutlineGeometry只有轮廓的椭圆或者拉伸的椭圆
    EllipsoidGeometry椭球体
    EllipsoidOutlineGeometry只有轮廓的椭球体
    RectangleGeometry矩形或者拉伸的矩形
    RectangleOutlineGeometry只有轮廓的矩形或者拉伸的矩形
    PolygonGeometry多边形,可以具有空洞或者拉伸一定的高度
    PolygonOutlineGeometry只有轮廓的多边形
    PolylineGeometry多段线,可以具有一定的宽度
    SimplePolylineGeometry简单的多段线
    PolylineVolumeGeometry多段线柱体
    PolylineVolumeOutlineGeometry只有轮廓的多段线柱体
    SphereGeometry球体
    SphereOutlineGeometry只有轮廓的球体
    WallGeometry
    WallOutlineGeometry只有轮廓的墙


    选取几何图形(Picking)

    即使多个 GeometryInstance被合并为单个Primitive,让然可以独立的被访问。我们可以为每一个GeometryInstance指定一个id,并且可以通过Scene.pick来判断该实例是否被选取:

    var handler = new Cesium.ScreenSpaceEventHandler( scene.canvas );
    //设置单击事件的处理句柄
    handler.setInputAction( function( movement )
    {
        var pick = scene.pick( movement.position );
        if ( Cesium.defined( pick ) && ( pick.id === 'rectangle-1' ) ){
            console.log( '矩形被选取' );
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK );

    几何图形实例(Geometry Instances)

    上面的例子中,我们已经用到了GeometryInstances,注意GeometryInstance与Geometry的关系:前者是后者的容器,多个Instance可以共用一个Geometry,并且可以通过GeometryInstances.modelMatrix属性提供不同position、scale、rotate等位置、缩放、旋转信息。

    合并几何图形(Combing Geometries)

    合并多个GeometryInstances 为一个Primitive可以极大的提高性能

    var instances = [cyanEllipsoidInstance, orangeEllipsoidInstance,...new Cesium.GeometryInstance];
    scene.primitives.add( new Cesium.Primitive( {
        geometryInstances : instances, //合并
        //某些外观允许每个几何图形实例分别指定某个属性,例如:
        appearance : new Cesium.PerInstanceColorAppearance({translucent : false,closed : true})
    } ) );

    cesium图形架构图


    外观(Appearances)

    Primitive由两个重要部分组成:几何图形实例、外观,一个Primitive只能有一个外观,而可以有多个实例。几何图形定义了结构,外观定义了每个像素被如何着色,外观可能使用材质(Material)。

    原语的另一个关键属性appearance定义了原始的阴影,即单个像素如何着色。一个原语可以有多个几何实例,但它只能有一个外观。根据外观的类型,外观将会material定义阴影的大部分。

    Cesium支持下表列出的外观:

    外观描述
    MaterialAppearance支持各种Geometry类型的外观,支持使用材质来定义着色。支持材料描述阴影。
    EllipsoidSurfaceAppearanceMaterialAppearance的一个版本。假设几何图形与地表是平行的,并且依此来进行顶点属性(vertex attributes)的计算。和Material Appearance一样,就像一个多边形,并且使用这个假设来通过程序上计算许多顶点属性来节省内存。
    PerInstanceColorAppearance让每个实例使用自定义的颜色来着色,使用每个实例的颜色来遮蔽每个实例。
    PolylineMaterialAppearance支持使用材质来着色多段线。支持材料遮蔽Polyline。
    PolylineColorAppearance使用每顶点或者每片段(per-vertex or per-segment )的颜色来着色多段线—使用每顶点或每段着色来遮蔽折线

    cesium图形与外观架构图

    外观定义了需要在GPU上执行的完整的GLSL顶点、片段着色器,通常不需要修改这一部分,除非需要定义自己的外观。

    外观还定义了完整的render state,用于在绘制Primitive时控制GPU的状态,可以直接或者通过高层API来定义render state:

    //下面的外观可用于定义一个Viewer不可进入的不透明盒子
    var appearance = new Cesium.PerInstanceColorAppearance( {
        translucent : false,
        closed : true
    } );
    //下面的代码效果同上
    var translucent = new Cesium.PerInstanceColorAppearance( {
        renderState : {
            depthTest : {
                enabled : true
            },
            cull : {
                enabled : true,
                face : Cesium.CullFace.BACK
            }
        }
    } );


    一旦外观被创建,其render state就不可再变,但是其材质是可以替换的。另外Primitive的外观也是不可修改的。

    外观定义绘制原始图形时在GPU上执行的完整GLSL顶点和片段着色器。除非我们正在编写自定义的外观,否则我们很少会碰到这些。外观还定义了完整渲染状态,当绘制原始图形时控制GPU的状态。我们可以直接定义渲染状态或使用像更高级别的性能closed和translucent,它的出现将转换为渲染状态

    大部分外观具有flat、faceForward属性,可以间接的控制GLSL 着色器:

    • flat:扁平化着色,不考虑光线的作用,不要考虑照明

    • faceForward:布尔值,控制光照效果。当照明时,翻转正常,使其始终面向观察者。避免背面的黑色区域,例如墙壁的内部

    flat和faceForward属性对着色器影响

    我们已经看到,并不是所有的外观都适用于所有几何体。例如,EllipsoidSurfaceAppearance不适合WallGeometry因为墙壁垂直于球体而不是平行的。

    除了这样的语义之外,为了与几何兼容的外观,它们必须具有匹配的顶点格式,这意味着几何必须具有外观所期望的数据作为输入。VertexFormat创建几何时可以提供A。

    我们可以通过请求几何计算所有顶点属性来保持简单,但效率低下,浪费,这将使几何与所有外观兼容(忽略每个实例的属性;见下文)。


    Geometry与Appearance的兼容性


    需要注意,不是所有外观和所有几何图形可以搭配使用,例如EllipsoidSurfaceAppearance与WallGeometry就不能搭配,原因是后者是垂直于地表的。

    cesium几何外观cesium Geometry与appearance 

    即使外观与几何图形兼容,它们还必须有匹配的顶点格式(vertex formats)—— 即几何图形必须具有外观可以作为输入的数据格式,在创建Geometry时可以提供VertexFormat。

    为了简便,可以让Geometry计算所有顶点属性(vertex attributes),以使之适用于任何外观,但这样做效率较差:

    var geometry = new Cesium.RectangleGeometry( {
    vertexFormat : Cesium.VertexFormat.ALL
    } )

    而如果我们使用外观EllipsoidSurfaceAppearance,其实只需要知道位置:

    var geometry = new Ceisum.RectangleGeometry( {
    vertexFormat : Ceisum.VertexFormat.POSITION_ONLY
    } )

    大部分外观具有vertexFormat属性或者VERTEX_FORMAT 静态常量,创建形状时只需要使用这些顶点格式即可:

    var geometry = new Ceisum.RectangleGeometry( {
        vertexFormat : Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT
    } )
    var geometry2 = new Ceisum.RectangleGeometry( {
        vertexFormat : Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT
    } )
    var appearance = new Ceisum.MaterialAppearance();
    var geometry3 = new Ceisum.RectangleGeometry( {
        vertexFormat : appearance.vertexFormat
    } )

    此外,两个形状必须具有匹配的vertexFormat,才能被合并到一个Primitive中。


    摘录文章

    Cesium(三) 几何图形与外观 https://blog.csdn.net/happyduoduo1/article/details/51868042

    Cesium学习笔记(五)几何和外观 https://blog.csdn.net/HobHunter/article/details/75109438

    Cesium学习笔记(六):几何和外观(Geometry and Appearances) https://blog.csdn.net/UmGsoil/article/details/74912638


    转载本站文章《Cesium笔记(6): Primitive类下的图形Geometry与外观Appearance的设置》,
    请注明出处:https://www.zhoulujun.cn/html/GIS/cesium/8332.html