在基礎篇中我們講過空間數據可視化之Entity實體類,今天我們介紹另外一個比較接近渲染引擎底層的類Primitive,雖然兩者都可用于繪制同樣的幾何圖形,但考慮到性能問題,我們更推薦您使用Primitive類實現。在使用Primitive API之前,您最好具備WebGL基礎知識,如果對WebGL不是太了解,建議先學習《WebGL編程指南》這本書。
Primitive介紹1. Primitive組成Primitive由兩部分組成:幾何形狀(Geometry)和外觀(Appearance)。幾何形狀定義了Primitive的結構,例如三角形、多邊形、折線、點、标簽等;外觀則定義了Primitive的着色或渲染(Shading),包括GLSL(OpenGL着色語言,OpenGL Shading Language)頂點着色器和片元着色器( vertex and fragment shaders),以及渲染狀态(render state)。
2. Primitive優劣勢相對于Entity,使用Primitive具有以下優勢:(1)性能:繪制大量Primitive時,可以将其合并為單個Geometry以減輕CPU負擔、更好地使用GPU。合并Primitive由web worker線程執行,以保持UI響應性;(2)靈活性:Geometry與Appearance 解耦,兩者可以分别進行修改;(3)低級别訪問:易于編寫GLSL頂點、片段着色器、使用自定義的渲染狀态 。
同時,也具有以下劣勢:(1)需要編寫更多的代碼,并且對圖形編程有更深刻的理解,尤其是OpenGL知識;(2)需要對組合幾何形狀對于靜态數據有效,而對于動态數據則不一定有效。
3.幾何圖形繪制方式以下是通過Entity和Primitive兩種方式繪制矩形圖形的方法:
// Entity方式
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方式
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')
})
}));
1.支持的幾何類型從基礎篇的Entity篇幅我們知道,Entity支持的圖形類型是以Graphics結尾的,一共有17種類型。而Primitive支持的幾何類型則是以Geometry結尾的,和Entity除了結尾命名不一樣之外,Cesium中還提供了獨有的點形狀PointPrimitive和一些形狀的集合,包括PointPrimitiveCollection、BillboardCollection、LabelCollection、PolylineCollection。支持的形狀如下圖所示:
添加簡單的點圖元集合方法如下:
//CreateapointPrimitivecollectionwithtwopoints
varpoints=scene.primitives.add(
newCesium.PointPrimitiveCollection({
modelMatrix:Cesium.Matrix4.IDENTITY,
debugShowBoundingVolume:false,
//OPAQUE完全不透明;TRANSLUCENT完全透明;OPAQUE_AND_TRANSLUCENT不透明和半透明
blendOption:Cesium.BlendOption.OPAQUE_AND_TRANSLUCENT,
})
);
//addPointPrimitive
points.add({
position:Cesium.Cartesian3.fromDegrees(-75.59777,40.53883,1000.0),
color:Cesium.Color.YELLOW,
});
points.add({
position:Cesium.Cartesian3.fromDegrees(-74.59777,40.53883,1000.0),
color:Cesium.Color.CYAN,
});
2.貼地或貼模型特性跟Entity類似,Primitive也支持貼地或貼模型的特性,但不一樣的是,Primitive是通過classificationType屬性控制的。其中GroundPolylineGeometry、GroundPolylinePrimitive結合實現貼地線;GroundPrimitive實現貼地幾何形狀,包括CircleGeometry、CorridorGeometry、EllipseGeometry、PolygonGeometry、RectangleGeometry;ClassificationPrimitive可實現貼地或貼模型,包括BoxGeometry、CylinderGeometry、EllipsoidGeometry、PolylineVolumeGeometry、SphereGeometry幾何形狀。下面為一簡單的貼模型示例:
scene.primitives.add(
newCesium.ClassificationPrimitive({
geometryInstances:newCesium.GeometryInstance({
geometry:Cesium.BoxGeometry.fromDimensions({
vertexFormat:Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
dimensions:newCesium.Cartesian3(8.0,5.0,8.0),
}),
modelMatrix:modelMatrix,
attributes:{
color:Cesium.ColorGeometryInstanceAttribute.fromColor(
newCesium.Color(1.0,0.0,0.0,0.5)
),
show:newCesium.ShowGeometryInstanceAttribute(true),
},
id:"volume",
}),
classificationType:Cesium.ClassificationType.CESIUM_3D_TILE,
})
);
3.組合幾何當我們使用一個圖元繪制多個靜态幾何圖形時,我們就會看到性能的優勢。組合多個GeometryInstances 為一個Primitive可以極大地提高性能,以下示例繪制了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()
}));
4.實例化幾何實例化可用于在場景的不同部分定位、縮放和旋轉相同的幾何體。多個實例可以引用相同的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
})
}));
5.更新每個示例的屬性在将幾何圖形添加到Primitive中以後,仍然可以修改幾何圖形實例的某些屬性:(1)顔色:如果Primitive設置了PerInstanceColorAppearance外觀,則可以修改ColorGeometryInstanceAttribute類型的顔色(2)可見性:任何實例可以修改可見性
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可以有多個幾何實例,但隻能有一個外觀。幾何圖形定義了結構,外觀定義了每個像素如何被着色,外觀可能直接使用材質(Material)。一個Primitive結構組成如下圖所示:
同時,Cesium定義了以下外觀:
外觀定義了需要在GPU上執行的完整的GLSL頂點、片段着色器,通常不需要修改這一部分,除非需要定義自己的外觀。外觀還定義了完整的渲染狀态,用于在繪制Primitive時控制GPU的狀态,我們可以直接或者通過高層API來定義渲染狀态,如“閉合(closed)”和“半透明(translucent)”,外觀将轉換為渲染狀态。如右圖所示:
//下面的外觀可用于定義一個不可進入的不透明的盒子
varappearance=newCesium.PerInstanceColorAppearance({
translucent:false,
closed:true,
});
//下面的代碼效果同上
varanotherAppearance=newCesium.PerInstanceColorAppearance({
renderState:{
depthTest:{
enabled:true,
},
cull:{
enabled:true,
face:Cesium.CullFace.BACK,
},
},
});
創建外觀後,不能更改其renderState屬性,但可以更改其material。我們還可以更改primitive的appearnace屬性。。大部分外觀具有flat、faceForward屬性,可以間接地控制GLSL着色器:(1)flat:扁平化着色,不考慮光線的作用(2)faceForward:布爾值,控制光照效果
着色器shadershader即着色器,分為頂點着色器(Vertex Shader)、片元着色器(Fragment Shader)、幾何着色器(Geometry shader)、計算着色器(Compute shader)、細分曲面着色器(Tessellation or hull shader),其中可編程的是頂點着色器和片元着色器。示意圖如下:
在屏幕上繪制或顯示一些物體時,這些物體的顯示形式是圖元(Primitive)或者網格(Mesh),比如一個貼在網格上的紋理角色。
幾何和外觀兼容性并非所有外觀都适用于所有幾何圖形。例如,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
// ...
});
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!