forked from xeolabs/scenejs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial distance/proximity culling system
- Loading branch information
Showing
17 changed files
with
1,918 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
function ProximityEngine(cfg) { | ||
|
||
this._center = [0, 0, 0]; | ||
this._radii = [200, 700, 1200]; | ||
|
||
this._bodies = {}; | ||
this._bodyList = []; | ||
this._numBodies = 0; | ||
|
||
this._bodyListDirty = false; | ||
|
||
this._updatedBodies = []; | ||
|
||
if (cfg) { | ||
this.setConfigs(cfg); | ||
} | ||
} | ||
|
||
/** | ||
* Configure this proximity engine | ||
* @param cfg | ||
*/ | ||
ProximityEngine.prototype.setConfigs = function (cfg) { | ||
if (cfg.center) { | ||
var center = cfg.center; | ||
this._center[0] = center[0]; | ||
this._center[1] = center[1]; | ||
this._center[2] = center[2]; | ||
} | ||
if (cfg.radii != undefined) { | ||
this._radii = cfg.radii; | ||
// Body statuses now redundant because radii now changed | ||
for (var i = 0; i < this._numBodies; i++) { | ||
this._bodyList[i].status = null; | ||
} | ||
} | ||
}; | ||
|
||
/** | ||
* Add a body | ||
* @param bodyId Unique body ID | ||
* @param cfg Body properties | ||
*/ | ||
ProximityEngine.prototype.addBody = function (bodyId, cfg) { | ||
if (this._bodies[bodyId]) { | ||
throw "Body with this ID already added: " + bodyId; | ||
} | ||
this._bodies[bodyId] = new ProximityBody(bodyId, cfg.pos, cfg.radius); | ||
this._bodyListDirty = true; | ||
}; | ||
|
||
/** | ||
* Remove a body that was added with {@link #addBody}. | ||
* @param bodyId | ||
*/ | ||
ProximityEngine.prototype.removeBody = function (bodyId) { | ||
delete this._bodies[bodyId]; | ||
this._bodyListDirty = true; | ||
}; | ||
|
||
/** | ||
* Find updates in proximity status for bodies, | ||
* return an array of the updated bodies in a callback | ||
* @param {Function(Array,Number)} callback Returns array of {@link ProximityBody}s that have changed status, | ||
* plus length of the array | ||
*/ | ||
ProximityEngine.prototype.integrate = function (callback) { | ||
if (this._bodyListDirty) { | ||
this._rebuildBodyList(); | ||
} | ||
var numUpdatedBodies = 0; | ||
var body; | ||
var dist; | ||
var status; | ||
var outerRadiusIdx = this._radii.length - 1; | ||
for (var i = 0; i < this._numBodies; i++) { | ||
body = this._bodyList[i]; | ||
dist = Math.abs(this._lenVec3(this._subVec3(this._center, body.pos, []))); // TODO: optimise - inline this | ||
status = -1; | ||
for (var j = outerRadiusIdx; j >= 0; j--) { | ||
if (dist > this._radii[j]) { | ||
if (j < outerRadiusIdx) { | ||
status = j + 1; | ||
} | ||
break; | ||
} | ||
status = j; | ||
} | ||
if (status !== body.status) { | ||
body.status = status; | ||
this._updatedBodies[numUpdatedBodies++] = body; | ||
} | ||
} | ||
callback(this._updatedBodies, numUpdatedBodies); | ||
}; | ||
|
||
ProximityEngine.prototype._rebuildBodyList = function () { | ||
this._numBodies = 0; | ||
for (var bodyId in this._bodies) { | ||
if (this._bodies.hasOwnProperty(bodyId)) { | ||
this._bodyList[this._numBodies++] = this._bodies[bodyId]; | ||
} | ||
} | ||
this._bodyListDirty = false; | ||
}; | ||
|
||
ProximityEngine.prototype._subVec3 = function (u, v, dest) { | ||
if (!dest) { | ||
dest = u; | ||
} | ||
dest[0] = u[0] - v[0]; | ||
dest[1] = u[1] - v[1]; | ||
dest[2] = u[2] - v[2]; | ||
return dest; | ||
}; | ||
|
||
ProximityEngine.prototype._lenVec3 = function (v) { | ||
return Math.sqrt(this._sqLenVec3(v)); | ||
}; | ||
|
||
ProximityEngine.prototype._sqLenVec3 = function (v) { | ||
return this._dotVector3(v, v); | ||
}; | ||
|
||
ProximityEngine.prototype._dotVector3 = function (u, v) { | ||
return (u[0] * v[0] + u[1] * v[1] + u[2] * v[2]); | ||
}; | ||
|
||
|
||
/** | ||
* A spherical body within a {@link ProximityEngine} | ||
* @param bodyId Body ID | ||
* @param pos Center of the body | ||
* @param radius radius of body | ||
* @constructor | ||
*/ | ||
function ProximityBody(bodyId, pos, radius) { | ||
this.bodyId = bodyId; | ||
this.pos = pos; | ||
this.radius = radius; | ||
this.status = null; | ||
} |
133 changes: 133 additions & 0 deletions
133
api/latest/plugins/lib/proximity/proximityEngineWorker.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/** | ||
* Web worker containing a ProximityEngine | ||
* | ||
* This worker accepts various commands to configure the engine, add or | ||
* remove bodies, and integrate, which means find proximity status changes for bodies. | ||
* | ||
* After each integration, this worker posts back an array buffer containing | ||
* an updated status for each body that has changed status. | ||
* | ||
* Input Commands | ||
* -------------------------------------------------------------------------- | ||
* | ||
* Configure the engine: | ||
* { | ||
* cmd: "setConfigs", | ||
* center: [Number, Number, Number, | ||
* innerRadius: Number, | ||
* outerRadius: Number | ||
* } | ||
* | ||
* Create a body: | ||
* { | ||
* cmd: "createBody", | ||
* bodyId: Number, | ||
* bodyCfg: { | ||
* pos: [Number, Number, Number], | ||
* radius: Number | ||
* } | ||
* } | ||
* | ||
* Remove a body: | ||
* { | ||
* cmd: "removeBody", | ||
* bodyId: Number | ||
* } | ||
* | ||
* Update a body: | ||
* { | ||
* cmd: "updateBody", | ||
* bodyId: Number, | ||
* bodyCfg: { | ||
* pos: [Number, Number, Number], | ||
* radius: Number | ||
* } | ||
* } | ||
* | ||
* Integrate the engine: | ||
* { | ||
* cmd: "integrate" | ||
* } | ||
* | ||
* Output Buffer | ||
* -------------------------------------------------------------------------- | ||
* | ||
* The output buffer contains a 2-element portion for each proximity body, each of | ||
* which contains the body ID and its proximity status: | ||
* | ||
* [ | ||
* bodyId, status, | ||
* bodyId, status, | ||
* ... | ||
* ] | ||
* | ||
*/ | ||
importScripts("proximityEngine.js"); | ||
|
||
// Array in which this worker posts back | ||
// an updated position and direction for each body | ||
var output; | ||
|
||
// Proximity engine engine | ||
var engine = new ProximityEngine(); | ||
|
||
// Set initial default configuration for proximity engine | ||
engine.setConfigs({ | ||
center:[0, 0, 0], | ||
radii:[200, 700, 1200] | ||
}); | ||
|
||
// Handle command from worker owner | ||
addEventListener("message", | ||
function (e) { | ||
|
||
var data = e.data; | ||
|
||
switch (data.cmd) { | ||
|
||
// Configure the proximity engine | ||
case "setConfigs": | ||
engine.setConfigs(data.configs); | ||
break; | ||
|
||
// Create a proximity body | ||
case "createBody": | ||
engine.addBody(data.bodyId, data.bodyCfg); | ||
break; | ||
|
||
// Update a proximity body | ||
case "updateBody": | ||
engine.updateBody(data.bodyId, data.bodyCfg); | ||
break; | ||
|
||
// Remove a proximity body | ||
case "removeBody": | ||
engine.removeBody(data.bodyId); | ||
break; | ||
|
||
// Integrate the proximity engine and post back the body updates | ||
case "integrate": | ||
var output = new Int16Array(data.buffer); | ||
var body; | ||
var ibuf = 0; | ||
engine.integrate( | ||
function (updatedBodies, numUpdated) { | ||
for (var i = 0; i < numUpdated; i++) { | ||
body = updatedBodies[i]; | ||
output[ibuf++] = body.bodyId; | ||
output[ibuf++] = body.status; | ||
} | ||
// Post the output | ||
var response = { | ||
buffer:output.buffer, | ||
lenOutput:ibuf | ||
}; | ||
self.postMessage(response, [response.buffer]); | ||
}); | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
}, false); | ||
|
Oops, something went wrong.