Support vertex edition
This commit is contained in:
		
							parent
							
								
									844f72f207
								
							
						
					
					
						commit
						635e5fef01
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1 +1,2 @@
 | 
			
		||||
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]) {
 | 
			
		||||
        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) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										51
									
								
								src/Model.js
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user