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

Instancing models 3d tiles #3059

Merged
merged 28 commits into from
Oct 24, 2015
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3415df3
Added Model instancing
lilleyse Sep 28, 2015
aecfb3c
Whitespace
pjcozzi Sep 28, 2015
37276da
Whitespace
pjcozzi Sep 28, 2015
5bab8d6
Whitespace
pjcozzi Sep 28, 2015
a65a038
Tweak doc
pjcozzi Sep 28, 2015
a5add4e
Fixed jittering by rendering relative to bounding volume
lilleyse Sep 28, 2015
791a555
Moved all instancing code into ModelInstanceCollection
lilleyse Sep 29, 2015
b938c61
Small fix
lilleyse Sep 30, 2015
33c4acd
Tweak comment
pjcozzi Sep 30, 2015
02781ce
Style tweak
pjcozzi Sep 30, 2015
12904b8
Style tweak
pjcozzi Sep 30, 2015
a416ee8
Style tweak
pjcozzi Sep 30, 2015
4f14143
Updated model instancing Sandcastle demo
lilleyse Sep 30, 2015
b48b4f2
Minor fixes
lilleyse Sep 30, 2015
b820a55
Rendering show and color using instanced attributes for now
lilleyse Oct 2, 2015
13d14c0
Support color and show when instancing is disabled
lilleyse Oct 4, 2015
77b2547
Instancing using batch texture
lilleyse Oct 5, 2015
61d5607
Merge branch 'instancing-models' into 3d-tiles
lilleyse Oct 5, 2015
bab0ba9
Added instanced model 3d tile type
lilleyse Oct 5, 2015
d5ce3b2
Model instancing optimizations and cleanup
lilleyse Oct 6, 2015
88efe56
Tweak comment
pjcozzi Oct 14, 2015
be59252
Removed Instancing 3D Tiles demo, using Cities instead
lilleyse Oct 20, 2015
bc10897
Prevent instance collections from sharing the same Model
lilleyse Oct 20, 2015
948ad72
Reverted previous commit, now share the same Model but create unique …
lilleyse Oct 21, 2015
69b858d
Fixed memory leak in non-instanced code path
lilleyse Oct 23, 2015
9ae609d
Renamed Cesium3dTileBatchTable to Cesium3DTileBatchTableResources to …
lilleyse Oct 23, 2015
a49b6fd
Removed baseUrl from Cesium3DTileset
lilleyse Oct 23, 2015
e19f70a
Small change
lilleyse Oct 23, 2015
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<!DOCTYPE html>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just use the cities.html example for this? Just point it to a tiles.json with i3dm tiles?

<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <!-- Use Chrome Frame in IE -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Create 3D models using glTF.">
<meta name="cesium-sandcastle-labels" content="Development">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.9/require.js"></script>
<script type="text/javascript">
require.config({
baseUrl : '../../../Source',
waitSeconds : 60
});
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar"></div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
"use strict";
//Sandcastle_Begin

var globeVisible = true;

var viewer = new Cesium.Viewer('cesiumContainer', {
globe : globeVisible ? undefined : false,
skyAtmosphere : globeVisible ? undefined : false
});

var scene = viewer.scene;
var camera = viewer.camera;

function orientCamera(center, radius) {
var controller = scene.screenSpaceCameraController;
var r = Math.max(radius, camera.frustum.near);
controller.minimumZoomDistance = r * 0.5;
var heading = Cesium.Math.toRadians(230.0);
var pitch = Cesium.Math.toRadians(-20.0);
camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, r * 2.0));
}

function loadInstanced3DTile() {
var city = scene.primitives.add(new Cesium.Cesium3DTileset({
url : 'http://localhost:8002/tilesets/trees'
}));

city.readyPromise.then(function() {
city.debugShowBox = true;
}).otherwise(function(error) {
window.alert(error);
});

orientCamera(Cesium.Cartesian3.fromRadians(-1.2911323805815227, 0.7097150757974291), 10.0);
}

loadInstanced3DTile();

