Tile mesh manipulation

454 views
Skip to first unread message

Xavier Tassin

unread,
Nov 9, 2017, 4:05:02 AM11/9/17
to cesium-dev
Hi,

I am looking for a way to smooth and/or flatten certain portion of the terrain at run-time.

Ideally, I would pick up a tile and update its mesh but I am not sure this can be done directly. 

The other option would be to generate terrain data and replace some tiles on the fly.

Could someone give me few pointers on how this could be done?

Many thanks,

Xavier


Gabby Getz

unread,
Nov 13, 2017, 6:25:31 PM11/13/17
to cesium-dev
Hey Xavier,

With the way you load terrain in Cesium normally, I don't think this is possible. Normally, you would create a TerrainProvider and point it at a server url with processed terrain tiles.

However, you may be able to accomplish what you are looking to do by loading in a 3D model. You would need to load a copy of the mesh of the current tile, then somehow send that new mesh back to the server and have it update the tile. 

Definitely an interesting problem, let us know if you find a good solution!
Thanks,
Gabby

--
You received this message because you are subscribed to the Google Groups "cesium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Poul Sørensen

unread,
Nov 14, 2017, 5:56:10 AM11/14/17
to cesium-dev
How can 3d models be used for terrain?

I am interested in a solution for the original question aswell, just dont see how 3d models can solve this?

To generalize the question abit into a subset of questions that might help solve this.

1) If we create a wrapper terrain provider that wraps the normal mesh provider, do libraries exists (or where in cesiumjs is the code located that reads the mesh tiles) such we may call the base terrain provider, alter the terrain mesh tile before passing it on to cesium.
2) Is it possible to reload a specific tile on a terrain provider without reloading everyhing?

If we can answer those two questions, we should be able to code a solution that allows to fill in soil or remove soil from a terrain solution in real time without sending to backend to compute?
To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+...@googlegroups.com.

Xavier Tassin

unread,
Nov 14, 2017, 10:21:11 AM11/14/17
to cesium-dev
I believe it is possible to get mesh data for a specific tile, manipulate it and generate a new tile using Cesium.HeightmapTerrainData

I am just not quite sur how to put this all together. This github issue is mentioning the process as I believe it should work:


Anybody able to fill in the blanks?

Cheers,

Xavier.

Gabby Getz

unread,
Nov 16, 2017, 4:31:01 PM11/16/17
to cesium-dev
You would not use the 3d model as a terrain provider, rather you would just add the model to the scene at your intended position. See the models tutorial for more info. 

Aha, thanks Xavier. It looks like you can manipulate the mesh verticies using HeightMapTerrainData. However, you're terrain data would need to be in the heightmap format initially and you can manipulate the height values.

To unsubscribe from this group and stop receiving emails from it, send an email to cesium-dev+unsubscribe@googlegroups.com.

Xavier Tassin

unread,
Nov 25, 2017, 11:40:23 AM11/25/17
to cesium-dev
Hi,

Following up on this topic.

With the great help of "slozier" in the mentioned Github issue, who shared a code example with me, I built a wrapper around the default CesiumTerrainProvider.

The wrapper test tiles for intersection (when requestTileGeometry is called) with a defined rectangle region and if matching returns a custom promise.

That promise generates a new tile using HeightmapTerrainData.

This works perfectly and generates valid mesh that renders fine in the viewer.

However, I can see artefacts in the form of flickering imagery tiles: they turn dark and normal again depending on camera movement or Sun position (see screenshot). Also, the issue is only visible when terrain provider is constructed with requestWaterMask=true.

Which leads me to think that vertex normals are not created properly by the HeightmapTerrainData method.

Any idea on that I am doing wrong?


Finally, I also tried to generate Quantized mesh instead but could not get the tiles to display (just get a hole instead)

Here the code I use - anything blatantly wrong in there?

var tileRect = this.baseProvider.tilingScheme.tileXYToRectangle(x, y, level);
var tileCenter = new Cesium.Cartesian3(tileRect.west + tileRect.width / 2, tileRect.north + tileRect.height / 2, height);

var data = new Cesium.QuantizedMeshTerrainData({
minimumHeight : height,
maximumHeight : height,
quantizedVertices : new Uint16Array([// order is SW NW SE NE
// longitude
0, 0, 32767, 32767,
// latitude
0, 32767, 0, 32767,
// heights
0, 0, 0, 0]),
indices : new Uint16Array([0, 3, 1,
0, 2, 3]),
boundingSphere : new Cesium.BoundingSphere(tileCenter, 100000),
orientedBoundingBox : new Cesium.OrientedBoundingBox(tileCenter, Cesium.Matrix3.fromRotationX(Cesium.Math.PI, new Cesium.Matrix3())),
horizonOcclusionPoint : tileCenter,
westIndices : [0, 1],
southIndices : [0, 2],
eastIndices : [2, 3],
northIndices : [1, 3],
westSkirtHeight : 1.0,
southSkirtHeight : 1.0,
eastSkirtHeight : 1.0,
northSkirtHeight : 1.0,

childTileMask: 0
});

