1. 程式人生 > >Cesium中級教程7

Cesium中級教程7

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

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

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頂點和麵片著色,以及渲染狀態。

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

  • Performance(效能):在繪製大量Primitive(如美國每個郵政編碼的多邊形)時,使用幾何圖形直接允許我們將它們組合成單個幾何圖形,以減少CPU開銷並更好地利用GPU。組合Primitive是在Web worker上完成的,以保持UI的響應性。
  • Flexibility(靈活):Primitive結合了幾何圖形和外觀。通過分離它們,我們可以獨立地修改每一個。我們可以新增與許多不同外觀相容的新幾何圖形,反之亦然。
  • Low-level access(低層級訪問):外觀提供接近金屬的渲染訪問,無需擔心直接使用Renderer的所有細節。外觀使下列情況變得容易:
    • 寫所有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')
  })
}));

image

我們使用Primitive(Primitive)代替矩形實體,它結合了幾何圖形和外觀。現在,我們將不區分GeometryGemometryInstance。例項不僅是幾何圖形的例項,更是其的容器。

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

image

因為它在表面上,所以我們可以使用EllipsoidSurfaceAppearance。這通過假設幾何圖形在曲面上或在橢球體上方的恆定高度來節省記憶體。

Geometry types 幾何圖形型別

CesiumJS提供下列幾何圖形:

image

image

組合幾何圖形

當我們使用一個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')
  })
}));

image

我們用不同的矩形建立了另一個例項,然後將這兩個例項提供給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()
}));

image

每個例項都有一個顏色屬性。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()
}));

image

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。這允許我們只計算一次幾何圖形,並多次重複使用它。

image

以下示例建立一個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
    })
}));

image

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

image

CesiumJS具有下列外觀:

image

外觀定義了繪製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:照明時,翻轉法線,使其始終面向觀眾。迴避背面的黑色區域,例如牆的內側。

image

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

並非所有外觀都適用於所有幾何圖形。例如,EllipsoidSurfaceAppearance外觀不適用於WallGeometry幾何圖形,因為牆不在球體的表面上。

要使外觀與幾何圖形相容,它們必須具有匹配的頂點格式,這意味著幾何圖形必須具有外觀所期待的輸入資料。建立幾何圖形時可以提供vertexFormat

image

image

幾何圖形的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

本文由 admin 創作,採用 知識共享署名 3.0 中國大陸許可協議 進行許可。 可自由轉載、引用,但需署名作者且註明文章出處。

Cesium中文網交流QQ群:807482793

Cesium中文網:http://cesiumcn.org/ | 國內快速訪問:http://ces