//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
265 changes: 265 additions & 0 deletions Apps/Sandcastle/gallery/development/3D Models Instancing.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1"> <!-- Use Chrome Frame in IE -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Create 3D models using glTF.">
<meta name="cesium-sandcastle-labels" content="Development">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Sandcastle-header.js"></script>
<script type="text/javascript" src="../../../ThirdParty/requirejs-2.1.9/require.js"></script>
<script type="text/javascript">
require.config({
baseUrl : '../../../Source',
waitSeconds : 60
});
</script>
</head>
<body class="sandcastle-loading" data-sandcastle-bucket="bucket-requirejs.html">
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar"></div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
"use strict";
//Sandcastle_Begin

var debugShowBoundingVolume = false;
var debugWireframe = false;
var globeVisible = true;

var viewer = new Cesium.Viewer('cesiumContainer', {
globe : globeVisible ? undefined : false,
skyAtmosphere : globeVisible ? undefined : false
});

var scene = viewer.scene;
var context = scene.context;
var camera = viewer.camera;
scene.debugShowFramesPerSecond = true;

var instancedArraysExtension = context._instancedArrays;
var count = 1024;
var spacing = 0.0002;
var url = '../../SampleData/models/CesiumAir/Cesium_Air.bgltf';
var dynamic = false;
var useCollection = true;

var centerLongitude = -123.0744619;
var centerLatitude = 44.0503706;
var height = 5000.0;

function orientCamera(center, radius) {
var controller = scene.screenSpaceCameraController;
var r = Math.max(radius, camera.frustum.near);
controller.minimumZoomDistance = r * 0.5;

var heading = Cesium.Math.toRadians(230.0);
var pitch = Cesium.Math.toRadians(-20.0);
camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, r * 2.0));
}

function createCollection(instances) {
var collection = scene.primitives.add(new Cesium.ModelInstanceCollection({
url : url,
instances : instances,
dynamic : dynamic,
debugShowBoundingVolume : debugShowBoundingVolume,
debugWireframe : debugWireframe
}));

collection.readyPromise.then(function(collection) {
// Play and loop all animations at half-speed
collection.activeAnimations.addAll({
speedup : 0.5,
loop : Cesium.ModelAnimationLoop.REPEAT
});
orientCamera(collection._boundingVolume.center, collection._boundingVolume.radius);
}).otherwise(function(error){
window.alert(error);
});
}

function createModels(instances) {
var points = [];
var model;

var length = instances.length;
for (var i = 0; i < length; ++i) {
var instance = instances[i];
var modelMatrix = instance.modelMatrix;
var translation = new Cesium.Cartesian3();
Cesium.Matrix4.getTranslation(modelMatrix, translation);
points.push(translation);

model = scene.primitives.add(Cesium.Model.fromGltf({
url : url,
modelMatrix : modelMatrix,
debugShowBoundingVolume : debugShowBoundingVolume,
debugWireframe : debugWireframe
}));

model.readyPromise.then(function(model) {
// Play and loop all animations at half-speed
model.activeAnimations.addAll({
speedup : 0.5,
loop : Cesium.ModelAnimationLoop.REPEAT
});
}).otherwise(function(error){
window.alert(error);
});
}

model.readyPromise.then(function(model) {
var boundingSphere = new Cesium.BoundingSphere();
Cesium.BoundingSphere.fromPoints(points, boundingSphere);
orientCamera(boundingSphere.center, boundingSphere.radius + model.boundingSphere.radius);
});
}

function reset() {
scene.primitives.removeAll();
var instances = [];
var gridSize = Math.sqrt(count);

for (var y = 0; y < gridSize; ++y) {
for (var x = 0; x < gridSize; ++x) {
var longitude = centerLongitude + spacing * (x - gridSize/2);
var latitude = centerLatitude + spacing * (y - gridSize/2);
var position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);

var heading = Math.random();
var pitch = Math.random();
var roll = Math.random();
var scale = (Math.random() + 1.0)/2.0;
var color = Cesium.Color.fromRandom();
var show = (Math.random() > 0.5);

var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, heading, pitch, roll);
Cesium.Matrix4.multiplyByUniformScale(modelMatrix, scale, modelMatrix);

instances.push({
modelMatrix : modelMatrix,
color : color,
show : show
});
}
}

useCollection ? createCollection(instances) : createModels(instances);
}

