// ==UserScript== // @name Face Angle Capture // @namespace http://github.com/AlexisTheLarge // @version 1.3 // @description Capture angles from 3D face reconstruction automatically // @author Alexis_TheLarge // @match http://cvl-demos.cs.nott.ac.uk/vrn/view.php* // @grant GM_addStyle // @grant GM.addStyle // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js // @require https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.5/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js // ==/UserScript== GM.addStyle("button.button.purple {background-color: #E80C7A !important; width: 100% !important; cursor:pointer; }"); GM.addStyle("#ProgressOverlay {color:white; width: 462px; height:462px; background-color: rgba(0,0,0,0.4); position: absolute; top: 0; left: 0; padding-top:40%; padding-left:10%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;"); GM.addStyle("#myProgress { width: 80%; background-color: white;} #myBar { width: 1%; height: 30px; background-color: #E80C7A; }"); var progress = 1; var step = 100/130; var progressbar = null; var progress_container = null; (function() { 'use strict'; window.addEventListener('load', function() { var viewer_frame = document.getElementById("viewer_frame"); progress_container = document.createElement('div'); progress_container.innerHTML = '

Capturing Angles...

'; progress_container.setAttribute ('id', 'ProgressOverlay'); progress_container.style.display = 'none'; viewer_frame.appendChild(progress_container); var viewer_controls = document.getElementById("viewer_controls"); var hr = viewer_controls.getElementsByTagName("hr")[0]; var zNode = document.createElement('p'); zNode.innerHTML = ''; viewer_controls.insertBefore(zNode, hr); document.getElementById ("generateAnglesButton").addEventListener ( "click", ButtonClickAction, false ); }, false); })(); function ButtonClickAction (zEvent) { generate_angles(); } /* jshint ignore:start */ async function generate_angles() { if (typeof objname === 'undefined') { var objname = unsafeWindow.objname; } objpath = "queue/obj/" + objname + ".obj"; jpgpath = "queue/obj/" + objname + ".jpg"; progressbar = document.getElementById("myBar"); progress_container.style.display = 'block'; var zip = new JSZip(); await generate(zip, 'a_', function(){}); await generate(zip, 'b_', function(face, plane, pivot, scene) { var axis = new THREE.Vector3( 1, 0, 0 ).normalize(); rotate(face, plane, pivot, scene, axis, ((Math.PI*0.5)/5)); }); await generate(zip, 'ba_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, ((Math.PI*0.5)/5)); rotate(face, plane, pivot, scene, axis_z, ((Math.PI*0.5)/7)); }); await generate(zip, 'bb_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, ((Math.PI*0.5)/5)); rotate(face, plane, pivot, scene, axis_z, -((Math.PI*0.5)/7)); }); await generate(zip, 'c_', function(face, plane, pivot, scene) { var axis = new THREE.Vector3( 1, 0, 0 ).normalize(); rotate(face, plane, pivot, scene, axis, ((Math.PI*0.5)/2)); }); await generate(zip, 'ca_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, ((Math.PI*0.5)/2)); rotate(face, plane, pivot, scene, axis_z, ((Math.PI*0.5)/5)); }); await generate(zip, 'cb_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, ((Math.PI*0.5)/2)); rotate(face, plane, pivot, scene, axis_z, -((Math.PI*0.5)/5)); }); await generate(zip, 'd_', function(face, plane, pivot, scene) { var axis = new THREE.Vector3( 1, 0, 0 ).normalize(); rotate(face, plane, pivot, scene, axis, -((Math.PI*0.5)/5)); }); await generate(zip, 'da_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, -((Math.PI*0.5)/5)); rotate(face, plane, pivot, scene, axis_z, ((Math.PI*0.5)/7)); }); await generate(zip, 'db_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, -((Math.PI*0.5)/5)); rotate(face, plane, pivot, scene, axis_z, -((Math.PI*0.5)/7)); }); await generate(zip, 'e_', function(face, plane, pivot, scene) { var axis = new THREE.Vector3( 1, 0, 0 ).normalize(); rotate(face, plane, pivot, scene, axis, -((Math.PI*0.5)/2)); }); await generate(zip, 'ea_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, -((Math.PI*0.5)/2)); rotate(face, plane, pivot, scene, axis_z, ((Math.PI*0.5)/5)); }); await generate(zip, 'eb_', function(face, plane, pivot, scene) { var axis_y = new THREE.Vector3( 1, 0, 0 ).normalize(); var axis_z = new THREE.Vector3( 0, 0, 1 ).normalize(); rotate(face, plane, pivot, scene, axis_y, -((Math.PI*0.5)/2)); rotate(face, plane, pivot, scene, axis_z, -((Math.PI*0.5)/5)); }); /*jshint ignore:end */ zip.generateAsync({type:"blob"}) .then(function(content) { // Force down of the Zip file saveAs(content, "face_angles.zip"); progress_container.style.display = 'none'; progress = 1; progressbar.style.width = progress + '%'; location.reload(); }); function generate(zip, prefix, pretransform) { camera = new THREE.OrthographicCamera(-96, 96, -96, 96, 1, 1000); camera.up.set( 0, 1, 0 ); camera.position.x = 80; camera.position.y = 0; camera.position.z = 100; camera.zoom = 1; camera.updateProjectionMatrix(); scene = new THREE.Scene(); scene.position.z = 0; scene.position.y = 0; var geometry = new THREE.BoxBufferGeometry( 1, 1, 1 ); var material_p = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); var mesh = new THREE.Mesh( geometry, material_p ); mesh.position.y = -96; mesh.position.x = -96; mesh.position.z = -30; var pivot = new THREE.Object3D(); pivot.add( mesh ); scene.add( pivot ); var manager = new THREE.LoadingManager(); var material = new THREE.MeshBasicMaterial({ map : THREE.ImageUtils.loadTexture(jpgpath), }); // plane plane = new THREE.Mesh(new THREE.PlaneGeometry(192, 192), material); plane.material.side = THREE.DoubleSide; plane.scale.y = -1; if (document.getElementById('checkBackground').checked) { scene.add(plane); } face = null; renderer = new THREE.WebGLRenderer({ alpha: true }); renderer.setPixelRatio( 1 ); renderer.setSize( 320,320 ); return new Promise((resolve, reject) => { var loader = new THREE.OBJVertexColorLoader(manager); loader.load(objpath, function (object) { object.children[0].material.side = THREE.DoubleSide; object.translateX(-96); object.translateY(-96); object.translateZ(-30); scene.add(object); face = object; render(); pretransform(face, plane, pivot, scene); for (var i = 0; i < 10 ; i++) { var axis = new THREE.Vector3( 0, 1, 0 ).normalize(); rotate(face, plane, pivot, scene, axis, ((Math.PI*0.5)/10)); imgData = renderer.domElement.toDataURL("image/jpeg").split(',')[1]; zip.file(prefix+i+".jpg", imgData, {base64: true}); progress += step; progressbar.style.width = progress + '%'; } resolve(true); }, function() {}, function () {}); }); } function rotate(face, plane, pivot, scene, axis, angle) { pivot_rotate(face, scene, pivot, angle, axis); pivot_rotate(plane, scene, pivot, angle, axis); render(); } function render() { camera.lookAt(scene.position); renderer.render(scene, camera); } function pivot_rotate(object, scene, pivot, angle, axis){ pivot_attach(object, scene, pivot); pivot.rotateOnAxis(axis,angle); pivot_detach(object, scene, pivot); } function pivot_attach(object, scene, pivot) { pivot.updateMatrixWorld(); THREE.SceneUtils.attach( object, scene, pivot ); } function pivot_detach(object, scene, pivot) { pivot.updateMatrixWorld(); object.updateMatrixWorld(); // if not done by the renderer THREE.SceneUtils.detach( object, pivot, scene ); pivot.rotation.set( 0, 0, 0 ); } } THREE.OBJVertexColorLoader = function (manager) { this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager; this.materials = null; }; THREE.OBJVertexColorLoader.prototype = { constructor: THREE.OBJVertexColorLoader, load: function (url, onLoad, onProgress, onError) { var scope = this; var loader = new THREE.XHRLoader(scope.manager); loader.setPath(this.path); loader.load(url, function (text) { onLoad(scope.parse(text)); }, onProgress, onError); }, setPath: function (value) { this.path = value; }, parse: function (text) { var container = new THREE.Group(); var geometry = new THREE.Geometry(); var vertices = []; var vertexColors = []; var faces = []; // v float float float float float float (vertex with rgb) var vertex_colour_pattern = /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/; // f vertex vertex vertex ... var face_pattern1 = /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/; var lines = text.split('\n'); for (var i = 0; i < lines.length; i++) { var line = lines[i]; line = line.trim(); var result; if (line.length === 0 || line.charAt(0) === '#') { continue; } else if ((result = vertex_colour_pattern.exec(line)) !== null) { vertices.push( new THREE.Vector3(parseFloat(result[1]), parseFloat(result[2]), parseFloat(result[3])) ); vertexColors.push(new THREE.Color(parseFloat(result[4]), parseFloat(result[5]), parseFloat(result[6]))); } else if ((result = face_pattern1.exec(line)) !== null) { faces.push(new THREE.Face3(result[1] - 1, result[2] - 1, result[3] - 1)); } } for (var i = 0; i < vertices.length; i++) { geometry.vertices.push(vertices[i]); } for (var i = 0; i < faces.length; i++) { faces[i].vertexColors[0] = vertexColors[faces[i].a]; faces[i].vertexColors[1] = vertexColors[faces[i].b]; faces[i].vertexColors[2] = vertexColors[faces[i].c]; geometry.faces.push(faces[i]); } var material = new THREE.MeshBasicMaterial({ vertexColors: THREE.VertexColors }); var mesh = new THREE.Mesh(geometry, material); container.add(mesh); return container; } };