From 635e5fef017572274599bfa41c47cfea1f917457 Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Wed, 11 Dec 2019 14:41:04 +0100 Subject: [PATCH] Support vertex edition --- .gitignore | 1 + js/main.js | 198 -------------------------------------------------- src/Loader.js | 23 +++++- src/Model.js | 51 ++++--------- src/main.js | 2 +- 5 files changed, 39 insertions(+), 236 deletions(-) delete mode 100644 js/main.js diff --git a/.gitignore b/.gitignore index 7e2f179..a992f1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ assets +js/main.js diff --git a/js/main.js b/js/main.js deleted file mode 100644 index 178619a..0000000 --- a/js/main.js +++ /dev/null @@ -1,198 +0,0 @@ -function fetchData(path, start, end, callback) { - let xhr = new XMLHttpRequest(); - - xhr.open('GET', path, true); - xhr.setRequestHeader('Range', 'bytes=' + start + "-" + (end - 1)); - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - if (xhr.status === 206) { - callback(xhr.responseText); - } - } - }; - xhr.send(); -} - -function parseLine(line) { - let element = {}; - let split = line.split(/[ \t]+/); - - if (split.length === 0) { - return; - } - - switch (split[0]) { - case "v": - element.type = Element.AddVertex; - element.value = new THREE.Vector3(parseFloat(split[1]), parseFloat(split[2]), parseFloat(split[3])); - return element; - - case "f": - element.type = Element.AddFace; - element.value = new THREE.Face3(parseInt(split[1], 10), parseInt(split[2], 10), parseInt(split[3], 10)); - return element; - - case "": - case "#": - return; - - default: - throw new Error(split[0] + " is not a defined macro"); - } - -} - -const Element = {}; -Element.AddVertex = "AddVertex"; -Element.AddFace = "AddFace"; - -class Loader { - constructor(path, chunkSize = 1024, timeout = 20) { - this.path = path; - this.chunkSize = chunkSize; - this.timeout = timeout; - this.currentByte = 0; - this.remainder = ""; - } - - start(callback) { - this.downloadAndParseNextChunk((data) => { - callback(data); - setTimeout(() => { - this.start(callback); - }, this.timeout); - }); - } - - downloadAndParseNextChunk(callback) { - fetchData(this.path, this.currentByte, this.currentByte + this.chunkSize, (data) => { - - if (data.length === 0) { - console.log("Loading finished"); - return; - } - - this.currentByte += this.chunkSize; - - let elements = []; - let split = data.split('\n'); - split[0] = this.remainder + split[0]; - this.remainder = split.pop(); - - for (let line of split) { - elements.push(parseLine(line)); - } - - callback(elements); - }); - } -} - -class Model extends THREE.Mesh { - constructor() { - let geometry = new THREE.BufferGeometry(); - let vertices = new Float32Array(10000000); - geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); - let normals = new Float32Array(10000000); - geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3)); - let material = new THREE.MeshLambertMaterial({color: 0xffffff}); - super(geometry, material); - this.frustumCulled = false; - this.vertices = []; - this.currentFace = 0; - } - - manageElement(element) { - switch (element.type) { - case Element.AddVertex: - this.vertices.push(element.value); - break; - - case Element.AddFace: - let buf = this.geometry.attributes.position.array; - buf[this.currentFace * 9 ] = this.vertices[element.value.a - 1].x; - buf[this.currentFace * 9 + 1] = this.vertices[element.value.a - 1].y; - buf[this.currentFace * 9 + 2] = this.vertices[element.value.a - 1].z; - buf[this.currentFace * 9 + 3] = this.vertices[element.value.b - 1].x; - buf[this.currentFace * 9 + 4] = this.vertices[element.value.b - 1].y; - buf[this.currentFace * 9 + 5] = this.vertices[element.value.b - 1].z; - buf[this.currentFace * 9 + 6] = this.vertices[element.value.c - 1].x; - buf[this.currentFace * 9 + 7] = this.vertices[element.value.c - 1].y; - buf[this.currentFace * 9 + 8] = this.vertices[element.value.c - 1].z; - this.geometry.attributes.position.needsUpdate = true; - - let normal = - this.vertices[element.value.b - 1].clone().sub(this.vertices[element.value.a - 1]) - .cross(this.vertices[element.value.c - 1].clone().sub(this.vertices[element.value.a - 1])); - normal.normalize(); - - buf = this.geometry.attributes.normal.array; - buf[this.currentFace * 9 ] = normal.x; - buf[this.currentFace * 9 + 1] = normal.y; - buf[this.currentFace * 9 + 2] = normal.z; - buf[this.currentFace * 9 + 3] = normal.x; - buf[this.currentFace * 9 + 4] = normal.y; - buf[this.currentFace * 9 + 5] = normal.z; - buf[this.currentFace * 9 + 6] = normal.x; - buf[this.currentFace * 9 + 7] = normal.y; - buf[this.currentFace * 9 + 8] = normal.z; - this.geometry.attributes.normal.needsUpdate = true; - - this.currentFace++; - break; - - default: - throw new Error("unknown element type: " + element.type); - } - this.geometry.verticesNeedUpdate = true; - this.geometry.elementsNeedUpdate = true; - } -} - -let camera, scene, renderer, loader, light1, light2, controls, model; - -init(); -animate(); - -function init() { - - loader = new Loader('assets/bunny_low_res_scaled.obj'); - loader.start(function(elements) { - for (let element of elements) { - if (element !== undefined) { - model.manageElement(element); - } - } - }); - - camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.0001, 1000); - camera.position.z = 3; - - scene = new THREE.Scene(); - - model = new Model(); - scene.add(model); - - light1 = new THREE.AmbientLight(0x999999); - scene.add(light1); - - light2 = new THREE.DirectionalLight(0xffffff, 1.0); - light2.position.set(0.0, 1.0, 0.0); - scene.add(light2); - - renderer = new THREE.WebGLRenderer({antialias: true}); - renderer.setSize(window.innerWidth, window.innerHeight); - document.body.appendChild(renderer.domElement); - - controls = new THREE.OrbitControls(camera, renderer.domElement); - -} - -function animate() { - - requestAnimationFrame(animate); - controls.update(); - renderer.render(scene, camera); - -} - diff --git a/src/Loader.js b/src/Loader.js index 05a1945..8a29ee8 100644 --- a/src/Loader.js +++ b/src/Loader.js @@ -24,12 +24,30 @@ function parseLine(line) { switch (split[0]) { case "v": element.type = Element.AddVertex; - element.value = new THREE.Vector3(parseFloat(split[1]), parseFloat(split[2]), parseFloat(split[3])); + element.value = new THREE.Vector3( + parseFloat(split[1]), + parseFloat(split[2]), + parseFloat(split[3]), + ); return element; case "f": element.type = Element.AddFace; - element.value = new THREE.Face3(parseInt(split[1], 10), parseInt(split[2], 10), parseInt(split[3], 10)); + element.value = new THREE.Face3( + parseInt(split[1], 10) - 1, + parseInt(split[2], 10) - 1, + parseInt(split[3], 10) - 1, + ); + return element; + + case "ev": + element.type = Element.EditVertex; + element.id = parseInt(split[1], 10) - 1; + element.value = new THREE.Vector3( + parseFloat(split[2]), + parseFloat(split[3]), + parseFloat(split[4]), + ); return element; case "": @@ -45,6 +63,7 @@ function parseLine(line) { const Element = {}; Element.AddVertex = "AddVertex"; Element.AddFace = "AddFace"; +Element.EditVertex = "EditVertex"; class Loader { constructor(path, chunkSize = 1024, timeout = 20) { diff --git a/src/Model.js b/src/Model.js index 724cb04..a2161c4 100644 --- a/src/Model.js +++ b/src/Model.js @@ -1,60 +1,41 @@ class Model extends THREE.Mesh { constructor() { - let geometry = new THREE.BufferGeometry(); - let vertices = new Float32Array(10000000); - geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3)); - let normals = new Float32Array(10000000); - geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3)); + let geometry = new THREE.Geometry(); let material = new THREE.MeshLambertMaterial({color: 0xffffff}); super(geometry, material); this.frustumCulled = false; this.vertices = []; - this.currentFace = 0; } manageElement(element) { switch (element.type) { case Element.AddVertex: - this.vertices.push(element.value); + this.geometry.vertices.push(element.value); + this.geometry.verticesNeedUpdate = true; + break; + + case Element.EditVertex: + this.geometry.vertices[element.id].copy(element.value); + this.geometry.verticesNeedUpdate = true; + this.geometry.elementsNeedUpdate = true; break; case Element.AddFace: - let buf = this.geometry.attributes.position.array; - buf[this.currentFace * 9 ] = this.vertices[element.value.a - 1].x; - buf[this.currentFace * 9 + 1] = this.vertices[element.value.a - 1].y; - buf[this.currentFace * 9 + 2] = this.vertices[element.value.a - 1].z; - buf[this.currentFace * 9 + 3] = this.vertices[element.value.b - 1].x; - buf[this.currentFace * 9 + 4] = this.vertices[element.value.b - 1].y; - buf[this.currentFace * 9 + 5] = this.vertices[element.value.b - 1].z; - buf[this.currentFace * 9 + 6] = this.vertices[element.value.c - 1].x; - buf[this.currentFace * 9 + 7] = this.vertices[element.value.c - 1].y; - buf[this.currentFace * 9 + 8] = this.vertices[element.value.c - 1].z; - this.geometry.attributes.position.needsUpdate = true; + let vertices = this.geometry.vertices; + let f = element.value; let normal = - this.vertices[element.value.b - 1].clone().sub(this.vertices[element.value.a - 1]) - .cross(this.vertices[element.value.c - 1].clone().sub(this.vertices[element.value.a - 1])); + vertices[f.b].clone().sub(vertices[f.a]) + .cross(vertices[f.c].clone().sub(vertices[f.a])); normal.normalize(); - buf = this.geometry.attributes.normal.array; - buf[this.currentFace * 9 ] = normal.x; - buf[this.currentFace * 9 + 1] = normal.y; - buf[this.currentFace * 9 + 2] = normal.z; - buf[this.currentFace * 9 + 3] = normal.x; - buf[this.currentFace * 9 + 4] = normal.y; - buf[this.currentFace * 9 + 5] = normal.z; - buf[this.currentFace * 9 + 6] = normal.x; - buf[this.currentFace * 9 + 7] = normal.y; - buf[this.currentFace * 9 + 8] = normal.z; - this.geometry.attributes.normal.needsUpdate = true; - - this.currentFace++; + f.normal = normal; + this.geometry.faces.push(f); + this.geometry.elementsNeedUpdate = true; break; default: throw new Error("unknown element type: " + element.type); } - this.geometry.verticesNeedUpdate = true; - this.geometry.elementsNeedUpdate = true; } } diff --git a/src/main.js b/src/main.js index fcc0b02..bd0c101 100644 --- a/src/main.js +++ b/src/main.js @@ -5,7 +5,7 @@ animate(); function init() { - loader = new Loader('assets/bunny_low_res_scaled.obj'); + loader = new Loader('assets/bunny_translate.obj'); loader.start(function(elements) { for (let element of elements) { if (element !== undefined) {