Skip to content

Commit

Permalink
Merge pull request #3048 from lilleyse/instancing
Browse files Browse the repository at this point in the history
Instancing
  • Loading branch information
pjcozzi committed Sep 28, 2015
2 parents bcbdc7a + d25a126 commit 37949ed
Show file tree
Hide file tree
Showing 13 changed files with 891 additions and 137 deletions.
201 changes: 201 additions & 0 deletions Apps/Sandcastle/gallery/development/Billboards Instancing.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
<!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="Clamp billboards to terrain.">
<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 id="terrainMenu"></div>
<div id="zoomButtons"></div>
<div id="toggleLighting"></div>
<div id="sampleButtons"></div>
</div>
<script id="cesium_sandcastle_script">
function startup(Cesium) {
"use strict";
//Sandcastle_Begin
var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
var context = scene.context;

var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
url : '//assets.agi.com/stk-terrain/world'
});

viewer.terrainProvider = cesiumTerrainProviderMeshes;
scene.debugShowFramesPerSecond = true;

var ellipsoid = scene.globe.ellipsoid;
var billboardCollection;
var instancingEnabled = true;
var instancedArraysExtension = context._instancedArrays;
var billboardCount = 100489;
var scale = 1.0;

// seneca
var centerLongitude = -1.385205433269729;
var centerLatitude = 0.6777926580888163;
var rectangleHalfSize = 0.5;
var e = new Cesium.Rectangle(centerLongitude - rectangleHalfSize, centerLatitude - rectangleHalfSize, centerLongitude + rectangleHalfSize, centerLatitude + rectangleHalfSize);

function resetBillboardCollection() {
if (Cesium.defined(billboardCollection)) {
scene.primitives.remove(billboardCollection);
}

billboardCollection = scene.primitives.add(new Cesium.BillboardCollection({
scene : scene
}));

var gridSize = Math.sqrt(billboardCount);
for (var y = 0; y < gridSize; ++y) {
for (var x = 0; x < gridSize; ++x) {
var longitude = Cesium.Math.lerp(e.west, e.east, x / (gridSize - 1));
var latitude = Cesium.Math.lerp(e.south, e.north, y / (gridSize - 1));
var position = new Cesium.Cartographic(longitude, latitude, 10000.0);

billboardCollection.add({
position : ellipsoid.cartographicToCartesian(position),
image : '../images/facility.gif',
scale : scale
});
}
}
}

var moveAmount = new Cesium.Cartesian3(1000, 0.0, 0.0);
var positionScratch = new Cesium.Cartesian3();
function animateBillboards() {
var billboards = billboardCollection._billboards;
var length = billboards.length;
for (var i = 0; i < length; ++i) {
var billboard = billboards[i];
Cesium.Cartesian3.clone(billboard.position, positionScratch);
Cesium.Cartesian3.add(positionScratch, moveAmount, positionScratch);
billboard.position = positionScratch;
}
}

Sandcastle.addToolbarMenu([ {
text : 'Instancing Enabled',
onselect : function() {
if (!instancingEnabled) {
context._instancedArrays = instancedArraysExtension;
instancingEnabled = true;
resetBillboardCollection();
}
}
}, {
text : 'Instancing Disabled',
onselect : function() {
if (instancingEnabled) {
context._instancedArrays = undefined;
instancingEnabled = false;
resetBillboardCollection();
}
}
}]);

Sandcastle.addToolbarMenu([ {
text : '100489 billboards',
onselect : function() {
billboardCount = 100489;
resetBillboardCollection();
}
}, {
text : '10000 billboards',
onselect : function() {
billboardCount = 10000;
resetBillboardCollection();
}
}, {
text : '1024 billboards',
onselect : function() {
billboardCount = 1024;
resetBillboardCollection();
}
}, {
text : '100 billboards',
onselect : function() {
billboardCount = 100;
resetBillboardCollection();
}
}, {
text : '25 billboards',
onselect : function() {
billboardCount = 25;
resetBillboardCollection();
}
}, {
text : '4 billboard',
onselect : function() {
billboardCount = 4;
resetBillboardCollection();
}
}]);

Sandcastle.addToolbarMenu([ {
text : 'Static billboards',
onselect : function() {
resetBillboardCollection();
scene.preRender.removeEventListener(animateBillboards);
}
}, {
text : 'Animated billboards',
onselect : function() {
resetBillboardCollection();
scene.preRender.addEventListener(animateBillboards);
}
}]);

Sandcastle.addToolbarMenu([ {
text : 'Scale : 1.0',
onselect : function() {
scale = 1.0;
resetBillboardCollection();
}
}, {
text : 'Scale : 0.5',
onselect : function() {
scale = 0.5;
resetBillboardCollection();
}
}, {
text : 'Scale : 0.1',
onselect : function() {
scale = 0.1;
resetBillboardCollection();
}
}]);

