Cesium学习笔记(五)几何和外观

之前的笔记种记录了Cesium可以使用实体(如多边形和椭球)创建不同的地质类型。例如:使用点阵图在地球上创建一个矩形

let view = new Cesium.Viewer('cesiumDemo');

view.entities.add({
    rectangle : {
        coordinates : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
        material : new Cesium.StripeMaterialProperty({
            evenColor: Cesium.Color.WHITE,
            oddColor: Cesium.Color.BLUE,
            repeat: 5
        })
    }
});

这里写图片描述

下面将记录primitives ,并查看形成它们的类型Geometry和Appearance类型。几何定义了primitives的结构,即构成原语的三角形,线条或点。外观定义了primitives的阴影,包括其完整的GLSL顶点和片段着色器以及渲染状态。


Cesium支持以下几何形状

  • BoxGeometry
  • BoxOutlineGeometry
  • CircleGeometry
  • CircleOutlineGeomerty
  • CorridorGeometry
  • CorridroOutlineGeometry
  • CylinderGeometry
  • CylinderOutlineGeometry
  • EllipseGemetry
  • EllipsoidOutlineGeometry
  • RectangleGeometry
  • RectanelOutlineGeometry
  • PolygonGeometry
  • PolygonOutlineGeometry
  • PolylineGeometry
  • SimplePolylineGeometry
  • PolylineVolumeGeometry
  • PolylineVolumeOutlineGeometry
  • SphereGeometry
  • SphereOutlineGeometry
  • WallGeometry
  • WallOutlineGeometry

这里写图片描述

使用几何和外观的好处是:

  • 性能 - 当绘制大量静态图元(例如美国的每个邮政编码的多边形)时,直接使用几何形状可以将它们组合成单个几何体,以减少CPU开销并更好地利用GPU。组合primitives是在网络工作者上完成的,以保持UI的响应。
  • 灵活性 - 基元组合几何和外观。通过解耦,我们可以独立地修改。我们可以添加与许多不同外观兼容的新几何体,反之亦然。
  • 低级访问 - 外观提供近乎金属的访问权限,无需担心Renderer直接使用的所有细节。外观使其易于:
    1、编写完整的GLSL顶点和片段着色器。
    2、使用自定义渲染状态

还有一些缺点:

  • 使用几何和外观直接需要更多的代码和更深入的了解图形。基元处于适用于映射应用程序的抽象级别; 几何和外观具有更接近传统3D引擎的抽象级别。
  • 组合几何对于静态数据是有效的,不一定是动态数据。

用primitives将上面的例子重写

    let view = new Cesium.Viewer('cesiumDemo', {
            baseLayerPicker: false,
            imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
                url: 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
            }),
            shadows: true
        });
        let scene =  view.scene;
        scene.globe.enableLighting = true;

        // 创建几何实例
        let instance =  new Cesium.GeometryInstance({
            // 矩形几何
            geometry: new Cesium.RectangleGeometry({
                rectangle: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
            })
        });

        // 添加
        scene.primitives.add(new Cesium.Primitive({
            geometryInstances: instance,
            // 几何外观
            appearance: new Cesium.EllipsoidSurfaceAppearance({
                material: Cesium.Material.fromType('Stripe')
            })
        }));

组合几何

当我们使用一个primitives绘制多个静态几何时,我们看到了性能优势。例如,我们画出两个矩形。

        // 创建几何实例
        let instance =  new Cesium.GeometryInstance({
            // 矩形几何
            geometry: new Cesium.RectangleGeometry({
                rectangle: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
            })
        });

        // 另一个实例
        let anotherInstance = new Cesium.GeometryInstance({
            geometry: new Cesium.RectangleGeometry({
                rectangle: Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0),
            })
        });
        // 添加
        scene.primitives.add(new Cesium.Primitive({
            // 用数组方式可以添加多个实例
            geometryInstances: [instance,anotherInstance],
            // 几何外观
            appearance: new Cesium.EllipsoidSurfaceAppearance({
                material: Cesium.Material.fromType('Stripe')
            })
        }));

这里写图片描述

我们创建了另一个具有不同矩形的实例,然后将这两个实例提供给基元。这两个实例都使用相同的外观。一些外观允许每个实例提供唯一的属性。例如,我们可以使用PerInstanceColorAppearance不同颜色来遮蔽每个实例。

        // 创建几何实例
        let instance =  new Cesium.GeometryInstance({
            // 矩形几何
            geometry: new Cesium.RectangleGeometry({
                rectangle: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
                vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
            }),
            attributes: {
                color: new Cesium.ColorGeometryInstanceAttribute(0.0, 0.0, 1.0, 0.8)
            }
        });

        // 另一个实例
        let anotherInstance = new Cesium.GeometryInstance({
            geometry: new Cesium.RectangleGeometry({
                rectangle: Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0),
                vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
            }),
            // 属性
            attributes: {
                color: new Cesium.ColorGeometryInstanceAttribute (1.0, 0.0, 0.0, 0.8)
            }
        });
        // 添加
        scene.primitives.add(new Cesium.Primitive({
            // 用数组方式可以添加多个实例
            geometryInstances: [instance,anotherInstance],
            // 几何外观根据自身的属性来设置
            appearance: new Cesium.PerInstanceColorAppearance()
        }));

这里写图片描述

