UNPKG

7.73 kBJavaScriptView Raw
1'use strict';
2/* eslint-disable no-undef */
3/* eslint-disable no-console */
4
5function FluxBuildings() {
6 // Whether a time trial is currently running.
7 // This requires only one time trial to run at a time per instance.
8 this._inTrial = false;
9 // How many times render has been called in this time trial.
10 this._renderCount = 0;
11 // How many times to render in each time trial.
12 this._maxCount = 10;
13
14 this._perf = new InteractivePerf();
15
16 this.printMemory();
17}
18
19/**
20 * Models that can be loaded from GCS
21 * New models can be uploaded here:
22 * https://console.cloud.google.com/storage/browser/object-library/?pli=1&project=object-library
23 */
24FluxBuildings.urls = [
25 "https://storage.googleapis.com/object-library/sphere.json",
26 "https://storage.googleapis.com/object-library/sphereBig.json",
27 "https://storage.googleapis.com/object-library/sphereSmall.json",
28 "https://storage.googleapis.com/object-library/spheres.json",
29 "https://storage.googleapis.com/object-library/buildingsMedMesh.json",
30 "https://storage.googleapis.com/object-library/buildingsBigMesh.json"
31];
32
33/**
34* Grab a model from flux-viewport-models and convert it to three.js runtime.
35* @param {String} url The location to load from
36*/
37FluxBuildings.prototype.loadModel = function (url) {
38 console.log("Loading model",url);
39 var _this = this;
40 this.requestModel(url, function (result) {
41 this._perf.begin();
42 fluxViewport.setGeometryEntity(result).then(function (result) {
43 fluxViewport.focus();
44 _this._perf.end('Load model');
45 if (result.isEmpty()) {
46 console.warn(result.primStatus.invalidKeySummary());
47 }
48 _this.countGeometry();
49 _this.printMemory();
50 }).catch(function (err) {
51 console.log(err);
52 });
53 }.bind(this));
54};
55
56/**
57* Respond to user pressing the record button.
58* Start recording any renders that are triggered by user interaction.
59* The next time the button is pressed the results will be processed and output.
60*/
61FluxBuildings.prototype.handleRecord = function () {
62 if (!fluxViewport.renderPatched) {
63 var renderFunction = fluxViewport.render;
64 var _this = this;
65 fluxViewport.render = function() {
66 _this._perf.begin();
67 renderFunction.call(fluxViewport);
68 _this._perf.end();
69 };
70 fluxViewport.renderPatched = true;
71 }
72 this._perf.toggleRecording();
73};
74
75/**
76* Respond to user pressing the trial button.
77* Start a time trial that renders the scene a certain number of times
78* and records the performance.
79*/
80FluxBuildings.prototype.handleTrial = function () {
81 this._testRender();
82};
83
84/**
85* Respond to usr pressing count button.
86* Count the number of triangles in the object.
87*/
88FluxBuildings.prototype.countGeometry = function () {
89 var model = fluxViewport._renderer._model;
90 this.countObjects(model);
91 this.countTriangles(model);
92 this.computeBoundingBox(model);
93};
94
95FluxBuildings.prototype.countObjects = function (objectRoot) {
96 var count = 0;
97 objectRoot.traverse( function (element) {
98 if (element.type === "Mesh") {
99 count++;
100 }
101 });
102 console.log("Number of objects:",count);
103};
104
105FluxBuildings.prototype.countTriangles = function (objectRoot) {
106 var faceCount = 0;
107 var vertCount = 0;
108 objectRoot.traverse( function (element) {
109 if (element.type === "Mesh" && element.visible===true) {
110 if (element.geometry instanceof THREE.BufferGeometry) {
111 vertCount += element.geometry.attributes.position.count;
112 if (element.geometry.attributes.index) {
113 faceCount += element.geometry.attributes.index.count/3;
114 } else { // default is one face per three points
115 faceCount += element.geometry.attributes.position.count/3;
116 }
117 }
118 else { // regular (non buffer) geometry
119 vertCount += element.geometry.vertices.length;
120 faceCount += element.geometry.faces.length;
121 }
122 }
123 });
124 console.log("Number of vertices:", vertCount);
125 console.log("Number of faces:", faceCount);
126};
127
128/**
129* Compute the bounding box of the object, including all of it's children.
130* @param {THREE.Object3D} objectRoot The object to size up.
131*/
132FluxBuildings.prototype.computeBoundingBox = function (objectRoot) {
133
134 var bbMax = new THREE.Vector3(-Infinity, -Infinity, -Infinity);
135 var bbMin = new THREE.Vector3(Infinity, Infinity, Infinity);
136 var tmp = new THREE.Vector3(0,0,0);
137
138 var foundBufferGeometry = false;
139 var foundRegularGeometry = false;
140 objectRoot.traverse( function (element) {
141 if (element.matrixWorldNeedsUpdate) {
142 // Tell three.js to update the matrix from the position attributes.
143 element.updateMatrixWorld(true);
144 }
145
146 // Use vertices to compute bounds
147 if (element.type === "Mesh" && element.visible===true) {
148
149 if (element.geometry instanceof THREE.BufferGeometry) {
150 foundBufferGeometry = true;
151 var positions = element.geometry.attributes.position.array;
152 var i = 0;
153 while (i < positions.length) {
154 tmp.set(positions[i],positions[i+1],positions[i+2]);
155 tmp.applyMatrix4(element.matrix);
156 bbMin.min(tmp);
157 bbMax.max(tmp);
158 i+=3;
159 }
160 }
161 else { // regular (non buffer) geometry
162 foundRegularGeometry = true;
163 var vertices = element.geometry.vertices;
164 vertices.forEach( function (vert) {
165 vert.applyMatrix4(element.matrix);
166 bbMin.min(vert);
167 bbMax.max(vert);
168 });
169 }
170
171 }
172 });
173 if (foundBufferGeometry) {
174 console.log("Found buffer geometry");
175 }
176 if (foundRegularGeometry) {
177 console.log("Found regular geometry");
178 }
179 // Compute size from bounds
180 tmp.copy(bbMax);
181 tmp.sub(bbMin);
182 console.log("Maximum axis aligned length:",Math.max(Math.max(tmp.x,tmp.y),tmp.z));
183};
184
185/**
186* Send an xhr to retrieve the model at the given url.
187* @param {String} url GCS item to retrieve.
188* @param {Function} callback The function to act on the model.
189*/
190FluxBuildings.prototype.requestModel = function (url, callback) {
191 var xhr = new XMLHttpRequest();
192 xhr.addEventListener('load', function () {
193 if (this.status === 200) { // OK
194 var responseObj = JSON.parse(this.response);
195 callback(responseObj);
196 } else {
197 console.error(this.status, this.response);
198 }
199 });
200 xhr.open("GET", url, true);
201 xhr.send();
202};
203
204/**
205* Print the amount of memory used by Chrome
206* Requires --enable-precise-memory-info when launching Chrome to get around security barrier.
207*/
208FluxBuildings.prototype.printMemory = function () {
209 if (window.performance && window.performance.memory) {
210 console.log("Js Heap used: ", window.performance.memory.usedJSHeapSize/1000000,"M");
211 } else {
212 console.log("This browser does not support memory statistics.");
213 }
214};
215
216/**
217* Render a certain number of times and output
218*/
219FluxBuildings.prototype._testRender = function () {
220 // Trial run a few renders
221 this._perf.startRecording();
222 this._inTrial = true;
223 this._renderCount = 0;
224 for (var i=0;i<this._maxCount;i++) {
225 this._perf.begin();
226 fluxViewport.render();
227 this._perf.end();
228 }
229 this._perf.stopRecording();
230};