If you’re having issues with draping your data on a 3D Tiles mesh, check the following:
-
Does your 3D Tiles layer (
TileSet3DLayer
) haveisDrapeTarget
set totrue
? -
Does the data you want to drape have the correct
DrapeTarget
?
See Draping on 3D tiles for details.
If you fulfilled both conditions, and you still don’t see your data being draped, check if it’s a RasterLayer
and if it’s the bottom-most layer in the layer tree. In that case, you must apply a workaround to drape your raster layer.
Limitation of draping the bottom-most raster layer on 3D tiles
Even though you set layer.rasterStyle.drapeTarget
to DrapeTarget.MESH
or DrapeTarget.ALL
,
and you set tileset3DLayer.isDrapeTarget
to true
, you still don’t see the raster data draped on the mesh.
Cause
Due to a technical limitation, you can’t drape the bottom-most RasterLayer
in the layer tree on a 3D Tiles mesh.
Workaround
As a workaround, you can add another "dummy" RasterLayer
beneath the layer you want to drape.
As a result, the layer you want to drape isn’t the bottom-most raster layer in the layer tree anymore. It then gets draped
correctly on 3D Tiles.
import {Map} from "@luciad/ria/view/Map.js";
import {createHereMapsTileSetModel} from "@luciad/ria/model/tileset/HereMapsTileSetModel.js";
import {RasterTileSetLayer} from "@luciad/ria/view/tileset/RasterTileSetLayer.js";
import {DrapeTarget} from "@luciad/ria/view/style/DrapeTarget.js";
import {TileSet3DLayer} from "@luciad/ria/view/tileset/TileSet3DLayer.js";
import {OGC3DTilesModel} from "@luciad/ria/model/tileset/OGC3DTilesModel.js";
import {RasterTileSetModel} from "@luciad/ria/model/tileset/RasterTileSetModel.js";
import {TileCoordinate} from "@luciad/ria/model/tileset/TileCoordinate.js";
import {getReference} from "@luciad/ria/reference/ReferenceProvider.js";
import {createBounds} from "@luciad/ria/shape/ShapeFactory.js";
import {RasterDataType} from "@luciad/ria/model/tileset/RasterDataType.js";
async function addMapLayers(map: Map) {
const dummyRasterLayer = createDummyRasterLayer();
map.layerTree.addChild(dummyRasterLayer, "bottom")
const drapedHereMapsLayer = await createHereMapsLayer();
map.layerTree.addChild(drapedHereMapsLayer, "above", dummyRasterLayer);
const meshLayer = await create3DTilesMeshLayer();
map.layerTree.addChild(meshLayer, "above", drapedHereMapsLayer);
}
function createDummyRasterLayer(): RasterTileSetLayer {
const model = new DummyRasterTileSetModel();
return new RasterTileSetLayer(model, {
label: "Dummy raster layer"
});
}
class DummyRasterTileSetModel extends RasterTileSetModel {
private _image: HTMLImageElement;
constructor(color: string = "rgb(255, 255, 255)") {
const epsg4326 = getReference("EPSG:4326");
super({
reference: epsg4326,
bounds: createBounds(epsg4326, [-180, 360, -90, 180]),
levelCount: 19,
tileWidth: 256,
tileHeight: 256,
level0Rows: 1,
level0Columns: 1,
dataType: RasterDataType.IMAGE
});
const canvas = document.createElement("canvas");
canvas.width = 256;
canvas.height = 256;
const ctx = canvas.getContext("2d")!;
ctx.fillStyle = color;
ctx.fillRect(0, 0, canvas.height, canvas.width);
this._image = document.createElement('img');
this._image.src = canvas.toDataURL("image/png");
}
getImage(tile: TileCoordinate, onSuccess: (tile: TileCoordinate, image: HTMLImageElement) => void,
onError: (tile: TileCoordinate, error?: any) => void): void {
onSuccess(tile, this._image);
}
}
async function createHereMapsLayer(): Promise<RasterTileSetLayer> {
const model = await createHereMapsTileSetModel({
apiKey: "CENSORED",
base: "aerial",
type: "maptile",
scheme: "satellite.day"
});
const layer = new RasterTileSetLayer(model, {
label: "HERE Maps",
});
layer.rasterStyle.drapeTarget = DrapeTarget.MESH;
return layer;
}
async function create3DTilesMeshLayer(): Promise<TileSet3DLayer> {
const model = await OGC3DTilesModel.create(
"https://sampleservices.luciad.com/ogc/3dtiles/marseille-mesh/tileset.json");
return new TileSet3DLayer(model, {
qualityFactor: 0.8,
label: "OGC 3D Tiles Mesh",
isDrapeTarget: true,
isPartOfTerrain: false,
drapeSlopeAngle: 60
});
}