UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

144 lines (134 loc) 5.82 kB
// Sample Obj model parser. This is not added to built into the engine library by default. // // To use, first register the parser: // // // add parser to model resource handler // var objParser = new pc.ObjModelParser(this.app.graphicsDevice); // this.app.loader.getHandler("model").addParser(objParser, function (url) { // return (pc.path.getExtension(url) === '.obj'); // }); // // Then load obj as a model asset: // // var asset = new pc.Asset("MyObj", "model", { // url: "model.obj" // }); // this.app.assets.add(asset); // this.app.assets.load(asset); function ObjModelParser(device) { this._device = device; this._defaultMaterial = new pc.StandardMaterial(); } Object.assign(ObjModelParser.prototype, { // First draft obj parser // probably doesn't handle a lot of the obj spec // Known issues: // - can't handle meshes larger than 65535 verts // - assigns default material to all meshes // - doesn't created indexed geometry parse: function (input, callback) { // expanded vert, uv and normal values from face indices var parsed = { default: { verts: [], normals: [], uvs: [], indices: [] } }; var group = 'default'; // current group var lines = input.split('\n'); var verts = [], normals = [], uvs = []; var i; for (i = 0; i < lines.length; i++) { var line = lines[i].trim(); var parts = line.split(/\s+/); if (line[0] === 'v') { if (parts[0] === 'v') { verts.push(parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3])); } else if (parts[0] === 'vn') { normals.push(parseFloat(parts[1]), parseFloat(parts[2]), parseFloat(parts[3])); } else if (parts[0] === 'vt') { uvs.push(parseFloat(parts[1]), parseFloat(parts[2])); } } else if (line[0] === 'g' || line[0] === 'o' || line[0] === 'u') { // split into groups for 'g' 'o' and 'usemtl' elements group = parts[1]; // only first value for name for now if (!parsed[group]) { parsed[group] = { verts: [], normals: [], uvs: [] }; } } else if (line[0] === 'f') { var p, r; if (parts.length === 4) { // triangles for (p = 1; p < parts.length; p++) { r = this._parseIndices(parts[p]); parsed[group].verts.push(verts[r[0] * 3], verts[r[0] * 3 + 1], verts[r[0] * 3 + 2]); // expand uvs from indices if (r[1] * 2 < uvs.length) { parsed[group].uvs.push(uvs[r[1] * 2], uvs[r[1] * 2 + 1]); } // expand uvs from indices if (r[2] * 3 < normals.length) { parsed[group].normals.push(normals[r[2] * 3], normals[r[2] * 3 + 1], normals[r[2] * 3 + 2]); } // expand normals from indices } } else if (parts.length === 5) { // quads var order = [1, 2, 3, 3, 4, 1]; // split quad into to triangles; for (var o = 0; o < order.length; o++) { p = order[o]; r = this._parseIndices(parts[p]); parsed[group].verts.push(verts[r[0] * 3], verts[r[0] * 3 + 1], verts[r[0] * 3 + 2]); // expand uvs from indices if (r[1] * 2 < uvs.length) { parsed[group].uvs.push(uvs[r[1] * 2], uvs[r[1] * 2 + 1]); } // expand uvs from indices if (r[2] * 3 < normals.length) { parsed[group].normals.push(normals[r[2] * 3], normals[r[2] * 3 + 1], normals[r[2] * 3 + 2]); } // expand normals from indices } } else { console.error(pc.string.format('OBJ uses unsupported {0}-gons', parts.length - 1)); } } } var model = new pc.Model(); var groupNames = Object.keys(parsed); var root = new pc.GraphNode(); // create a new mesh instance for each "group" for (i = 0; i < groupNames.length; i++) { var currentGroup = parsed[groupNames[i]]; if (!currentGroup.verts.length) continue; if (currentGroup.verts.length > 65535) { console.warn('Warning: mesh with more than 65535 vertices'); } var geom = new pc.Geometry(); geom.positions = currentGroup.verts; if (currentGroup.normals.length > 0) { geom.normals = currentGroup.normals; } if (currentGroup.uvs.length > 0) { geom.uvs = currentGroup.uvs; } var mesh = pc.Mesh.fromGeometry(this._device, geom); var mi = new pc.MeshInstance(mesh, this._defaultMaterial, new pc.GraphNode()); model.meshInstances.push(mi); root.addChild(mi.node); } model.graph = root; model.getGraph().syncHierarchy(); callback(null, model); }, _parseIndices: function (str) { var result = []; var indices = str.split('/'); for (var i = 0; i < 3; i++) { if (indices[i]) { result[i] = parseInt(indices[i], 10) - 1; // convert to 0-indexed } } return result; } });