Support vertex edition
This commit is contained in:
parent
844f72f207
commit
635e5fef01
|
@ -1 +1,2 @@
|
||||||
assets
|
assets
|
||||||
|
js/main.js
|
||||||
|
|
198
js/main.js
198
js/main.js
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -24,12 +24,30 @@ function parseLine(line) {
|
||||||
switch (split[0]) {
|
switch (split[0]) {
|
||||||
case "v":
|
case "v":
|
||||||
element.type = Element.AddVertex;
|
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;
|
return element;
|
||||||
|
|
||||||
case "f":
|
case "f":
|
||||||
element.type = Element.AddFace;
|
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;
|
return element;
|
||||||
|
|
||||||
case "":
|
case "":
|
||||||
|
@ -45,6 +63,7 @@ function parseLine(line) {
|
||||||
const Element = {};
|
const Element = {};
|
||||||
Element.AddVertex = "AddVertex";
|
Element.AddVertex = "AddVertex";
|
||||||
Element.AddFace = "AddFace";
|
Element.AddFace = "AddFace";
|
||||||
|
Element.EditVertex = "EditVertex";
|
||||||
|
|
||||||
class Loader {
|
class Loader {
|
||||||
constructor(path, chunkSize = 1024, timeout = 20) {
|
constructor(path, chunkSize = 1024, timeout = 20) {
|
||||||
|
|
51
src/Model.js
51
src/Model.js
|
@ -1,60 +1,41 @@
|
||||||
class Model extends THREE.Mesh {
|
class Model extends THREE.Mesh {
|
||||||
constructor() {
|
constructor() {
|
||||||
let geometry = new THREE.BufferGeometry();
|
let geometry = new THREE.Geometry();
|
||||||
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});
|
let material = new THREE.MeshLambertMaterial({color: 0xffffff});
|
||||||
super(geometry, material);
|
super(geometry, material);
|
||||||
this.frustumCulled = false;
|
this.frustumCulled = false;
|
||||||
this.vertices = [];
|
this.vertices = [];
|
||||||
this.currentFace = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
manageElement(element) {
|
manageElement(element) {
|
||||||
switch (element.type) {
|
switch (element.type) {
|
||||||
case Element.AddVertex:
|
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;
|
break;
|
||||||
|
|
||||||
case Element.AddFace:
|
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 =
|
let normal =
|
||||||
this.vertices[element.value.b - 1].clone().sub(this.vertices[element.value.a - 1])
|
vertices[f.b].clone().sub(vertices[f.a])
|
||||||
.cross(this.vertices[element.value.c - 1].clone().sub(this.vertices[element.value.a - 1]));
|
.cross(vertices[f.c].clone().sub(vertices[f.a]));
|
||||||
normal.normalize();
|
normal.normalize();
|
||||||
|
|
||||||
buf = this.geometry.attributes.normal.array;
|
f.normal = normal;
|
||||||
buf[this.currentFace * 9 ] = normal.x;
|
this.geometry.faces.push(f);
|
||||||
buf[this.currentFace * 9 + 1] = normal.y;
|
this.geometry.elementsNeedUpdate = true;
|
||||||
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error("unknown element type: " + element.type);
|
throw new Error("unknown element type: " + element.type);
|
||||||
}
|
}
|
||||||
this.geometry.verticesNeedUpdate = true;
|
|
||||||
this.geometry.elementsNeedUpdate = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ animate();
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
|
|
||||||
loader = new Loader('assets/bunny_low_res_scaled.obj');
|
loader = new Loader('assets/bunny_translate.obj');
|
||||||
loader.start(function(elements) {
|
loader.start(function(elements) {
|
||||||
for (let element of elements) {
|
for (let element of elements) {
|
||||||
if (element !== undefined) {
|
if (element !== undefined) {
|
||||||
|
|
Loading…
Reference in New Issue