提交 7c0b2462 编写于 作者: M Mr.doob

Merge pull request #8443 from jonnenauha/objloader

ObjLoader improvements
......@@ -8,6 +8,31 @@ THREE.OBJLoader = function ( manager ) {
this.materials = null;
this.regexp = {
// v float float float
vertex_pattern : /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
// vn float float float
normal_pattern : /^vn\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
// vt float float
uv_pattern : /^vt\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/,
// f vertex vertex vertex
face_vertex : /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/,
// f vertex/uv vertex/uv vertex/uv
face_vertex_uv : /^f\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+))?/,
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal
face_vertex_uv_normal : /^f\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)\s+(-?\d+)\/(-?\d+)\/(-?\d+)(?:\s+(-?\d+)\/(-?\d+)\/(-?\d+))?/,
// f vertex//normal vertex//normal vertex//normal
face_vertex_normal : /^f\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)\s+(-?\d+)\/\/(-?\d+)(?:\s+(-?\d+)\/\/(-?\d+))?/,
// o object_name | g group_name
object_pattern : /^[og]\s*(.+)?/,
// s boolean
smoothing_pattern : /^s\s+(\d+|on|off)/,
// mtllib file_reference
material_library_pattern : /^mtllib /,
// usemtl material_name
material_use_pattern : /^usemtl /
};
};
THREE.OBJLoader.prototype = {
......@@ -40,315 +65,431 @@ THREE.OBJLoader.prototype = {
},
parse: function ( text ) {
console.time( 'OBJLoader' );
_createParserState : function()
{
var state = {
objects : [],
object : {},
vertices : [],
normals : [],
uvs : [],
materialLibraries : [],
startObject : function(name, fromDeclaration)
{
// If the current object (initial from reset) is not from a g/o declaration in the parsed
// file. We need to use it for the first parsed g/o to keep things in sync.
if ( this.object && this.object.fromDeclaration === false ) {
this.object.name = name;
this.object.fromDeclaration = (fromDeclaration !== false);
return;
}
var objects = [];
var object;
var foundObjects = false;
var vertices = [];
var normals = [];
var uvs = [];
this.object = {
name : name || '',
geometry : {
vertices : [],
normals : [],
uvs : []
},
material : {
name : '',
smooth : true
},
fromDeclaration : (fromDeclaration !== false)
};
this.objects.push(this.object);
},
function addObject( name ) {
parseVertexIndex : function( value, len ) {
var geometry = {
vertices: [],
normals: [],
uvs: []
};
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
var material = {
name: '',
smooth: true
};
},
object = {
name: name,
geometry: geometry,
material: material
};
parseNormalIndex : function( value, len ) {
objects.push( object );
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 3 ) * 3;
}
},
function parseVertexIndex( value ) {
parseUVIndex : function( value, len ) {
var index = parseInt( value );
var index = parseInt( value, 10 );
return ( index >= 0 ? index - 1 : index + len / 2 ) * 2;
return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3;
},
}
addVertex : function( a, b, c ) {
function parseNormalIndex( value ) {
var src = this.vertices;
this.object.geometry.vertices.push(src[ a ]);
this.object.geometry.vertices.push(src[ a + 1 ]);
this.object.geometry.vertices.push(src[ a + 2 ]);
this.object.geometry.vertices.push(src[ b ]);
this.object.geometry.vertices.push(src[ b + 1 ]);
this.object.geometry.vertices.push(src[ b + 2 ]);
this.object.geometry.vertices.push(src[ c ]);
this.object.geometry.vertices.push(src[ c + 1 ]);
this.object.geometry.vertices.push(src[ c + 2 ]);
var index = parseInt( value );
},
return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3;
addVertexLine : function( a )
{
}
var src = this.vertices;
this.object.geometry.vertices.push(src[ a ]);
this.object.geometry.vertices.push(src[ a + 1 ]);
this.object.geometry.vertices.push(src[ a + 2 ]);
function parseUVIndex( value ) {
},
var index = parseInt( value );
addNormal : function( a, b, c ) {
return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2;
var src = this.normals;
this.object.geometry.normals.push(src[ a ]);
this.object.geometry.normals.push(src[ a + 1 ]);
this.object.geometry.normals.push(src[ a + 2 ]);
this.object.geometry.normals.push(src[ b ]);
this.object.geometry.normals.push(src[ b + 1 ]);
this.object.geometry.normals.push(src[ b + 2 ]);
this.object.geometry.normals.push(src[ c ]);
this.object.geometry.normals.push(src[ c + 1 ]);
this.object.geometry.normals.push(src[ c + 2 ]);
}
},
function addVertex( a, b, c ) {
addUV : function( a, b, c ) {
object.geometry.vertices.push(
vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ],
vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ],
vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ]
);
var src = this.uvs;
this.object.geometry.uvs.push(src[ a ]);
this.object.geometry.uvs.push(src[ a + 1 ]);
this.object.geometry.uvs.push(src[ b ]);
this.object.geometry.uvs.push(src[ b + 1 ]);
this.object.geometry.uvs.push(src[ c ]);
this.object.geometry.uvs.push(src[ c + 1 ]);
}
},
function addNormal( a, b, c ) {
addUVLine : function( a ) {
object.geometry.normals.push(
normals[ a ], normals[ a + 1 ], normals[ a + 2 ],
normals[ b ], normals[ b + 1 ], normals[ b + 2 ],
normals[ c ], normals[ c + 1 ], normals[ c + 2 ]
);
var src = this.uvs;
this.object.geometry.uvs.push(src[ a ]);
this.object.geometry.uvs.push(src[ a + 1 ]);
}
},
function addUV( a, b, c ) {
addFace : function( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {
object.geometry.uvs.push(
uvs[ a ], uvs[ a + 1 ],
uvs[ b ], uvs[ b + 1 ],
uvs[ c ], uvs[ c + 1 ]
);
var vLen = this.vertices.length;
}
var ia = this.parseVertexIndex( a, vLen );
var ib = this.parseVertexIndex( b, vLen );
var ic = this.parseVertexIndex( c, vLen );
var id;
function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {
if ( d === undefined ) {
var ia = parseVertexIndex( a );
var ib = parseVertexIndex( b );
var ic = parseVertexIndex( c );
var id;
this.addVertex( ia, ib, ic );
if ( d === undefined ) {
} else {
addVertex( ia, ib, ic );
id = this.parseVertexIndex( d, vLen );
} else {
this.addVertex( ia, ib, id );
this.addVertex( ib, ic, id );
id = parseVertexIndex( d );
}
addVertex( ia, ib, id );
addVertex( ib, ic, id );
if ( ua !== undefined ) {
}
var uvLen = this.uvs.length;
if ( ua !== undefined ) {
ia = this.parseUVIndex( ua, uvLen );
ib = this.parseUVIndex( ub, uvLen );
ic = this.parseUVIndex( uc, uvLen );
ia = parseUVIndex( ua );
ib = parseUVIndex( ub );
ic = parseUVIndex( uc );
if ( d === undefined ) {
if ( d === undefined ) {
this.addUV( ia, ib, ic );
addUV( ia, ib, ic );
} else {
} else {
id = this.parseUVIndex( ud, uvLen );
id = parseUVIndex( ud );
this.addUV( ia, ib, id );
this.addUV( ib, ic, id );
addUV( ia, ib, id );
addUV( ib, ic, id );
}
}
}
if ( na !== undefined ) {
if ( na !== undefined ) {
// Normals are many times the same. If so, skip function call and parseInt.
var nLen = this.normals.length;
ia = this.parseNormalIndex( na, nLen );
ia = parseNormalIndex( na );
ib = parseNormalIndex( nb );
ic = parseNormalIndex( nc );
if (na === nb)
ib = ia;
else
ib = this.parseNormalIndex( nb, nLen );
if ( d === undefined ) {
if (na === nc)
ic = ia;
else
ic = this.parseNormalIndex( nc, nLen );
addNormal( ia, ib, ic );
if ( d === undefined ) {
} else {
this.addNormal( ia, ib, ic );
} else {
id = this.parseNormalIndex( nd, nLen );
id = parseNormalIndex( nd );
this.addNormal( ia, ib, id );
this.addNormal( ib, ic, id );
addNormal( ia, ib, id );
addNormal( ib, ic, id );
}
}
},
addLineGeometry : function(vertexes, uvs)
{
this.object.geometry.type = 'Line';
var vLen = this.vertices.length;
var uvLen = this.uvs.length;
for (var vi = 0, l = vertexes.length; vi < l; vi++) {
this.addVertexLine( this.parseVertexIndex( vertexes[vi], vLen ) );
}
for (var uvi = 0, l = uvs.length; uvi < l; uvi++) {
this.addUVLine( this.parseUVIndex( uvs[uvi], uvLen ) );
}
}
};
}
state.startObject('', false);
return state;
},
parse: function ( text ) {
addObject( '' );
console.time( 'OBJLoader' );
// v float float float
var vertex_pattern = /^v\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/;
var state = this._createParserState();
// vn float float float
var normal_pattern = /^vn\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/;
if ( text.indexOf('\r\n') !== -1 ) {
// This is faster than String.split with regex that splits on both
text = text.replace('\r\n', '\n');
}
// vt float float
var uv_pattern = /^vt\s+([\d|\.|\+|\-|e|E]+)\s+([\d|\.|\+|\-|e|E]+)/;
var lines = text.split( '\n' );
var line = '', lineFirstChar = '', lineSecondChar = '';
var lineLength = 0;
var result = [];
// f vertex vertex vertex ...
var face_pattern1 = /^f\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)(?:\s+(-?\d+))?/;
// Faster to just trim left side of the line. Use if available.
var trimLeft = (typeof ''.trimLeft === 'function');
// f vertex/uv vertex/uv vertex/uv ...
var face_pattern2 = /^f\s+((-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+))(?:\s+((-?\d+)\/(-?\d+)))?/;
for ( var i = 0, l = lines.length; i < l; i ++ ) {
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var face_pattern3 = /^f\s+((-?\d+)\/(-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+)\/(-?\d+))\s+((-?\d+)\/(-?\d+)\/(-?\d+))(?:\s+((-?\d+)\/(-?\d+)\/(-?\d+)))?/;
line = lines[ i ];
if (trimLeft)
line = line.trimLeft();
else
line = line.trim();
// f vertex//normal vertex//normal vertex//normal ...
var face_pattern4 = /^f\s+((-?\d+)\/\/(-?\d+))\s+((-?\d+)\/\/(-?\d+))\s+((-?\d+)\/\/(-?\d+))(?:\s+((-?\d+)\/\/(-?\d+)))?/;
lineLength = line.length;
if ( lineLength === 0 ) {
continue;
}
var object_pattern = /^[og]\s*(.+)?/;
lineFirstChar = line.charAt( 0 );
if ( lineFirstChar === '#' ) {
// @todo invoke passed in handler if any
continue;
}
var smoothing_pattern = /^s\s+(\d+|on|off)/;
if ( lineFirstChar === 'v' ) {
//
lineSecondChar = line.charAt( 1 );
var lines = text.split( '\n' );
if ( lineSecondChar === ' ' && ( result = this.regexp.vertex_pattern.exec( line ) ) !== null ) {
for ( var i = 0; i < lines.length; i ++ ) {
// 0 1 2 3
// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
var line = lines[ i ];
line = line.trim();
state.vertices.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
var result;
} else if ( lineSecondChar === 'n' && ( result = this.regexp.normal_pattern.exec( line ) ) !== null ) {
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
// 0 1 2 3
// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
continue;
state.normals.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
} else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
} else if ( lineSecondChar === 't' && ( result = this.regexp.uv_pattern.exec( line ) ) !== null ) {
// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
// 0 1 2
// ["vt 0.1 0.2", "0.1", "0.2"]
vertices.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
state.uvs.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] )
);
} else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
} else {
// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
throw new Error( "Unexpected vertex/normal/uv line: '" + line + "'");
normals.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
}
} else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
} else if ( lineFirstChar === "f" ) {
// ["vt 0.1 0.2", "0.1", "0.2"]
if ( ( result = this.regexp.face_vertex_uv_normal.exec( line ) ) !== null ) {
uvs.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] )
);
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal
// 0 1 2 3 4 5 6 7 8 9 10 11 12
// ["f 1/1/1 2/2/2 3/3/3", "1", "1", "1", "2", "2", "2", "3", "3", "3", undefined, undefined, undefined]
} else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
state.addFace(
result[ 1 ], result[ 4 ], result[ 7 ], result[ 10 ],
result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
);
// ["f 1 2 3", "1", "2", "3", undefined]
} else if ( ( result = this.regexp.face_vertex_uv.exec( line ) ) !== null ) {
addFace(
result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
);
// f vertex/uv vertex/uv vertex/uv
// 0 1 2 3 4 5 6 7 8
// ["f 1/1 2/2 3/3", "1", "1", "2", "2", "3", "3", undefined, undefined]
} else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
state.addFace(
result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
);
// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
} else if ( ( result = this.regexp.face_vertex_normal.exec( line ) ) !== null ) {
addFace(
result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
);
// f vertex//normal vertex//normal vertex//normal
// 0 1 2 3 4 5 6 7 8
// ["f 1//1 2//2 3//3", "1", "1", "2", "2", "3", "3", undefined, undefined]
} else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
state.addFace(
result[ 1 ], result[ 3 ], result[ 5 ], result[ 7 ],
undefined, undefined, undefined, undefined,
result[ 2 ], result[ 4 ], result[ 6 ], result[ 8 ]
);
// ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
} else if ( ( result = this.regexp.face_vertex.exec( line ) ) !== null ) {
addFace(
result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ],
result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ],
result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ]
);
// f vertex vertex vertex
// 0 1 2 3 4
// ["f 1 2 3", "1", "2", "3", undefined]
} else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
state.addFace(
result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
);
// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
} else {
addFace(
result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
undefined, undefined, undefined, undefined,
result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
);
throw new Error( "Unexpected face line: '" + line + "'");
} else if ( ( result = object_pattern.exec( line ) ) !== null ) {
}
// o object_name
// or
// g group_name
} else if ( lineFirstChar === "l" ) {
var name = result[ 0 ].substr( 1 ).trim();
var lineParts = line.substring(1).trim().split(" ");
var lineVertexes = [], lineUVs = [];
if ( foundObjects === false ) {
if (line.indexOf("/") === -1) {
foundObjects = true;
object.name = name;
lineVertexes = lineParts;
} else {
for (var li = 0, llen = lineParts.length; li < llen; li++) {
addObject( name );
var parts = lineParts[li].split("/");
if (parts[0] !== "")
lineVertexes.push(parts[0]);
if (parts[1] !== "")
lineUVs.push(parts[1])
}
}
state.addLineGeometry(lineVertexes, lineUVs);
} else if ( ( result = this.regexp.object_pattern.exec( line ) ) !== null ) {
// o object_name
// or
// g group_name
var name = result[ 0 ].substr( 1 ).trim();
state.startObject(name);
} else if ( /^usemtl /.test( line ) ) {
} else if ( this.regexp.material_use_pattern.test( line ) ) {
// material
object.material.name = line.substring( 7 ).trim();
state.object.material.name = line.substring( 7 ).trim();
} else if ( /^mtllib /.test( line ) ) {
} else if ( this.regexp.material_library_pattern.test( line ) ) {
// mtl file
} else if ( ( result = smoothing_pattern.exec( line ) ) !== null ) {
state.materialLibraries.push( line.substring( 7 ).trim() );
} else if ( ( result = this.regexp.smoothing_pattern.exec( line ) ) !== null ) {
// smooth shading
object.material.smooth = result[ 1 ] === "1" || result[ 1 ] === "on";
var value = result[ 1 ].trim().toLowerCase();
state.object.material.smooth = ( value === '1' || value === 'on' );
} else {
throw new Error( "Unexpected line: " + line );
// Handle null terminated files without exception
if (line === '\0')
continue;
throw new Error( "Unexpected line: '" + line + "'");
}
}
var container = new THREE.Group();
container.materialLibraries = [].concat(state.materialLibraries);
for ( var i = 0, l = objects.length; i < l; i ++ ) {
for ( var i = 0, l = state.objects.length; i < l; i ++ ) {
object = objects[ i ];
var object = state.objects[ i ];
var geometry = object.geometry;
var isLine = (geometry.type === 'Line');
// Skip o/g line declarations that did not follow with any faces
if ( geometry.vertices.length === 0 )
continue;
var buffergeometry = new THREE.BufferGeometry();
......@@ -376,18 +517,27 @@ THREE.OBJLoader.prototype = {
material = this.materials.create( object.material.name );
// mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
if (isLine && material && !(material instanceof THREE.LineBasicMaterial)) {
var materialLine = new THREE.LineBasicMaterial();
materialLine.copy(material);
material = materialLine;
}
}
if ( !material ) {
material = new THREE.MeshPhongMaterial();
material = ( !isLine ? new THREE.MeshPhongMaterial() : new THREE.LineBasicMaterial() );
material.name = object.material.name;
}
material.shading = object.material.smooth ? THREE.SmoothShading : THREE.FlatShading;
var mesh = new THREE.Mesh( buffergeometry, material );
var mesh = ( !isLine ? new THREE.Mesh( buffergeometry, material ) : new THREE.Line( buffergeometry, material ) );
mesh.name = object.name;
container.add( mesh );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册