https://github.com/AnalyticalGraphicsInc/cesium/wiki/Geometry-and-Appearances

Geometry and Appearances

Patrick Cozzi edited this page on 18 Aug 2015 · 77 revisions

Part I is now on the Cesium website.

Part II: Creating Custom Geometry and Appearances

This is now out-of-date. There will be a new version as part of #1683.

Cesium supports many common geometries and appearances out of the box. However, we may need to visualize a new type of geometry or apply custom shading to existing geometries.

Since geometries and appearances are decoupled, we can add new geometries that are compatible with many appearances and vice-versa. Doing so requires some knowledge of computer graphics and geometry. In this tutorial, we create a simple new Geometry and Appearance.

To follow along, download the latest full version of Cesium, or fork the Cesium repo. See the Contributor's Guide for details. If you develop new geometries or appearances that would be useful to the Cesium community, please consider contributing them.

Geometry

Geometry is a geometry representation that supports indexed or non-indexed triangles, lines, or points. Let's start by making a simple geometry for a tetrahedron, which is a solid composed of four equilateral triangles forming a pyramid. To begin, create the file TetrahedronGeometry.js in the Cesium Source/Core/ directory and add the following code:

  1. /*global define*/
  2. define([
  3. './Cartesian3',
  4. './ComponentDatatype',
  5. './PrimitiveType',
  6. './BoundingSphere',
  7. './GeometryAttribute',
  8. './GeometryAttributes',
  9. './GeometryPipeline',
  10. './VertexFormat',
  11. './Geometry'
  12. ], function(
  13. Cartesian3,
  14. ComponentDatatype,
  15. PrimitiveType,
  16. BoundingSphere,
  17. GeometryAttribute,
  18. GeometryAttributes,
  19. GeometryPipeline,
  20. VertexFormat,
  21. Geometry) {
  22. "use strict";
  23.  
  24. var TetrahedronGeometry = function() {
  25. var negativeRootTwoOverThree = -Math.sqrt(2.0) / 3.0;
  26. var negativeOneThird = -1.0 / 3.0;
  27. var rootSixOverThree = Math.sqrt(6.0) / 3.0;
  28.  
  29. var positions = new Float64Array(4 * 3);
  30.  
  31. // position 0
  32. positions[0] = 0.0;
  33. positions[1] = 0.0;
  34. positions[2] = 1.0;
  35.  
  36. // position 1
  37. positions[3] = 0.0;
  38. positions[4] = (2.0 * Math.sqrt(2.0)) / 3.0;
  39. positions[5] = negativeOneThird;
  40.  
  41. // position 2
  42. positions[6] = -rootSixOverThree;
  43. positions[7] = negativeRootTwoOverThree;
  44. positions[8] = negativeOneThird;
  45.  
  46. // position 3
  47. positions[9] = rootSixOverThree;
  48. positions[10] = negativeRootTwoOverThree;
  49. positions[11] = negativeOneThird;
  50.  
  51. var attributes = new GeometryAttributes({
  52. position : new GeometryAttribute({
  53. componentDatatype : ComponentDatatype.DOUBLE,
  54. componentsPerAttribute : 3,
  55. values : positions
  56. })
  57. });
  58.  
  59. var indices = new Uint16Array(4 * 3);
  60.  
  61. // back triangle
  62. indices[0] = 0;
  63. indices[1] = 1;
  64. indices[2] = 2;
  65.  
  66. // left triangle
  67. indices[3] = 0;
  68. indices[4] = 2;
  69. indices[5] = 3;
  70.  
  71. // right triangle
  72. indices[6] = 0;
  73. indices[7] = 3;
  74. indices[8] = 1;
  75.  
  76. // bottom triangle
  77. indices[9] = 2;
  78. indices[10] = 1;
  79. indices[11] = 3;
  80.  
  81. this.attributes = attributes;
  82. this.indices = indices;
  83. this.primitiveType = PrimitiveType.TRIANGLES;
  84. this.boundingSphere = undefined;
  85. };
  86.  
  87. return TetrahedronGeometry;
  88. });