Cheers,

Xavier.

Poul Sørensen

unread,
Nov 26, 2017, 12:57:42 PM11/26/17
to cesium-dev
Is the code on github ? then I could also play around and see if I could get it working and solve the issues you mention

Xavier Tassin

unread,
Nov 27, 2017, 8:29:40 AM11/27/17
to cesiu...@googlegroups.com
Hi,
Here is my (very crude) test terrain provider. It flattens a piece of terrain (0 alt) near London Hearthrow airport.
Artefact becomes visible when getting close to the ground.

var FlatTerrainProvider = function(options) {
this.baseProvider = new Cesium.CesiumTerrainProvider(options);

this.setRegion(51.46491,-0.44692); // London Heathrow
};

FlatTerrainProvider.prototype = {

get availability() {
return this.baseProvider.availability;
},
get credit() {
return this.baseProvider.credit;
},
get errorEvent() {
return this.baseProvider.errorEvent;
},
get hasVertexNormals() {
return this.baseProvider.hasVertexNormals;
},
get hasWaterMask() {
return this.baseProvider.hasWaterMask;
},
get ready() {
return this.baseProvider.ready;
},
get readyPromise() {
return this.baseProvider.readyPromise;
},
get tilingScheme() {
return this.baseProvider.tilingScheme;
},
getLevelMaximumGeometricError: function(level) {
return this.baseProvider.getLevelMaximumGeometricError(level);
},
getTileDataAvailable: function(x, y, level) {
return this.baseProvider.getTileDataAvailable(x, y, level);
},
setRegion: function(lat, lon) {
this.region = Cesium.Rectangle.fromDegrees(lon - 0.02, lat - 0.02, lon + 0.02, lat + 0.02);
},

requestTileGeometry: function(x, y, level, request) {
var t00 = this.baseProvider.getTileDataAvailable(x * 2, y * 2, level + 1);
var t01 = this.baseProvider.getTileDataAvailable(x * 2, y * 2 + 1, level + 1);
var t10 = this.baseProvider.getTileDataAvailable(x * 2 + 1, y * 2, level + 1);
var t11 = this.baseProvider.getTileDataAvailable(x * 2 + 1, y * 2 + 1, level + 1);

if (level > 13 || !(t00 && t01 && t10 && t11)) {
var size =
2;
var tileRect = this.baseProvider.tilingScheme.tileXYToRectangle(x, y, level);
var widthBuffer = 2 * tileRect.width / (size - 1);
var heightBuffer = 2 * tileRect.height / (size - 1);
var union = Cesium.Rectangle;

var regionRect = new Cesium.Rectangle(this.region.west - widthBuffer, this.region.south - heightBuffer, this.region.east + widthBuffer, this.region.north + heightBuffer);
var intersection = Cesium.Rectangle.intersection(regionRect, tileRect);
if (intersection !== undefined) {
var promise = this.baseProvider.requestTileGeometry(x, y, level, request);
if (promise === undefined) return undefined;
return this.getPromise(promise, size, tileRect, intersection);
}
}

return this.baseProvider.requestTileGeometry(x, y, level, request);
},

getPromise:
function(promise, size, tileRect, intersection) {

if (promise === undefined) return undefined;

var height = 0;

return promise.then((terrainData) => {

var size = 2;
var heights = new Float32Array(size * size);
for (var i = 0; i < size; i++) {
for (var j = 0; j < size; j++) {
heights[i * size + j] = height;
}
}

var childTileMask = 0;

return new Cesium.HeightmapTerrainData({ buffer: heights, width: size, height: size, childTileMask: childTileMask });
});
}
};

--
You received this message because you are subscribed to a topic in the Google Groups "cesium-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/cesium-dev/rIqkdrkhZMk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to cesium-dev+unsubscribe@googlegroups.com.

Xavier Tassin

unread,
Dec 1, 2017, 8:31:39 AM12/1/17
to cesium-dev
By the way, there is a mistake in the QuantizedMeshTerrainData documentation example: it sates southIndices : [0, 1] where it should be southIndices : [0, 2]

So, nobody has any idea why vertex normals are messed up after using HeightmapTerrainData?

Cheers,

Xavier.
Reply all
Reply to author
Forward
0 new messages