resetBillboardCollection();

//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.
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Change Log
==========

### 1.15 - 2015-11-02
* Breaking changes
* ...
* Deprecated
* ...
* Adding instancing support via the ANGLE_instanced_arrays extension. Using instancing in `BillboardCollection` and the new `ModelInstanceCollection` primitive.


### 1.14 - 2015-10-01

* Breaking changes
Expand Down
46 changes: 42 additions & 4 deletions Source/Renderer/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ define([

this._vertexArrayObject = getExtension(gl, ['OES_vertex_array_object']);
this._fragDepth = getExtension(gl, ['EXT_frag_depth']);
this._instancedArrays = getExtension(gl, ['ANGLE_instanced_arrays']);

this._drawBuffers = getExtension(gl, ['WEBGL_draw_buffers']);
ContextLimits._maximumDrawBuffers = defined(this._drawBuffers) ? gl.getParameter(this._drawBuffers.MAX_DRAW_BUFFERS_WEBGL) : 1;
Expand Down Expand Up @@ -307,6 +308,13 @@ define([
this._currentFramebuffer = undefined;
this._maxFrameTextureUnitIndex = 0;

// Vertex attribute divisor state cache. Workaround for ANGLE (also look at VertexArray.setVertexAttribDivisor)
this._vertexAttribDivisors = [];
this._previousDrawInstanced = false;
for (var i = 0; i < ContextLimits._maximumVertexAttributes; i++) {
this._vertexAttribDivisors.push(0);
}

this._pickObjects = {};
this._nextPickColor = new Uint32Array(1);

Expand Down Expand Up @@ -544,6 +552,19 @@ define([
}
},

/**
* <code>true</code> if the ANGLE_instanced_arrays extension is supported. This
* extension provides access to instanced rendering.
* @memberof Context.prototype
* @type {Boolean}
* @see {@link https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays}
*/
instancedArrays : {
get : function() {
return !!this._instancedArrays;
}
},

/**
* <code>true</code> if the WEBGL_draw_buffers extension is supported. This
* extensions provides support for multiple render targets. The framebuffer object can have mutiple
Expand Down Expand Up @@ -807,6 +828,7 @@ define([
var va = drawCommand.vertexArray;
var offset = drawCommand.offset;
var count = drawCommand.count;
var instanceCount = drawCommand.instanceCount;

//>>includeStart('debug', pragmas.debug);
if (!PrimitiveType.validate(primitiveType)) {
Expand All @@ -818,11 +840,19 @@ define([
}

if (offset < 0) {
throw new DeveloperError('drawCommand.offset must be omitted or greater than or equal to zero.');
throw new DeveloperError('drawCommand.offset must be greater than or equal to zero.');
}

if (count < 0) {
throw new DeveloperError('drawCommand.count must be omitted or greater than or equal to zero.');
throw new DeveloperError('drawCommand.count must be greater than or equal to zero.');
}

if (instanceCount < 0) {
throw new DeveloperError('drawCommand.instanceCount must be greater than or equal to zero.');
}

if (instanceCount > 0 && !context.instancedArrays) {
throw new DeveloperError('Instanced arrays extension is not supported');
}
//>>includeEnd('debug');

Expand All @@ -836,10 +866,18 @@ define([
if (defined(indexBuffer)) {
offset = offset * indexBuffer.bytesPerIndex; // offset in vertices to offset in bytes
count = defaultValue(count, indexBuffer.numberOfIndices);
context._gl.drawElements(primitiveType, count, indexBuffer.indexDatatype, offset);
if (instanceCount === 0) {
context._gl.drawElements(primitiveType, count, indexBuffer.indexDatatype, offset);
} else {
context._instancedArrays.drawElementsInstancedANGLE(primitiveType, count, indexBuffer.indexDatatype, offset, instanceCount);
}
} else {
count = defaultValue(count, va.numberOfVertices);
context._gl.drawArrays(primitiveType, offset, count);
if (instanceCount === 0) {
context._gl.drawArrays(primitiveType, offset, count);
} else {
context._instancedArrays.drawArraysInstancedANGLE(primitiveType, offset, count, instanceCount);
}
}

va._unBind();
Expand Down
8 changes: 8 additions & 0 deletions Source/Renderer/DrawCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ define([
*/
this.offset = defaultValue(options.offset, 0);

/**
* The number of instances to draw.
*
* @type {Number}
* @default 1
*/
this.instanceCount = defaultValue(options.instanceCount, 0);

/**
* The shader program to apply.
*
Expand Down
Loading

0 comments on commit 37949ed

Please sign in to comment.