The tetrahedron is made up of four vertices, whose positions lie on the unit sphere. For precision, we always store positions in a Float64Array.

Each of the tetrahedron's four triangles is defined by three indices. Using indices - as opposed to defining three vertices per triangle - allows us to reuse vertices to save memory. For our tetrahedron, each vertex is indexed three times since each vertex has three incident triangles. Indices are stored in a Uint16Array, but can also be stored in a Uint32Array if more than 64K vertices are used.

Tip: Use IndexDatatype.createTypedArray to allocate the right typed array for indices.

As shown with the blue arrow on the back triangle, the outward-facing side of the triangle is defined by ordering indices in counter-clockwise order. If we wrapped four fingers of our righthand around the back triangle in the orders the indices are defined, 0 - 1 - 2, our thumb points in the direction that is considered outward facing. In Cesium, this counter-clockwise winding order is required.

Our tetrahedron assigns to four public properties, which are required to meet the Geometryinterface.

  1. this.attributes = attributes;
  2. this.indices = indices;
  3. this.primitiveType = Cesium.PrimitiveType.TRIANGLES;
  4. this.boundingSphere = undefined;
  • attributes - A GeometryAttributes object where each property is a GeometryAttribute. Each attribute defines one characteristic of the vertices in the geometry, and data is stored in a typed array. Examples of attributes include positions, normals, and colors.
  • indices (optional) - Index data that indexes into attributes. Using indices allows us to reuse vertices without duplicating them (and avoiding duplication is virtually always a win). For example, our tetrahedron has 4 vertices and each vertex is part of 3 different triangles. Using indices allows us to reuse the same vertex for each triangle instead of creating a copy.
  • primitiveType - The primitive that composes the geometry. Most often this is TRIANGLES or LINES, which provide the most flexibility. This determines how the indices (or vertices) are interpreted. For example, when TRIANGLES is used, every three vertices is interpreted as a triangle.
  • boundingSphere (optional) - A sphere that encloses the geometry. This is used to improve drawing performance via culling.

Bounding Spheres

We can improve the performance of drawing our tetrahedron by computing the bounding sphere.

  1. this.boundingSphere = BoundingSphere.fromVertices(positions);

BoundingSphere has functions to compute a tight bounding sphere like fromVertices, but in many cases we can use our knowledge of the geometry to quickly create a tighter bounding sphere. Since we know the tetrahedron's vertices lie on the unit sphere, we can just use the unit sphere as the bounding sphere:

  1. this.boundingSphere = new BoundingSphere(new Cartesian3(0.0, 0.0, 0.0), 1.0);

Visualizing the Tetrahedron with a Primitive

Our tetrahedron is centered in its local coordinate system and inscribed in the unit sphere. To visualize it, we need to compute a modelMatrix to position and scale it. In addition, since it only has position attributes, we'll use an appearance with flat shading so normals are not required. First, build the code and run the HTTP server for testing (.\Tools\apache-ant-1.8.2\bin\ant combine runServer). Navigate to http://localhost:8080/Apps/Sandcastle/index.html, your local version of Cesium Sandcastle. Paste the following code in the Sandcastle Hello World demo:

  1. var widget = new Cesium.CesiumWidget('cesiumContainer');
  2. var scene = widget.scene;
  3. var ellipsoid = widget.centralBody.ellipsoid;
  4.  
  5. var modelMatrix = Cesium.Matrix4.multiplyByUniformScale(
  6. Cesium.Matrix4.multiplyByTranslation(
  7. Cesium.Transforms.eastNorthUpToFixedFrame(ellipsoid.cartographicToCartesian(
  8. Cesium.Cartographic.fromDegrees(-100.0, 40.0))),
  9. new Cesium.Cartesian3(0.0, 0.0, 200000.0)),
  10. 500000.0);
  11.  
  12. var instance = new Cesium.GeometryInstance({
  13. geometry : new Cesium.TetrahedronGeometry(),
  14. modelMatrix : modelMatrix,
  15. attributes : {
  16. color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE)
  17. }
  18. });
  19.  
  20. scene.primitives.add(new Cesium.Primitive({
  21. geometryInstances : instance,
  22. appearance : new Cesium.PerInstanceColorAppearance({
  23. flat : true,
  24. translucent : false
  25. })
  26. }));

Here's our tetrahedron, scaled and positioned, without shading:

Without shading, it is hard to see the surfaces. To view a wireframe, we could change the primitiveType to LINES and change the indices to represent a line segment per unique triangle edge. However, GeometryPipeline is a collection of functions that transform geometries. The function GeometryPipeline.toWireframe transforms a geometry to use the LINES primitive type. Replace the instance with this:

  1. var instance = new Cesium.GeometryInstance({
  2. geometry : Cesium.GeometryPipeline.toWireframe(new Cesium.TetrahedronGeometry()),
  3. modelMatrix : modelMatrix,
  4. attributes : {
  5. color : Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE)
  6. }
  7. });

Tip: Use GeometryPipeline.toWireframe for debugging to visualize a geometry's primitives.

Adding Normals for Shading

To use an appearance with shading, the geometry must have a normal attribute. The normal to a triangle is a unit vector that is perpendicular to the triangle.

In our case, we need to compute the normals for each vertex to determine the shading of the geometry. The normal to a vertex is a vector in the direction of the sum of the normals for each triangle the vertex composes and with a magnitude of 1. Below shows how we can add the normals of

Normal vectors can be computed after the geometry is created using GeometryPipeline.computeNormal. Lets take a look at how the generated normals effect shading. In TetrahedronGeometry,js, replace the last few lines of the constructor (after we set the values of the indices) with the following:

  1. var boundingSphere = new BoundingSphere(new Cartesian3(0.0, 0.0, 0.0), 1.0);
  2.  
  3. var geometry = GeometryPipeline.computeNormal(new Geometry({
  4. attributes: attributes,
  5. indices: indices,
  6. primitiveType: PrimitiveType.TRIANGLES,
  7. boundingSphere: boundingSphere
  8. }));
  9.  
  10. this.attributes = geometry.attributes;
  11. this.indices = geometry.indices;
  12. this.primitiveType = geometry.primitiveType;
  13. this.boundingSphere = geometry.boundingSphere;

Build Cesium then reload the sandcastle example to see the results:

This is not what we would expect shading to look like. To better understand what's happening, we can visualize the normal vectors with createTangentSpaceDebugPrimitive. Add the following code to the end of the Sandcastle example:

  1. scene.primitives.add(Cesium.createTangentSpaceDebugPrimitive({
  2. geometry: tetrahedron,
  3. modelMatrix: modelMatrix,
  4. length: 0.2
  5. }));

As you can see, the normal vectors aren't very "normal" to any of the triangles of the tetrahedron. Using single vertices works best when angle between adjacent triangles is close to 180 degrees (like the triangles in a sphere), and thus the normals for the adjacent triangles are pointing in the same general direction. To get better shading, we must duplicate each vertex so that adjacent triangles no longer share vertices.

 

