Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create uniform buildings #159

Merged
merged 1 commit into from
Nov 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions samples-generator/bin/3d-tiles-samples-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ var promises = [
createTilesetReplacementWithViewerRequestVolume(),
createTilesetSubtreeExpiration(),
createTilesetPoints(),
createTilesetUniform(),
// Samples
createDiscreteLOD(),
createTreeBillboards(),
Expand Down Expand Up @@ -2307,6 +2308,144 @@ function createTilesetPoints() {
return Promise.all(promises);
}

function createTilesetUniform() {
var tilesetName = 'TilesetUniform';
var tilesetDirectory = path.join(outputDirectory, 'Tilesets', tilesetName);
var tilesetPath = path.join(tilesetDirectory, 'tileset.json');
var tileset2Path = path.join(tilesetDirectory, 'tileset2.json');

// Only subdivide the middle tile in level 1. Helps reduce tileset size.
var subdivideCallback = function(level, x, y) {
return level === 0 || (level === 1 && x === 1 && y === 1);
};

var results = createUniformTileset(3, 3, subdivideCallback);
var tileOptions = results.tileOptions;
var tileNames = results.tileNames;
var tilesetJson = results.tilesetJson;

// Insert an external tileset
var externalTile1 = clone(tilesetJson.root, true);
delete externalTile1.transform;
delete externalTile1.refine;
delete externalTile1.children;
externalTile1.content.uri = 'tileset2.json';

var externalTile2 = clone(tilesetJson.root, true);
delete externalTile2.transform;
delete externalTile2.refine;
delete externalTile2.content;

var tileset2Json = clone(tilesetJson, true);
tileset2Json.root = externalTile2;
tilesetJson.root.children = [externalTile1];

return saveTilesetFiles(tileOptions, tileNames, tilesetDirectory, tilesetPath, tilesetJson, true)
.then(function() {
saveTilesetJson(tileset2Path, tileset2Json, prettyJson);
});
}

function createUniformTileset(depth, divisions, subdivideCallback) {
depth = Math.max(depth, 1);
divisions = Math.max(divisions, 1);

var tileOptions = [];
var tileNames = [];

var tilesetJson = {
asset : {
version : versionNumber
},
properties : undefined,
geometricError : largeGeometricError
};

divideTile(0, 0, 0, divisions, depth, tilesetJson, tileOptions, tileNames, subdivideCallback);

return {
tilesetJson : tilesetJson,
tileOptions : tileOptions,
tileNames : tileNames
};
}

function divideTile(level, x, y, divisions, depth, parent, tileOptions, tileNames, subdivideCallback) {
var uri = level + '_' + x + '_' + y + '.b3dm';
var tilesPerAxis = Math.pow(divisions, level);

var buildingsLength = divisions * divisions;
var buildingsPerAxis = Math.sqrt(buildingsLength);

var tileWidthMeters = tileWidth / tilesPerAxis;
var tileLongitudeExtent = longitudeExtent / tilesPerAxis;
var tileLatitudeExtent = latitudeExtent / tilesPerAxis;
var tileHeightMeters = tileWidthMeters / (buildingsPerAxis * 3);

var xOffset = -tileWidth / 2.0 + (x + 0.5) * tileWidthMeters;
var yOffset = -tileWidth / 2.0 + (y + 0.5) * tileWidthMeters;
var transform = Matrix4.fromTranslation(new Cartesian3(xOffset, yOffset, 0));

var west = longitude - longitudeExtent / 2.0 + x * tileLongitudeExtent;
var south = latitude - latitudeExtent / 2.0 + y * tileLatitudeExtent;
var east = west + tileLongitudeExtent;
var north = south + tileLatitudeExtent;
var tileLongitude = west + (east - west) / 2.0;
var tileLatitude = south + (north - south) / 2.0;
var region = [west, south, east, north, 0, tileHeightMeters];

var isLeaf = (level === depth - 1);
var isRoot = (level === 0);
var subdivide = !isLeaf && (!defined(subdivideCallback) || subdivideCallback(level, x, y));
var geometricError = isLeaf ? 0.0 : largeGeometricError / Math.pow(2, level + 1);
var children = subdivide ? [] : undefined;

var tileJson = {
boundingVolume : {
region : region
},
geometricError : geometricError,
content : {
uri : uri
},
children : children
};

if (isRoot) {
parent.root = tileJson;
tileJson.transform = Matrix4.pack(buildingsTransform, new Array(16));
tileJson.refine = 'REPLACE';
} else {
parent.children.push(tileJson);
}

tileOptions.push({
buildingOptions : {
uniform : true,
numberOfBuildings : buildingsLength,
tileWidth : tileWidthMeters,
longitude : tileLongitude,
latitude : tileLatitude
},
createBatchTable : true,
transform : transform
});

tileNames.push(uri);

var nextLevel = level + 1;
var nextX = divisions * x;
var nextY = divisions * y;

if (subdivide) {
for (var i = 0; i < divisions; ++i) {
for (var j = 0; j < divisions; ++j) {
divideTile(nextLevel, nextX + i, nextY + j, divisions, depth, tileJson, tileOptions, tileNames, subdivideCallback);
}
}
}
}

function createDiscreteLOD() {
var glbPaths = ['data/dragon_high.glb', 'data/dragon_medium.glb', 'data/dragon_low.glb'];
var tileNames = ['dragon_high.b3dm', 'dragon_medium.b3dm', 'dragon_low.b3dm'];
Expand Down
81 changes: 70 additions & 11 deletions samples-generator/lib/createBuildings.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var redMaterial = new Material({
* Creates a set of buildings that will be converted to a b3dm tile.
*
* @param {Object} [options] Object with the following properties:
* @param {Boolean} [options.uniform=false] Whether to create uniformly sized and spaced buildings.
* @param {Number} [options.numberOfBuildings=10] The number of buildings to create.
* @param {Number} [options.tileWidth=200.0] The width of the tile in meters. Buildings are placed randomly in this area.
* @param {Number} [options.averageWidth=4.0] Average building width in meters around which random widths and depths are generated.
Expand All @@ -46,21 +47,79 @@ var redMaterial = new Material({
* @param {String} [options.translucencyType='opaque'] Specifies the type of translucency to apply to the tile. Possible values are 'opaque', 'translucent', 'mix'.
* @param {Number} [options.longitude=-1.31968] The center longitude of the tile. Used to generate metadata for the batch table.
* @param {Number} [options.latitude=0.698874] The center latitude of the tile. Used to generate metadata for the batch table.
* @param {Number} [options.seed=2] The random seed to use.
* @param {Number} [options.seed=11] The random seed to use.
*
* @returns {Building[]} An array of buildings.
*/
function createBuildings(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
var seed = defaultValue(options.seed, 11);
var numberOfBuildings = defaultValue(options.numberOfBuildings, 10);
var tileWidth = defaultValue(options.tileWidth, 200.0);
var averageWidth = defaultValue(options.averageWidth, 4.0);
var averageHeight = defaultValue(options.averageHeight, 5.0);
var baseColorType = defaultValue(options.baseColorType, 'white');
var translucencyType = defaultValue(options.translucencyType, 'opaque');
var centerLongitude = defaultValue(options.longitude, -1.31968);
var centerLatitude = defaultValue(options.latitude, 0.698874);
options = defaultValue(options, {});
options.seed = defaultValue(options.seed, 11);
options.numberOfBuildings = defaultValue(options.numberOfBuildings, 10);
options.tileWidth = defaultValue(options.tileWidth, 200.0);
options.averageWidth = defaultValue(options.averageWidth, 4.0);
options.averageHeight = defaultValue(options.averageHeight, 5.0);
options.baseColorType = defaultValue(options.baseColorType, 'white');
options.translucencyType = defaultValue(options.translucencyType, 'opaque');
options.longitude = defaultValue(options.longitude, -1.31968);
options.latitude = defaultValue(options.latitude, 0.698874);

if (options.uniform) {
return createUniformBuildings(options);
}
return createRandomBuildings(options);
}

function createUniformBuildings(options) {
var numberOfBuildings = options.numberOfBuildings;
var tileWidth = options.tileWidth;
var centerLongitude = options.longitude;
var centerLatitude = options.latitude;

var buildingsPerAxis = Math.sqrt(numberOfBuildings);
var buildingWidth = tileWidth / (buildingsPerAxis * 3);
var buildings = [];

for (var i = 0; i < buildingsPerAxis; ++i) {
for (var j = 0; j < buildingsPerAxis; ++j) {
var x = buildingWidth * 1.5 + i * buildingWidth * 3.0 - tileWidth / 2.0;
var y = buildingWidth * 1.5 + j * buildingWidth * 3.0 - tileWidth / 2.0;
var z = buildingWidth / 2.0;
var rangeX = x / tileWidth - 0.5;
var rangeY = y / tileWidth - 0.5;

var translation = Cartesian3.fromElements(x, y, z, scratchTranslation);
var rotation = Quaternion.clone(Quaternion.IDENTITY, scratchRotation);
var scale = Cartesian3.fromElements(buildingWidth, buildingWidth, buildingWidth, scratchScale);
var matrix = Matrix4.fromTranslationQuaternionRotationScale(translation, rotation, scale, new Matrix4());

var longitudeExtent = metersToLongitude(tileWidth, centerLatitude);
var latitudeExtent = metersToLatitude(tileWidth, centerLongitude);
var longitude = centerLongitude + rangeX * longitudeExtent;
var latitude = centerLatitude + rangeY * latitudeExtent;

buildings.push(new Building({
matrix : matrix,
material : whiteOpaqueMaterial,
longitude : longitude,
latitude : latitude,
height : buildingWidth
}));
}
}

return buildings;
}

function createRandomBuildings(options) {
var seed = options.seed;
var numberOfBuildings = options.numberOfBuildings;
var tileWidth = options.tileWidth;
var averageWidth = options.averageWidth;
var averageHeight = options.averageHeight;
var baseColorType = options.baseColorType;
var translucencyType = options.translucencyType;
var centerLongitude = options.longitude;
var centerLatitude = options.latitude;

// Set the random number seed before creating materials
CesiumMath.setRandomNumberSeed(seed);
Expand Down