每个实例都有一个Color属性。然后使用一个构造原语PerInstanceColorAppearance,它知道使用每个实例的颜色属性来确定阴影。
组合几何使Cesium可以有效地绘制出几何图形。以下示例绘制2,592个独特的彩色矩形。它将优化几何,然后绘制非常快。

        let instances = [];
        for(let lon = -180.0; lon<180.0; lon += 5.0){
            for(let lat = -85.0; lat<85.0; lat += 5.0){
                instances.push(new Cesium.GeometryInstance({
                    geometry: new Cesium.RectangleGeometry({
                        rectangle : Cesium.Rectangle.fromDegrees(lon, lat, lon + 5.0, lat + 5.0),
                        vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
                    }),
                    attributes: {
                        color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({alpha : 0.5}))
                    }
                }));
            }
        }
        scene.primitives.add(new Cesium.Primitive({
            geometryInstances: instances,
            appearance: new Cesium.PerInstanceColorAppearance()
        }));

这里写图片描述

选择

实例组合后,它们仍然可以独立访问。特别是,我们可以分配一个id实例并使用它来确定实例是否被选中Scene.pick。 id可以是任何JavaScript类型:字符串,数字,具有其属性的对象等。
以下示例使用a创建一个实例id,并在单击该控件时将消息写入控制台。

        let instance = new Cesium.GeometryInstance({
            id: 'instance',
            geometry: new Cesium.RectangleGeometry({
                rectangle: Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
                vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
            }),
            attributes: {
                color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
            }
        });

        scene.primitives.add(new Cesium.Primitive({
            geometryInstances: instance,
            appearance: new Cesium.PerInstanceColorAppearance()
        }));

        // 添加监听事件
        let handler = new Cesium.ScreenSpaceEventHandler();
        handler.setInputAction((movement)=>{
            let pick = scene.pick(movement.position);
            if(Cesium.defined(pick) && pick.id==='instance'){
                console.log('单击了实例')
            }
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

这里写图片描述

使用id,而不是对实例本身的引用,允许原始和我们的应用程序避免在构建原语后,在内存中保留对完整实例的引用,包括其对几何的引用。由于几何可以包含几个大型类型的数组,这样我们可以节省大量的内存。

几何实例

到目前为止,我们已经将几何实例定义为几何体的容器。此外,实例用于在场景的不同部分中定位,缩放和旋转相同的几何。这是可能的,因为多个实例可以引用相同Geometry,并且每个实例可以具有不同的modelMatrix。这使我们只能计算几何一次,并重复使用多次。

这里写图片描述

更新每个实例属性

几何体的每个实例属性在添加到基元之后也可以进行更新。每个实例的属性包括:

  • 颜色:ColorGeometryInstanceAttribute确定实例的颜色。原始必须有一个PerInstanceColorAppearance。
  • 显示:布尔确定实例的可见性。适用于任何实例。

此示例显示如何更改几何实例的颜色:

let circleInstance = new Cesium.GeometryInstance({
    geometry : new Cesium.CircleGeometry({
        center : Cesium.Cartesian3.fromDegrees(-95.0, 43.0),
        radius : 250000.0,
        vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
    }),
    attributes : {
        color : Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(1.0, 0.0, 0.0, 0.5))
    },
    id: 'circle'
});
let primitive = new Cesium.Primitive({
    geometryInstances : circleInstance,
    appearance : new Cesium.PerInstanceColorAppearance({
        translucent : false,
        closed : true
    })
});
scene.primitives.add(primitive);

setInterval(()=> {
    var attributes = primitive.getGeometryInstanceAttributes('circle');
    attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({alpha : 1.0}));
},2000);

几何实例的属性可以从原语使用中检索primitive.getGeometryInstanceAttributes。attributes可以直接改变属性。在这种情况下,我们正在改变attributes.color为每2000毫秒等于一个新的随机生成的颜色。


外观

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

这里写图片描述

Cesium有以下外观:

  • MaterialAppearance
  • EllipsoidSurfaceAppearance
  • PerInstanceColorAppearance
  • PolylineMaterialAppearance
  • PolylineColorAppearance

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

let appearance  = new Cesium.PerInstanceColorAppearance({
  translucent : false,
  closed : true
});

let anotherAppearance  = new Cesium.PerInstanceColorAppearance({
  renderState : {
    depthTest : {
      enabled : true
    },
    cull : {
      enabled : true,
      face : Cesium.CullFace.BACK
    }
  }
});

一旦创建了外观,我们就不能改变它的renderState属性,但是我们可以改变它的属性material。同样,我们也可以改变原始的appearance属性。

大多数外观也有flat和faceForward属性,间接控制GLSL着色器。

  • flat - 平底阴影。不要考虑照明。
  • faceForward - 当照明时,翻转正常,使其始终面向观察者。避免背面的黑色区域,例如墙壁的内部。

这里写图片描述

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

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

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

let geometry = new Cesium.RectangleGeometry({
  vertexFormat : Cesium.VertexFormat.ALL
  // ...
});

这里写图片描述
这里写图片描述

EllipsoidSurfaceAppearance例如,如果我们正在使用,我们可以只是请求位置。

let geometry = new Ceisum.RectangleGeometry({
  vertexFormat : Ceisum.VertexFormat.POSITION_ONLY
  // ...
});

一般来说,我们如何知道用于给定外观的顶点格式?大多数外观都有一个vertexFormat属性,甚至一个VERTEX_FORMAT静态常量。

let geometry = new Ceisum.RectangleGeometry({
  vertexFormat : Ceisum.EllipsoidSurfaceAppearance.VERTEX_FORMAT
  // ...
});

let geometry2 = new Ceisum.RectangleGeometry({
  vertexFormat : Ceisum.PerInstanceColorAppearance.VERTEX_FORMAT
  // ...
});

let appearance = new Ceisum.MaterialAppearance(/* ... */);
let geometry3 = new Ceisum.RectangleGeometry({
  vertexFormat : appearance.vertexFormat
  // ...
});

而且,几何形状vertexFormat决定了它是否可以与其他几何组合。两个几何不一定是相同的类型; 他们只需要匹配的顶点格式。

官方文档

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值