In TetrahedronGeometry.js, replace the positions and indices with the following:

  1. var positions = new Float64Array(4 * 3 * 3);
  2. // back triangle
  3. positions[0] = 0.0;
  4. positions[1] = 0.0;
  5. positions[2] = 1.0;
  6. positions[3] = 0.0;
  7. positions[4] = (2.0 * Math.sqrt(2.0)) / 3.0;
  8. positions[5] = negativeOneThird;
  9. positions[6] = -rootSixOverThree;
  10. positions[7] = negativeRootTwoOverThree;
  11. positions[8] = negativeOneThird;
  12.  
  13. // left triangle
  14. positions[9] = 0.0;
  15. positions[10] = 0.0;
  16. positions[11] = 1.0;
  17. positions[12] = -rootSixOverThree;
  18. positions[13] = negativeRootTwoOverThree;
  19. positions[14] = negativeOneThird;
  20. positions[15] = rootSixOverThree;
  21. positions[16] = negativeRootTwoOverThree;
  22. positions[17] = negativeOneThird;
  23.  
  24. // right triangle
  25. positions[18] = 0.0;
  26. positions[19] = 0.0;
  27. positions[20] = 1.0;
  28. positions[21] = rootSixOverThree;
  29. positions[22] = negativeRootTwoOverThree;
  30. positions[23] = negativeOneThird;
  31. positions[24] = 0.0;
  32. positions[25] = (2.0 * Math.sqrt(2.0)) / 3.0;
  33. positions[26] = negativeOneThird;
  34.  
  35. // bottom triangle
  36. positions[27] = -rootSixOverThree;
  37. positions[28] = negativeRootTwoOverThree;
  38. positions[29] = negativeOneThird;
  39. positions[30] = 0.0;
  40. positions[31] = (2.0 * Math.sqrt(2.0)) / 3.0;
  41. positions[32] = negativeOneThird;
  42. positions[33] = rootSixOverThree;
  43. positions[34] = negativeRootTwoOverThree;
  44. positions[35] = negativeOneThird;
  45.  
  46. var indices = new Uint16Array(4 * 3);
  47.  
  48. // back triangle
  49. indices[0] = 0;
  50. indices[1] = 1;
  51. indices[2] = 2;
  52.  
  53. // left triangle
  54. indices[3] = 3;
  55. indices[4] = 4;
  56. indices[5] = 5;
  57.  
  58. // right triangle
  59. indices[6] = 6;
  60. indices[7] = 7;
  61. indices[8] = 8;
  62.  
  63. // bottom triangle
  64. indices[9] = 9;
  65. indices[10] = 10;
  66. indices[11] = 11;

We can still use GeometryPipeline.computeNormal to find the normal vectors. To see the results, build Cesium and reload the sandcastle example.

Now that we've duplicated the positions, the normal vector for each position is perpendicular to the triangle that vertices composes. This corrects the shading.

Using a Web Worker

Using a web workers for a geometry allows the computation to happen asynchronously, which keeps the UI responsive. The computation for our tetrahedron is pretty trivial, but many geometry computations can be complicated so all built-in Cesium geometries use a web worker.

The first step is to add createTetrahedronGeometry.js to the Source/Workers/ directory. This will contain a function to instruct the web worker what do to when it is triggered. In this case, we want to create the geometry in the worker. Copy and paste the following code into the createTetrahedronGeometry.js file:

  1. /*global define*/
  2. define([
  3. '../Core/TetrahedronGeometry',
  4. '../Scene/PrimitivePipeline',
  5. './createTaskProcessorWorker'
  6. ], function(
  7. TetrahedronGeometry,
  8. PrimitivePipeline,
  9. createTaskProcessorWorker) {
  10. "use strict";
  11.  
  12. function createTetrahedronGeometry(parameters, transferableObjects) {
  13. var geometry = TetrahedronGeometry.createGeometry();
  14. PrimitivePipeline.transferGeometry(geometry, transferableObjects);
  15.  
  16. return {
  17. geometry : geometry,
  18. index : parameters.index
  19. };
  20. }
  21.  
  22. return createTaskProcessorWorker(createTetrahedronGeometry);
  23. });

Now we're going to modify TetrahedronGeometry.js. We don't want the computation of positions and indices to happen until TetrahedronGeometry.computeGeometry is called. Change the current TetrahedronGeometry constructor to:

  1. TetrahedronGeometry.createGeometry = function() {
  2. ...
  3. };

This function is going to return a Geometry. Replace the last four lines of the function (this.attributes = attributes;....) with

  1. return new Geometry({
  2. attributes : attributes,
  3. indices : indices,
  4. primitiveType : PrimitiveType.TRIANGLES,
  5. boundingSphere : new BoundingSphere(new Cartesian3(0.0, 0.0, 0.0), 1.0)
  6. });

