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 

有關未來計划,請參閱 幾何和外觀路線圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM