This commit is contained in:
Thomas FORGIONE 2015-11-27 10:20:13 +01:00
parent adbd3c95f1
commit df876748c1
7 changed files with 237 additions and 68 deletions

71
analysis/hover/main.m Normal file
View File

@ -0,0 +1,71 @@
diffTable;
EXP_ID = 1;
ARROW_ID = 2;
STARTED = 3;
TIME = 4;
% Compute diff tables, and split by exps
hovers = {};
map = [];
start = 1;
current_exp_id = M(1,EXP_ID);
for i = 1:length(M),
if M(i, EXP_ID) ~= current_exp_id,
current_exp_id = M(i, EXP_ID);
start = start + 1;
end
map(i) = start;
end
hovers = cell(max(map), 1);
is_hovering = false;
current_hover = -1;
current_time = 0;
for i = 1:length(M),
if M(i, STARTED),
if (current_hover ~= -1 && M(i, ARROW_ID) ~= current_hover && is_hovering),
% Add line for previous hovering
hovers{map(M(i, EXP_ID))} = [hovers{map(M(i, EXP_ID))}; M(i, TIME) - current_time];
end
current_hover = M(i, ARROW_ID);
current_time = M(i, TIME);
else
hovers{map(M(i, EXP_ID))} = [hovers{map(M(i, EXP_ID))}; M(i, TIME) - current_time];
end
end
% All hover time
all_hovers = sort(vertcat(hovers{:}));
times = 0:0.001:0.6;
curve = zeros(length(times),1);
for i = 1 : length(times),
curve(i) = sum(all_hovers < times(i));
end
plot(times, curve);

View File

@ -24,6 +24,7 @@ let modelMap;
let smallMap; let smallMap;
let smallModel; let smallModel;
let triangleMeshes = []; let triangleMeshes = [];
let colorToFace = [];
let renderer = new THREE.CanvasRenderer(); let renderer = new THREE.CanvasRenderer();
renderer.domElement.style = renderer.domElement; renderer.domElement.style = renderer.domElement;
@ -45,6 +46,7 @@ scene.add(mesh);
scene.add(camera); scene.add(camera);
let counter = 0; let counter = 0;
let forceFinished = false;
init() init()
@ -78,7 +80,7 @@ function init() {
} }
progLoader = new L3D.ProgressiveLoader( progLoader = new L3D.ProgressiveLoader(
buildPathBigObj(path), scene, info.camera, null, function(a,b) { /* process.stderr.write((100*a/b) + '%\n'); */ }, false, info.sort buildPathBigObj(path), new THREE.Object3D(), info.camera, null, function(a,b) { /* process.stderr.write((100*a/b) + '%\n'); */ }, false, info.sort
); );
// Init variables // Init variables
@ -104,6 +106,7 @@ function init() {
face3.materialIndex = counter; face3.materialIndex = counter;
material.materials.push(new THREE.MeshBasicMaterial({color: counter, overdraw: true})); material.materials.push(new THREE.MeshBasicMaterial({color: counter, overdraw: true}));
colorToFace[counter] = face3;
geometry.faces.push(face3); geometry.faces.push(face3);
@ -116,12 +119,12 @@ function init() {
} }
process.stderr.write('Loading complete.\n'); process.stderr.write('--> Loading complete.\n');
progLoader.onBeforeEmit = loop; progLoader.onBeforeEmit = loop;
progLoader.load(function() { progLoader.load(function() {
process.stderr.write("Loading complete\n"); process.stderr.write("--> Loading complete\n");
forceFinished = true; forceFinished = true;
}); });
@ -144,19 +147,50 @@ function buildPathMap(path) { return './maps/' + path.name + '.json'; }
function loop() { function loop() {
process.stderr.write(imageNumber + '\n'); process.stderr.write('--> ' + imageNumber + '\n');
camera.update(20); for (let i = 0; i < 10; i++)
camera.update(20);
camera.look(); camera.look();
process.stderr.write('Rendering...\n'); process.stderr.write('--> Rendering...\n');
let lastTime = Date.now(); let lastTime = Date.now();
renderer.render(scene, camera); renderer.render(scene, camera);
process.stderr.write('Renderered in ' + (Date.now() - lastTime) + '\n'); process.stderr.write('--> Renderered in ' + (Date.now() - lastTime) + '\n');
fs.writeFileSync(__dirname + '/img/' + pad(imageNumber++, 5) + '.png', renderer.domElement.toBuffer()); fs.writeFileSync(__dirname + '/img' + (info.sort ? '1' : '') + '/' + pad(imageNumber++, 5) + '.png', renderer.domElement.toBuffer());
let score = 0;
let denom = 0;
// Traverse image to find faces
lastTime = Date.now();
let pixelData = renderer.getContext()
.getImageData(0, 0, renderer.domElement.width, renderer.domElement.height).data;
for (let i = 0; i < pixelData.length; i += 4) {
let pixelNumber = (pixelData[i] << 16) + (pixelData[i+1] << 8) + (pixelData[i+2]);
if (pixelNumber !== 0) {
denom++;
try {
if (progLoader.hasFace(colorToFace[pixelNumber])) {
score++;
}
} catch(e) {
process.stderr.write('--> ' + pixelNumber + '\n');
}
}
}
process.stderr.write('--> Computed pixels in ' + (Date.now() - lastTime) + 'ms\n');
score /= denom;
process.stderr.write('--> Score : ' + score + '\n');
console.log(score);
} }
@ -187,7 +221,7 @@ function initElements(camera, sceneInfo, redCoins) {
// camera.coins = L3D.generateCoins(L3D.createWhompCoins(), redCoins); // camera.coins = L3D.generateCoins(L3D.createWhompCoins(), redCoins);
return {name:'Whomps Fortress', folder:'whomp'}; return {name:'Whomps Fortress', folder:'whomp'};
default: default:
process.stderr.write('This sceneId doesn\'t exist\n'); process.stderr.write('--> This sceneId doesn\'t exist\n');
process.exit(-1); process.exit(-1);

View File

@ -26,6 +26,8 @@ L3D.ReplayCamera = function() {
this.recommendationClicked = null; this.recommendationClicked = null;
this.isArrow = false;
}; };
L3D.ReplayCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype); L3D.ReplayCamera.prototype = Object.create(THREE.PerspectiveCamera.prototype);
L3D.ReplayCamera.prototype.constructor = L3D.ReplayCamera; L3D.ReplayCamera.prototype.constructor = L3D.ReplayCamera;
@ -107,6 +109,11 @@ L3D.ReplayCamera.prototype.nextEvent = function() {
var self = this; var self = this;
if (self.isArrow) {
self.isArrow = false;
process.stderr.write('\033[31mArrowclicked finished !\033[0m\n');
}
this.counter++; this.counter++;
// Finished // Finished
@ -139,6 +146,8 @@ L3D.ReplayCamera.prototype.nextEvent = function() {
// },500); // },500);
// })(this); // })(this);
} else if (this.event.type == 'arrow') { } else if (this.event.type == 'arrow') {
self.isArrow = true;
process.stderr.write('\033[33mArrowclicked ! ' + JSON.stringify(self.cameras[self.event.id].camera.position) + '\033[0m\n');
if (this.shouldRecover) { if (this.shouldRecover) {
(function(self, tmp) { (function(self, tmp) {
self.event.type = 'camera'; self.event.type = 'camera';
@ -252,7 +261,7 @@ L3D.ReplayCamera.prototype.moveHermite = function(recommendation) {
L3D.ReplayCamera.prototype.moveReco = function(recommendationId) { L3D.ReplayCamera.prototype.moveReco = function(recommendationId) {
this.recommendationClicked = this.cameras[recommendationId].camera; this.recommendationClicked = recommendationId;
this.moveHermite(this.cameras[recommendationId]); this.moveHermite(this.cameras[recommendationId]);
@ -270,7 +279,7 @@ L3D.ReplayCamera.prototype.save = function() {};
*/ */
L3D.ReplayCamera.prototype.toList = function() { L3D.ReplayCamera.prototype.toList = function() {
var camera = (this.recommendationClicked === null ? this : this.recommendationClicked); var camera = this; // (this.recommendationClicked === null ? this : this.cameras[this.recommendationClicked].camera);
camera.updateMatrix(); camera.updateMatrix();
camera.updateMatrixWorld(); camera.updateMatrixWorld();
@ -284,7 +293,7 @@ L3D.ReplayCamera.prototype.toList = function() {
var ret = var ret =
[[camera.position.x, camera.position.y, camera.position.z], [[camera.position.x, camera.position.y, camera.position.z],
[camera.target.x, camera.target.y, camera.target.z], [camera.target.x, camera.target.y, camera.target.z],
this.recommendationClicked !== null this.recommendationClicked
]; ];
for (var i = 0; i < frustum.planes.length; i++) { for (var i = 0; i < frustum.planes.length; i++) {

View File

@ -301,7 +301,7 @@ ProgressiveLoader.prototype.initIOCallbacks = function() {
this.socket.on('elements', function(arr) { this.socket.on('elements', function(arr) {
process.stderr.write('Received ' + arr.length + '\n'); // process.stderr.write('Received ' + arr.length + '\n');
for (var i = 0; i < arr.length; i++) { for (var i = 0; i < arr.length; i++) {
@ -431,15 +431,23 @@ ProgressiveLoader.prototype.initIOCallbacks = function() {
} }
var param;
if (typeof self.onBeforeEmit === 'function') { if (typeof self.onBeforeEmit === 'function') {
self.onBeforeEmit();
}
// Ask for next elements for (var m of self.meshes) {
if (!self.laggy) { m.geometry.computeBoundingSphere();
self.socket.emit('next', self.getCamera()); }
param = self.onBeforeEmit();
setTimeout(function() { self.socket.emit('next', self.getCamera(), param);}, 100);
} else { } else {
setTimeout(function() { self.socket.emit('next', self.getCamera());}, 100);
// Ask for next elements
if (!self.laggy) {
self.socket.emit('next', self.getCamera(), param);
} else {
setTimeout(function() { self.socket.emit('next', self.getCamera());}, 100);
}
} }
}); });

View File

@ -25,7 +25,7 @@ L3D.initPeachCastle = function(scene, collidableObjects, recommendation, clickab
var loader = new L3D.ProgressiveLoader( var loader = new L3D.ProgressiveLoader(
'/static/data/castle/princess peaches castle (outside).obj', '/static/data/castle/princess peaches castle (outside).obj',
scene, scene,
null, recommendation,
function(object) { function(object) {
if (clickable !== undefined) if (clickable !== undefined)
clickable.push(object); clickable.push(object);
@ -356,7 +356,7 @@ L3D.initWhompScene = function(scene, collidableObjects, recommendation, clickabl
var loader = new L3D.ProgressiveLoader( var loader = new L3D.ProgressiveLoader(
'/static/data/whomp/Whomps Fortress.obj', '/static/data/whomp/Whomps Fortress.obj',
scene, scene,
null, recommendation,
function(object) { function(object) {
if (clickable !== undefined) if (clickable !== undefined)
clickable.push(object); clickable.push(object);
@ -512,7 +512,7 @@ L3D.initMountainScene = function(scene, collidableObjects, recommendation, click
var loader = new L3D.ProgressiveLoader( var loader = new L3D.ProgressiveLoader(
'/static/data/mountain/coocoolmountain.obj', '/static/data/mountain/coocoolmountain.obj',
scene, scene,
null, recommendation,
function(object) { function(object) {
// object.rotation.x = -Math.PI/2; // object.rotation.x = -Math.PI/2;
// object.rotation.z = Math.PI/2; // object.rotation.z = Math.PI/2;

View File

@ -355,9 +355,6 @@ function pushMesh(name) {
reco.matrixWorldInverse.getInverse( reco.matrixWorld ); reco.matrixWorldInverse.getInverse( reco.matrixWorld );
var frustum = new THREE.Frustum(); var frustum = new THREE.Frustum();
var projScreenMatrix = new THREE.Matrix4();
projScreenMatrix.multiplyMatrices(reco.projectionMatrix, reco.matrixWorldInverse);
frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(reco.projectionMatrix, reco.matrixWorldInverse)); frustum.setFromMatrix(new THREE.Matrix4().multiplyMatrices(reco.projectionMatrix, reco.matrixWorldInverse));
geo.availableMeshes[name].recommendations.push({ geo.availableMeshes[name].recommendations.push({

View File

@ -159,7 +159,7 @@ geo.MeshStreamer = function(path) {
* Number of element to send by packet * Number of element to send by packet
* @type {Number} * @type {Number}
*/ */
this.chunk = 1250; this.chunk = 1250 / 2;
this.previousReco = 0; this.previousReco = 0;
@ -344,7 +344,7 @@ geo.MeshStreamer.prototype.start = function(socket) {
}); });
socket.on('next', function(_camera) { socket.on('next', function(_camera, score) {
var cameraFrustum = {}; var cameraFrustum = {};
@ -365,7 +365,7 @@ geo.MeshStreamer.prototype.start = function(socket) {
planes: [] planes: []
}; };
var fullFrustum = _camera[2]; var recommendationClicked = _camera[2];
for (i = 3; i < _camera.length; i++) { for (i = 3; i < _camera.length; i++) {
@ -384,10 +384,25 @@ geo.MeshStreamer.prototype.start = function(socket) {
// Create config for proportions of chunks // Create config for proportions of chunks
var config; var config;
var didPrefetch = false;
if (self.prefetch) { if (!self.prefetch || (recommendationClicked === null && score < 0.85)) {
console.log("Score not good enough, no prefetch");
config = [{ frustum: cameraFrustum, proportion: 1}];
} else if (recommendationClicked !== null) {
console.log("Recommendation is clicking : full for " + JSON.stringify(self.mesh.recommendations[recommendationClicked].position));
config = [{frustum: cameraFrustum, proportion:0.5}, {frustum : self.mesh.recommendations[recommendationClicked], proportion: 0.5}];
} else {
console.log("Good % (" + score + "), allow some prefetching");
didPrefetch = true;
config = [{ frustum: cameraFrustum, proportion : 0.5}]; config = [{ frustum: cameraFrustum, proportion : 0.5}];
// config = [];
// Find best recommendation // Find best recommendation
var bestReco; var bestReco;
@ -398,20 +413,20 @@ geo.MeshStreamer.prototype.start = function(socket) {
var sum = 0; var sum = 0;
for (var i = 0; i < self.mesh.recommendations.length; i++) { for (var i = 1; i <= self.mesh.recommendations.length; i++) {
sum += self.predictionTable[self.previousReco][i]; sum += self.predictionTable[self.previousReco][i];
} }
for (var i = 0; i < self.mesh.recommendations.length; i++) { for (var i = 1; i <= self.mesh.recommendations.length; i++) {
if (self.predictionTable[self.previousReco][i] > 0) { if (self.predictionTable[self.previousReco][i] > 0) {
config.push({ config.push({
proportion : self.predictionTable[self.previousReco][i] / (2 * sum), proportion : self.predictionTable[self.previousReco][i] / (2 * sum),
frustum : self.mesh.recommendations[i] frustum : self.mesh.recommendations[i-1]
}); });
@ -428,66 +443,95 @@ geo.MeshStreamer.prototype.start = function(socket) {
} }
if (!fullFrustum) {
// console.log('Frustum and prefetch : ' + (cameraFrustum !== undefined) + ' ' + (bestReco !== undefined));
} else {
// console.log('Full frustum fetching (reco clicked)');
config = [{
proportion: 1,
frustum: cameraFrustum
}];
}
} else {
config = [{frustum: cameraFrustum, proportion: 1}];
} }
// Send next elements // Send next elements
var oldTime = Date.now(); var oldTime = Date.now();
var next = self.nextElements(config); var next = self.nextElements(config);
// console.log(next.configSizes); // console.log(
// 'Adding ' +
// next.size +
// ' for newConfig : '
// + JSON.stringify(config.map(function(o) { return o.proportion}))
// );
console.log(next.configSizes);
// console.log('Time to generate chunk : ' + (Date.now() - oldTime) + 'ms'); // console.log('Time to generate chunk : ' + (Date.now() - oldTime) + 'ms');
if (self.prefetch && next.size < self.chunk) { if (self.prefetch && next.size < self.chunk) {
console.log("Chunk not full : prefetch reco");
// Recompute config // Recompute config
var newConfig = []; var newConfig = [];
var sum = 0; var sum = 0;
for (var i = 0; i < config.length; i++) { if (!didPrefetch) {
// Check if config was full if (self.predictionTable !== undefined) {
if (next.configSizes[i] >= self.chunk * config[i].proportion) {
newConfig.push(config[i]); var sum = 0;
sum += config[i].proportion;
for (var i = 1; i <= self.mesh.recommendations.length; i++) {
sum += self.predictionTable[self.previousReco][i];
}
for (var i = 1; i <= self.mesh.recommendations.length; i++) {
if (self.predictionTable[self.previousReco][i] > 0) {
newConfig.push({
proportion : self.predictionTable[self.previousReco][i] / (sum),
frustum : self.mesh.recommendations[i-1]
});
}
}
}
} else {
for (var i = 0; i < config.length; i++) {
// Check if config was full
if (next.configSizes[i] >= self.chunk * config[i].proportion) {
newConfig.push(config[i]);
sum += config[i].proportion;
}
}
// Normalize config probabilities
for (var i = 0; i < newConfig.length; i++) {
newConfig[i].proportion /= sum;
} }
} }
for (var i = 0; i < newConfig.length; i++) {
newConfig[i].proportion /= sum;
}
// Normalize config probabilities
var newData = self.nextElements(newConfig, self.chunk - next.size); var newData = self.nextElements(newConfig, self.chunk - next.size);
next.data.push.apply(next.data, newData.data); next.data.push.apply(next.data, newData.data);
// console.log('Adding ' + newData.size + ' for newConfig : ' + JSON.stringify(newConfig.map(function(o) { return o.proportion}))); // console.log(
// 'Adding ' +
// newData.size +
// ' for newConfig : '
// + JSON.stringify(newConfig.map(function(o) { return o.proportion}))
// );
next.size = next.size + newData.size; next.size = next.size + newData.size;
@ -495,6 +539,8 @@ geo.MeshStreamer.prototype.start = function(socket) {
if (next.size < self.chunk) { if (next.size < self.chunk) {
console.log("Chunk not full : fill linear");
// If nothing, just serve stuff // If nothing, just serve stuff
var tmp = self.nextElements([ var tmp = self.nextElements([
// { // {
@ -508,7 +554,7 @@ geo.MeshStreamer.prototype.start = function(socket) {
} }
// console.log('Chunk of size ' + next.size); console.log('Chunk of size ' + next.size + ' (generated in ' + (Date.now() - oldTime) + 'ms)');
// console.log('Time to generate chunk : ' + (Date.now() - oldTime) + 'ms'); // console.log('Time to generate chunk : ' + (Date.now() - oldTime) + 'ms');
if (next.data.length === 0) { if (next.data.length === 0) {
@ -637,9 +683,13 @@ geo.MeshStreamer.prototype.nextElements = function(config, chunk) {
// Sort buffer // Sort buffer
if (config[configIndex].frustum !== undefined) { if (config[configIndex].frustum !== undefined) {
buffers[configIndex].sort(this.faceComparator(config[configIndex].frustum)); buffers[configIndex].sort(this.faceComparator(config[configIndex].frustum));
} else { } else {
// console.log("Did not sort"); // console.log("Did not sort");
} }
// Fill chunk // Fill chunk
@ -648,9 +698,9 @@ geo.MeshStreamer.prototype.nextElements = function(config, chunk) {
var size = this.pushFace(buffers[configIndex][i], data); var size = this.pushFace(buffers[configIndex][i], data);
totalSize += size; totalSize += size;
configSize += size; configSizes[configIndex] += size;
if (configSize > chunk * config[configIndex].proportion) { if (configSizes[configIndex] > chunk * config[configIndex].proportion) {
break; break;