Cesium学习笔记(五)自定义几何形状和外观

自定义几何形状和外观

有关Primitive API可用的Geometry & Appearance系统的信息,这是使用自定义网格、形状、体积和外观扩展CesiumJS的高级主题,并不适合典型的Cesium用户。

几何概述

Geometry定义了图元的结构,即构成图元的三角形、直线或点。
Appearance定义了图元的着色,包括其完整的GLSL顶点和片段着色器以及渲染状态。
使用Geometry和Appearance的好处是:

  • 性能:当绘制大量静态图元时,直接使用Geometry可以使我们将它们组合成一个几何图形,减少CPU开销并更好地利用GPU。组合原语是在web worker上完成的,以保持UI的响应速度。
  • 灵活性:primitives结合了Geometry和Appearance。通过解耦它们,我们可以添加与许多不同外观兼容的新几何形状,反之亦然。
  • 低级访问:外观可提供接近金属的渲染访问权限,而不必担心Renderer直接使用Direct的所有细节。Appearance使我们可以轻松地:
    • 编写完整的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')
  })
}));

在上面的代码中没有使用entities,而是使用Primitive来代替,它结合了GeometryInstance和Appearance。
创建矩形的几何形状,即覆盖矩形区域并适合地球曲率的三角形,我们创建一个RectangleGeometry。

图形组合

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

我们用另一个矩形创建了另一个实例,然后将两个实例都提供给图元(Primitive)。这将以相同的外观绘制两个实例。
在这里插入图片描述
一些外观允许每个实例提供唯一的属性。例如,我们可以使用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属性,确定图形的颜色。
组合几何图形可以使CesiumJS有效地绘制大量几何图形。下面的例子绘制了2592个唯一着色的矩形。

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

var instances = [];

for (var lon = -180.0; lon < 180.0; lon += 5.0) {
  for (var 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的实例,当它被选中的时候会发送一条消息到控制台。

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,每个实例可以有一个不同的模型矩阵。这允许我们只计算几何一次,并重用它多次。
在这里插入图片描述
下面的例子创建了一个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
    })
}));

在这里插入图片描述

更新每一个实例的属性

当几何实例被添加到原语中后,更新每个实例的属性来改变外观。这些属性包括:

  • Color:ColorGeometryInstanceAttribute决定了实例的颜色。原语必须有PerInstanceColorAppearance
  • Show:布尔值,决定该实例是否显示,任何实例都有这条属性。
    下面的例子展示如何更改几何实例的颜色:
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);

在这里插入图片描述
图形的颜色会不断改变。

外观

几何形状定义了结构。图元的另一个关键是外观,定义了图元的底纹、颜色等,比如一个单独的像素点是如何被上色的。一个图元可以有很多几何实例,但是只能有一个外观。根据外观的类型,外观将拥有一个material属性来定义着色主体。
在这里插入图片描述
上图展示了图元、几何实例和外观之间的关系。一个图元可以对应着多个几何实例,但只能对应一个外观。
CesiumJS拥有以下外观:

  • MaterialAppearance:一种适用于所有几何类型的外观,并支持material来描述阴影。
  • EllipsoidSurfaceMaterialAppearance的一个版本,它假设几何形状与地球表面平行,比如一个多边形,并使用这个假设通过程序计算许多顶点属性来节省内存。
  • PerInstanceColorAppearance:使用每个实例的颜色为每个实例着色。
  • PolylineMaterialAppearance:支持改变多段线的材质
  • PolylineColorAppearance:使用每顶点或每段着色来为折线着色。

外观定义了当图元被绘制时在GPU上执行的完整GLSL顶点和片段着色器。外观还定义了完整的渲染状态,它控制着绘制原语时GPU的状态。我们可以直接定义呈现状态,也可以使用更高级的属性,比如closedtranslucent,外观会将它们转换成渲染状态。

一旦外观被创建了,我们就不能改变它的renderState属性,但是我们可以改变它的material属性。我们也可以改变图元的appearance属性。
大多数外观拥有flatfaceForward属性,它们间接控制着GLSL着色器。

  • flat:扁平阴影,不考虑光线的因素。
  • faceForward:考虑光线影响,使它总是朝着观察者,避开背面的黑色区域,比如墙的内侧。
    flat:true
    在这里插入图片描述
    faceForward: false
    在这里插入图片描述
    faceForward: true
    在这里插入图片描述

几何形状和外观的兼容性

并不是所有的外观都适用于所有的几何形状。例如,椭球表面外观不适用于墙壁几何,因为墙壁不是在地球表面上。
要使外观与几何图形兼容,它们必须具有匹配的顶点格式,这意味着几何图形必须具有外观期望作为输入的数据。创建几何图形时可以提供VertexFormat。
在这里插入图片描述
在这里插入图片描述
一个几何形状的vertexFormat决定了它是否可以和其他几何形状结合。两个几何形状不必具有相同的类型,但它们必须匹配vertex format。
为了方便,外观也拥有vertexFormat属性或者是一个静态常量VERTEX_FORMAT,这个常量可以作为几何图形的一个选项传入。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值