forked from playcanvas/engine
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobj-model.js
More file actions
138 lines (130 loc) · 5.7 KB
/
obj-model.js
File metadata and controls
138 lines (130 loc) · 5.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
pc.extend(pc, function () {
/**
* Sample Obj model parser. This is not added to applications by default.
*
* To use:
* @example
* // add parser to model resource handler
* this.app.loader.getHandler("model").addParser(new pc.ObjModelParser(this.app.graphicsDevice), function (url) {
* return (pc.path.getExtension(url) === '.obj');
* });
* Then load obj as a model asset
* e.g.
* var asset = new pc.Asset("MyObj", "model", {
* url: "model.obj"
* });
* this.app.assets.add(asset);
* this.app.assets.load(asset);
*/
var ObjModelParser = function (device) {
this._device = device;
};
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) {
// 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
parsed[group].uvs.push(uvs[r[1]*2], uvs[r[1]*2+1]); // expand uvs from indices
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;
p = 1;
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 mesh = pc.createMesh(this._device, currentGroup.verts, {
normals: currentGroup.normals,
uvs: currentGroup.uvs
});
var mi = new pc.MeshInstance(new pc.GraphNode(), mesh, pc.ModelHandler.DEFAULT_MATERIAL);
model.meshInstances.push(mi);
root.addChild(mi.node);
}
model.graph = root;
model.getGraph().syncHierarchy();
return 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;
}
};
return {
ObjModelParser: ObjModelParser
};
}());