The next step is to introduce a new constructor. Add the following code:

  1. var TetrahedronGeometry = function() {
  2. this._workerName = 'createTetrahedronGeometry';
  3. };

With these changes, we can generate the tetrahedron asynchronously using the same syntax we were using before. We also have the option to generate it synchronously by calling TetrahedronGeometry.createGeometry from the code.

Geometry and Appearances【转】的更多相关文章

  1. Cesium中级教程7 - Geometry and Appearances 几何图形和外观

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ 本教程将向您介绍提供使用Primitive API的几何图形和外 ...

  2. Cesium学习笔记(六):几何和外观(Geometry and Appearances)【转】

    https://blog.csdn.net/UmGsoil/article/details/74912638 我们先直接来看一个例子 var viewer = new Cesium.Viewer('c ...

  3. Cesium官方教程8-- 几何体和外观效果

    原文地址:https://cesiumjs.org/tutorials/Geometry-and-Appearances/ 几何体和外观效果(Geometry and Appearances) 这篇教 ...

  4. Cesium中级教程4 - 空间数据可视化(二)

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ Viewer中的Entity功能 让我们看看Viewer为操作e ...

  5. CSharpGL(14)用geometry shader渲染模型的法线(normal)

    +BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(14)用geometry shader渲染模型的法线(normal) +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 ...

  6. the operation was attempted on an empty geometry Arcgis Project异常

    处理gis数据,投影变换时出现异常: the operation was attempted on an empty geometry 解决思路: arcgis的repair geometry方法:删 ...

  7. Topology and Geometry in OpenCascade-Adapters

    Topology and Geometry in OpenCascade-Adapters eryar@163.com 摘要Abstract:本文简要介绍了适配器模式(adapter pattern) ...

  8. HDU1086You can Solve a Geometry Problem too(判断线段相交)

    You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3 ...

  9. <<Differential Geometry of Curves and Surfaces>>笔记

    <Differential Geometry of Curves and Surfaces> by Manfredo P. do Carmo real line Rinterval I== ...

随机推荐

  1. 如何使用adb工具在电脑上使用程序的方式操控自己的android手机

    在电脑安装adb工具: sudo apt install android-tools-adb android-tools-fastboot# 检查是否成功adb version 开启adb服务 sud ...

  2. Linux下MySQL的数据文件存放在哪里的??

    http://bbs.csdn.net/topics/390620630 mysql> show variables like '%dir%';+------------------------ ...

  3. SQL SERVER-3种连接

    Nested Loops Join Merge Join Hash Join

  4. c# 写入文本文件

  5. 使用Cloudera Manager搭建Kudu环境

    使用Cloudera Manager搭建Kudu环境 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 1>.点击添加服务进入CM服务安装向导 2>.选择需要安装的kudu ...

  6. HTML&CSS基础-外边框

    HTML&CSS基础-外边框  作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.HTML <!DOCTYPE html> <html> <h ...

  7. python高级特性-迭代

    概述 for  v   in d.values(): for k,v  in d.items(): for  a    in 'adfa': #判断对象是否可迭代 from collections i ...

  8. Nginx一个server配置多个location(使用alias)

    公司测试环境使用nginx部署多个前端项目.网上查到了两个办法: 在配置文件中增加多个location,每个location对应一个项目比如使用80端口,location / 访问官网: locati ...

  9. 团队协作editconfig与eslint

    editconfig root = true [*] charset = utf-8 indent_style = space indent_size = 2 end_of_line = lf ins ...

  10. Django --- ajax结合sweetalert使用,分页器,bulk_create批量创建数据

    目录 ajax结合sweetalert使用 bulk_create批量插入数据 分页器的使用 ajax结合sweetalert使用 ajax可以在不刷新页面的情况下与后端进行交互,在对数据进行操作的时 ...