Cesium中級教程7 - Geometry and Appearances 幾何圖形和外觀

Cesium中文網:http://cesiumcn.org/ | 國內快速訪問:http://cesium.coinidea.com/javascript

本教程將向您介紹提供使用Primitive API的幾何圖形和外觀系統。這是一個高級主題,用於擴展具備自定義網格、形狀、體積和外觀的CesiumJS,而不是面向通用的Cesium用戶。若是您有興趣學習如何在地球上繪製各類形狀和體積,請查看建立實體教程。 CesiumJS可使用實體(如多邊形和橢圓體)建立不一樣的幾何類型。例如,將如下代碼複製並粘貼到Hello World Sandcastle示例中,以在球體上建立具備點模式的矩形:html

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

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

在本教程中,咱們將深刻到遮光罩下,查看構成它們的幾何圖形和外觀類型。幾何圖形定義了Primitive結構,即構成基本體的三角形、線或點。外觀定義了Primitive的着色,包括其完整的GLSL頂點和麪片着色,以及渲染狀態。java

使用幾何圖形和外觀的好處是:git

  • Performance(性能):在繪製大量Primitive(如美國每一個郵政編碼的多邊形)時,使用幾何圖形直接容許咱們將它們組合成單個幾何圖形,以減小CPU開銷並更好地利用GPU。組合Primitive是在Web worker上完成的,以保持UI的響應性。
  • Flexibility(靈活):Primitive結合了幾何圖形和外觀。經過分離它們,咱們能夠獨立地修改每個。咱們能夠添加與許多不一樣外觀兼容的新幾何圖形,反之亦然。
  • Low-level access(低層級訪問):外觀提供接近金屬的渲染訪問,無需擔憂直接使用Renderer的全部細節。外觀使下列狀況變得容易:
    • 寫全部GLSL的頂點和麪片着色器
    • 使用自定義渲染狀態

固然也會有一些缺點:github

  • 直接使用幾何圖形和外觀須要更多的代碼和對圖形更深刻的理解。實體處於適合映射應用程序的抽象級別;幾何圖形和外觀的抽象級別更接近於傳統的3D引擎
  • 組合幾何圖形對靜態數據有效,對動態數據不必定有效。

讓咱們使用幾何圖形和外觀重寫初始代碼示例:canvas

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

咱們使用Primitive(Primitive)代替矩形實體,它結合了幾何圖形和外觀。如今,咱們將不區分GeometryGemometryInstance。實例不只是幾何圖形的實例,更是其的容器。app

爲了建立矩形的幾何圖形,即覆蓋矩形區域的三角形和適合球體曲率的三角形,咱們建立了一個RectangleGeometrydom

由於它在表面上,因此咱們可使用EllipsoidSurfaceAppearance。這經過假設幾何圖形在曲面上或在橢球體上方的恆定高度來節省內存。ide

Geometry types 幾何圖形類型

CesiumJS提供下列幾何圖形:性能

組合幾何圖形

當咱們使用一個Primitive繪製多個靜態幾何圖形時,咱們看到了性能優點。例如,在一個Primitive中繪製兩個矩形。

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

每一個實例都有一個顏色屬性。Primitive是用PerinstanceColorAppearance構造的,它使用每一個實例的顏色屬性來肯定着色。

組合幾何圖形可使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()
}));

Picking 拾取

實例合併後能夠獨立訪問。爲實例分配一個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避免了在內存中,在Primitive構造以後,對整個實例的引用,包括幾何圖形。

Geometry instances 幾何實例

實例可用於在場景的不一樣部分定位、縮放和旋轉相同的幾何體。這是可能的,由於多個實例能夠引用相同的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
    })
}));

Updating per-instance attributes 更新實例屬性

將幾何圖形添加到Primitive後,更新幾何圖形的每一個實例屬性以更改可視化效果。每一個實例的屬性包括:

  • Color: ColorGeometryInstanceAttribute決定了顏色實例。Primitive必須具備PerInstanceColorAppearance。
  • Show:boolean類型決定實例是否可見。全部實例都具備該屬性。

下列展現瞭如何改變幾何實例的顏色:

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使用primitive.getGeometryInstanceAttributes檢索。attirbutes的屬性能夠直接被改變。

外觀

幾何定義結構。primitive的另外一個關鍵屬性,appearance,定義了primitive的紋理,即單個像素的顏色。primitive能夠有多個幾何實例,但只能有一個外觀。根據外觀的類型,外觀將具備定義着色的主體的material

CesiumJS具備下列外觀:

外觀定義了繪製Primitive時在GPU上執行的完整GLSL頂點和麪片着色器。外觀還定義了完整的渲染狀態,它控制繪製primitvie時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。咱們還能夠更改primitive的appearnace屬性。

大多數外觀還具備flatfaceForward屬性,這些屬性間接控制GLSL着色器。

  • flat:平面陰影。不要考慮照明。
  • faceForward:照明時,翻轉法線,使其始終面向觀衆。迴避背面的黑色區域,例如牆的內側。

Geometry and appearance compatibility 幾何圖形和外觀兼容

並不是全部外觀都適用於全部幾何圖形。例如,EllipsoidSurfaceAppearance外觀不適用於WallGeometry幾何圖形,由於牆不在球體的表面上。

要使外觀與幾何圖形兼容,它們必須具備匹配的頂點格式,這意味着幾何圖形必須具備外觀所期待的輸入數據。建立幾何圖形時能夠提供vertexFormat

幾何圖形的vertexFormat肯定它是否能夠與其餘幾何圖形組合。兩個幾何圖形沒必要是相同的類型,但它們須要匹配的頂點格式。

爲方便起見,外觀要麼具備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
  // ...
});

Resources 資源

參考文檔:

更多材料請訪問:Fabric 更多將來計劃,請訪問:Geometry and Appearances Roadmap

Cesium中文網交流QQ羣:807482793 Cesium中文網:http://cesiumcn.org/ | 國內快速訪問:http://cesium.coinidea.com/

相關文章
相關標籤/搜索