Sandcastle.addToolbarMenu([ {
text : '1024 instances',
onselect : function() {
count = 1024;
reset();
}
}, {
text : '100 instances',
onselect : function() {
count = 100;
reset();
}
}, {
text : '25 instances',
onselect : function() {
count = 25;
reset();
}
}, {
text : '4 instances',
onselect : function() {
count = 4;
reset();
}
}, {
text : '10000 instances',
onselect : function() {
count = 10000;
reset();
}
}]);

Sandcastle.addToolbarMenu([ {
text : 'Aircraft',
onselect : function() {
url = '../../SampleData/models/CesiumAir/Cesium_Air.bgltf';
spacing = 0.0002;
reset();
}
}, {
text : 'Ground vehicle',
onselect : function() {
url = '../../SampleData/models/CesiumGround/Cesium_Ground.bgltf';
spacing = 0.00008;
reset();
}
}, {
text : 'Milk truck',
onselect : function() {
url = '../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.bgltf';
spacing = 0.00008;
reset();
}
}, {
text : 'Skinned character',
onselect : function() {
url = '../../SampleData/models/CesiumMan/Cesium_Man.bgltf';
spacing = 0.00001;
reset();
}
}]);


Sandcastle.addToolbarMenu([ {
text : 'Instancing Enabled',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When instancing is disabled, I suspect we are allocating an array or something per frame since the garbage collector is at 21.7% in the profile.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lilleyse did you look at this performance issue? I do not want to merge this until we track it down.

onselect : function() {
context._instancedArrays = instancedArraysExtension;
useCollection = true;
reset();
}
}, {
text : 'Instancing Disabled',
onselect : function() {
context._instancedArrays = undefined;
useCollection = true;
reset();
}
}, {
text : 'Individual models',
onselect : function() {
useCollection = false;
reset();
}
}]);

Sandcastle.addToolbarMenu([ {
text : 'Static',
onselect : function() {
dynamic = false;
reset();
}
}, {
text : 'Dynamic',
onselect : function() {
dynamic = true;
reset();
}
}]);

//Sandcastle_End
Sandcastle.finishedLoading();
}
if (typeof Cesium !== "undefined") {
startup(Cesium);
} else if (typeof require === "function") {
require(["Cesium"], startup);
}
</script>
</body>
</html>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 6 additions & 4 deletions Source/Renderer/Buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ define([
'../Core/destroyObject',
'../Core/DeveloperError',
'../Core/IndexDatatype',
'./BufferUsage'
'./BufferUsage',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to get more 3D Tiles code into master sooner, can you open a separate pull request into master for these changes and the changes to ShaderProgram.js?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And maybe even the changes to ShaderSource.js (and code that uses it).

'./WebGLConstants'
], function(
defaultValue,
defined,
defineProperties,
destroyObject,
DeveloperError,
IndexDatatype,
BufferUsage) {
BufferUsage,
WebGLConstants) {
"use strict";

/**
Expand Down Expand Up @@ -123,7 +125,7 @@ define([

return new Buffer({
context: options.context,
bufferTarget: options.context._gl.ARRAY_BUFFER,
bufferTarget: WebGLConstants.ARRAY_BUFFER,
typedArray: options.typedArray,
sizeInBytes: options.sizeInBytes,
usage: options.usage
Expand Down Expand Up @@ -195,7 +197,7 @@ define([
var bytesPerIndex = IndexDatatype.getSizeInBytes(indexDatatype);
var buffer = new Buffer({
context : context,
bufferTarget : context._gl.ELEMENT_ARRAY_BUFFER,
bufferTarget : WebGLConstants.ELEMENT_ARRAY_BUFFER,
typedArray : options.typedArray,
sizeInBytes : options.sizeInBytes,
usage : options.usage
Expand Down
4 changes: 2 additions & 2 deletions Source/Renderer/ShaderProgram.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,9 @@ define([
for (j = 0; j < fragmentUniformsCount; j++) {
if (vertexShaderUniforms[i] === fragmentShaderUniforms[j]) {
uniformName = vertexShaderUniforms[i];
duplicateName = "czm_mediump_" + uniformName;
duplicateName = 'czm_mediump_' + uniformName;
// Update fragmentShaderText with renamed uniforms
var re = new RegExp(uniformName + "\\b", "g");
var re = new RegExp(uniformName + '\\b', 'g');
fragmentShaderText = fragmentShaderText.replace(re, duplicateName);
duplicateUniformNames[duplicateName] = uniformName;
}
Expand Down
Loading