Cesium 几何体和外观(Geometry & Appearances)

 0、概述

本教程将向您介绍Primitive API 的 Geometry & Appearances(几何体和外观)系统。

这是一个高级主题,用于通过自定义网格、形状、体积和外观扩展CesiumJS,并不适合Cesium初学者。

声明:内容均来自Cesium官方教程,经翻译和整理而成。

原文链接:https://cesium.com/learn/cesiumjs-learn/cesiumjs-geometry-appearances/

一、几何体(Geometry

CesiumJS可以使用Entity(如多边形和椭球)创建不同的几何体类型。

例如,将以下内容复制并粘贴到Hello World Sandcastle示例中,以在球体上创建一个带有条纹图案的矩形。

viewer.entities.add({
        rectangle: {
          coordinates: Cesium.Rectangle.fromDegrees(-100, 20, -90, 30),
          material: new Cesium.StripeMaterialProperty({
            evenColor: Cesium.Color.YELLOW,
            oddColor: Cesium.Color.RED,
            repeat: 10
          })
        }
      })

在本教程中,我们深入了解 Geometry 和 Appearance 类型。

几何定义了Primitive(图元)的结构,即构成图元的三角形、线或点。

Appearance(外观)定义图元的着色,包括其完整的 GLSL 顶点和片元着色器,以及渲染状态。

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

  • 性能 - 在绘制大量静态图元(例如美国每个邮政编码的多边形)时,直接使用几何图形可以让我们将它们组合成单个几何图形,以减少 CPU 开销并更好地利用 GPU。组合图元是在 Web Worker 上完成的,以保持 UI 响应。
  • 灵活性 - 图元结合了几何和外观。通过解耦它们,我们可以独立地修改每一个。我们可以添加与许多不同外观兼容的新几何图形,反之亦然。
  • 低级访问 - 外观提供对渲染的低级访问,而无需担心 直接使用渲染器的所有细节 。
  • 外观可以很容易地:
  • - 编写完整的 GLSL 顶点和片元着色器。
  • - 使用自定义渲染状态。
  • 还有一些缺点:
  • 直接使用几何图形和外观需要更多的代码和对图形学更深入的理解。实体处于适合映射应用程序的抽象级别;几何图形和外观具有更接近传统 3D 引擎的抽象级别。
  • 组合图元对静态数据有效,但不一定对动态数据有效

让我们使用几何图形和外观重写初始代码示例:

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;

// original code
//viewer.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
//        })
//    }
//});

var instance = new Cesium.GeometryInstance({
  geometry : new Cesium.RectangleGeometry({
    rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
    vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
  })
});

scene.primitives.add(new Cesium.Primitive({
  geometryInstances : instance,
  appearance : new Cesium.EllipsoidSurfaceAppearance({
    material : Cesium.Material.fromType('Stripe')
  })
}));

我们没有使用rectangle entity,而是使用了通用的 Primitive,它结合了几何实例和外观。

目前,除了实例是几何体的容器之外,我们不会区分 Geometry 和 GeometryInstance 。

为了创建矩形的几何图形,即覆盖矩形区域并适合地球曲率的三角形,我们创建了一个 RectangleGeometry

由于它在表面上,我们可以使用EllipsoidSurfaceAppearance。

这通过基于几何体位于表面上或椭圆体上方的恒定高度这一事实进行假设来节省内存。

二、几何体类型

CesiumJS 支持以下几何图形:

Cesium Sandcastle

三、组合几何体

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

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;

var instance = new Cesium.GeometryInstance({
  geometry : new Cesium.RectangleGeometry({
    rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
    vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
  })
});

var anotherInstance = new Cesium.GeometryInstance({
  geometry : new Cesium.RectangleGeometry({
    rectangle : Cesium.Rectangle.fromDegrees(-85.0, 20.0, -75.0, 30.0),
    vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
  })
});

scene.primitives.add(new Cesium.Primitive({
  geometryInstances : [instance, anotherInstance],
  appearance : new Cesium.EllipsoidSurfaceAppearance({
    material : Cesium.Material.fromType('Stripe')
  })
}));

我们用不同的矩形创建了另一个实例,然后将这两个实例都提供给了同一个图元。这将绘制具有相同外观的两个实例。

某些外观允许每个实例提供独特的属性。例如,我们可以使用 PerInstanceColorAppearance 为每个实体指定不同的颜色。

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;

var 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)
  }
});

var 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 构造的 ,它使用每个实例的颜色属性来确定着色。

组合几何图形允许 CesiumJS 有效地绘制大量几何图形。

四、拾取

实例合并后可以独立访问。为实例指定id,并使用该id确定是否使用Scene.pick拾取实例。

下面的示例创建一个id为my rectangle的实例,并在单击该实例时将消息写入控制台。

 

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;

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

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

var handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
handler.setInputAction(function (movement) {
    var pick = scene.pick(movement.position);
    if (Cesium.defined(pick) && (pick.id === 'my rectangle')) {
      console.log('Mouse clicked rectangle.');
    }
  }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

 

使用id可以避免在构造图元后在内存中保留对完整实例的引用,包括几何图形。

五、几何实例

实例可用于在场景的不同部分定位、缩放和旋转相同的几何体。

这是可能的,因为多个实例可引用相同的Geometry,并且每个实例可以具有不同的modelMatrix

这允许我们只计算一次几何图形并多次重复使用它。

下面的示例创建一个EllipsoidGeometry和两个实例。每个实例都引用相同的椭球几何体,但使用不同modelMatrix,从而使一个椭球位于另一个之上。

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;

var ellipsoidGeometry = new Cesium.EllipsoidGeometry({
    vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
    radii : new Cesium.Cartesian3(300000.0, 200000.0, 150000.0)
});

var cyanEllipsoidInstance = new Cesium.GeometryInstance({
    geometry : ellipsoidGeometry,
    modelMatrix : Cesium.Matrix4.multiplyByTranslation(
        Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-100.0, 40.0)),
        new Cesium.Cartesian3(0.0, 0.0, 150000.0),
        new Cesium.Matrix4()
    ),
    attributes : {
        color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.CYAN)
    }
});

var orangeEllipsoidInstance = new Cesium.GeometryInstance({
    geometry : ellipsoidGeometry,
    modelMatrix : Cesium.Matrix4.multiplyByTranslation(
        Cesium.Transforms.eastNorthUpToFixedFrame(Cesium.Cartesian3.fromDegrees(-100.0, 40.0)),
        new Cesium.Cartesian3(0.0, 0.0, 450000.0),
        new Cesium.Matrix4()
    ),
    attributes : {
        color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.ORANGE)
    }
});

scene.primitives.add(new Cesium.Primitive({
    geometryInstances : [cyanEllipsoidInstance, orangeEllipsoidInstance],
    appearance : new Cesium.PerInstanceColorAppearance({
        translucent : false,
        closed : true
    })
}));

 

 

六、更新每个实例的属性

将几何图形添加到图元后,更新几何图形的每个实例属性以更改可视化效果。每个实例的属性包括:

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

 

var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;

var 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'
});
var primitive = new Cesium.Primitive({
    geometryInstances : circleInstance,
    appearance : new Cesium.PerInstanceColorAppearance({
        translucent : false,
        closed : true
    })
});
scene.primitives.add(primitive);

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

几何实例的属性可以使用primitive.getGeometryInstanceAttributes从图元中检索。可以直接更改属性的属性。

七、外观(Appearance)

几何定义了结构。图元的另一个关键属性appearance定义了图元的着色,即单个像素的着色方式。

 

 

CesiumJS有以下几种Appearance:

外观定义了在绘制图元时在 GPU 上执行的完整 GLSL 顶点和片元着色器。Appearances 还定义了完整的渲染状态,它在绘制图元时控制 GPU 的状态。
我们可以直接定义渲染状态,也可以使用更高级别的属性,如closed和translucent,外观将转换为渲染状态。例如:
// Perhaps for an opaque box that the viewer will not enter.
//  - Backface culled and depth tested.  No blending.

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

// This appearance is the same as above
var anotherAppearance  = new Cesium.PerInstanceColorAppearance({
  renderState : {
    depthTest : {
      enabled : true
    },
    cull : {
      enabled : true,
      face : Cesium.CullFace.BACK
    }
  }
});

一旦外观被创建,我们就不能改变它的 renderState 属性,但我们可以改变它的 material。我们还可以更改图元的 外观 属性。

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

  • flat  - 平面着色。不考虑照明。

  faceForward  - 照明时,翻转法线使其始终面向观察者。避免背面的黑色区域,例如墙的内侧。

八、几何和外观兼容性

并非所有外观都适用于所有几何图形。例如,椭球曲面外观不适用于墙几何图形,因为墙不在球体的表面上。 

要使外观与几何体兼容,它们必须具有匹配的顶点格式,这意味着几何体必须具有外观所需的数据作为输入。创建几何图形时,可以提供VertexFormat。

 

几何图形 vertexFormat 决定了它是否可以与另一个几何图形组合。两个几何图形不必是相同的类型,但它们需要匹配的顶点格式。

为方便起见,外观具有 vertexFormat 属性或 VERTEX_FORMAT 静态常量,可以作为几何体的选项传入。

var geometry = new Cesium.RectangleGeometry({
  vertexFormat : Cesium.EllipsoidSurfaceAppearance.VERTEX_FORMAT
  // ...
});

var geometry2 = new Cesium.RectangleGeometry({
  vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
  // ...
});

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

资源

在参考文档中,请参阅:

有关材料的更多信息,请参阅 Fabric 

有关未来计划,请参阅 几何和外观路线图

posted on 2021-12-10 17:36  苹果园dog  阅读(535)  评论(0编辑  收藏  举报

导航