blockbench/js/io/formats/obj.js

249 lines
6.1 KiB
JavaScript
Raw Normal View History

2019-07-18 00:02:07 +08:00
(function() {
var _obj_export;
function getMtlFace(obj, index) {
2020-10-03 02:06:13 +08:00
//if (index % 2 == 1) index--;
var key = Canvas.face_order[index];
2019-07-18 00:02:07 +08:00
var tex = obj.faces[key].getTexture()
2018-10-18 01:50:25 +08:00
2019-07-18 00:02:07 +08:00
if (tex === null) {
return false
} else if (!tex || typeof tex === 'string') {
return 'usemtl none\n'
} else {
2020-07-16 15:32:59 +08:00
return 'usemtl m_' + tex.id + '\n';
2019-07-18 00:02:07 +08:00
}
}
var codec = new Codec('obj', {
name: 'OBJ Wavefront Model',
extension: 'obj',
compile(options) {
if (!options) options = 0;
2018-10-18 01:50:25 +08:00
2019-07-19 23:31:22 +08:00
var old_scene_position = new THREE.Vector3().copy(scene.position);
2019-07-18 00:02:07 +08:00
scene.position.set(0,0,0)
2018-10-18 01:50:25 +08:00
2019-07-18 00:02:07 +08:00
var output = '# Made in Blockbench '+appVersion+'\n';
var materials = {};
2018-10-18 01:50:25 +08:00
2019-07-18 00:02:07 +08:00
var indexVertex = 0;
var indexVertexUvs = 0;
var indexNormals = 0;
2018-10-18 01:50:25 +08:00
2019-07-18 00:02:07 +08:00
output += 'mtllib ' + (options.mtl_name||'materials.mtl') +'\n';
2018-10-18 01:50:25 +08:00
2020-01-24 01:53:36 +08:00
var scale = 1/16;
2018-10-18 01:50:25 +08:00
var parseMesh = function ( mesh ) {
var nbVertex = 0;
var nbVertexUvs = 0;
var nbNormals = 0;
var geometry = mesh.geometry;
2020-10-04 17:13:38 +08:00
var element = OutlinerElement.uuids[mesh.name];
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
if (!element) return;
2018-10-18 01:50:25 +08:00
if (element.export === false) return;
2019-08-01 06:01:47 +08:00
output += 'o ' + element.name + '\n';
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var vertices = geometry.vertices;
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
for ( var i = 0, l = vertices.length; i < l; i ++ ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var vertex = vertices[ i ].clone();
vertex.applyMatrix4( mesh.matrixWorld );
2018-10-18 01:50:25 +08:00
2020-01-24 01:53:36 +08:00
output += 'v ' + (vertex.x*scale) + ' ' + (vertex.y*scale) + ' ' + (vertex.z*scale) + '\n';
2019-08-01 06:01:47 +08:00
nbVertex ++;
}
// uvs
var faces = geometry.faces;
var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
var hasVertexUvs = faces.length === faceVertexUvs.length;
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
if ( hasVertexUvs ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
for ( var i = 0, l = faceVertexUvs.length; i < l; i ++ ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var vertexUvs = faceVertexUvs[ i ];
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
for ( var j = 0, jl = vertexUvs.length; j < jl; j ++ ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var uv = vertexUvs[ j ];
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
nbVertexUvs ++;
2018-10-18 01:50:25 +08:00
}
}
2019-08-01 06:01:47 +08:00
}
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
// normals
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var normalMatrixWorld = new THREE.Matrix3();
normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
for ( var i = 0, l = faces.length; i < l; i ++ ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var face = faces[ i ];
var vertexNormals = face.vertexNormals;
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
if ( vertexNormals.length === 3 ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
for ( var j = 0, jl = vertexNormals.length; j < jl; j ++ ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var normal = vertexNormals[ j ].clone();
normal.applyMatrix3( normalMatrixWorld );
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
nbNormals ++;
}
} else {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
var normal = face.normal.clone();
normal.applyMatrix3( normalMatrixWorld );
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
for ( var j = 0; j < 3; j ++ ) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
nbNormals ++;
2018-10-18 01:50:25 +08:00
}
}
2019-08-01 06:01:47 +08:00
}
// material
for (var face in element.faces) {
var tex = element.faces[face].getTexture()
if (tex && tex.uuid && !materials[tex.id]) {
materials[tex.id] = tex
2018-10-18 01:50:25 +08:00
}
2019-08-01 06:01:47 +08:00
}
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
for ( var i = 0, j = 1, l = faces.length; i < l; i ++, j += 3 ) {
2018-10-18 01:50:25 +08:00
2020-10-03 02:06:13 +08:00
var face = faces[ i ];
var f_mat = getMtlFace(element, face.materialIndex)
2019-08-01 06:01:47 +08:00
if (f_mat) {
2018-10-18 01:50:25 +08:00
2019-08-01 06:01:47 +08:00
if (i % 2 === 0) {
output += f_mat
2018-10-18 01:50:25 +08:00
}
2019-08-01 06:01:47 +08:00
output += 'f ';
output += ( indexVertex + face.a + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j ) + ' ';
output += ( indexVertex + face.b + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 1 ) : '' ) + '/' + ( indexNormals + j + 1 ) + ' ';
output += ( indexVertex + face.c + 1 ) + '/' + ( hasVertexUvs ? ( indexVertexUvs + j + 2 ) : '' ) + '/' + ( indexNormals + j + 2 ) + '\n';
2018-10-18 01:50:25 +08:00
}
}
// update index
indexVertex += nbVertex;
indexVertexUvs += nbVertexUvs;
indexNormals += nbNormals;
};
2019-07-18 00:02:07 +08:00
scene.traverse( function ( child ) {
2018-10-18 01:50:25 +08:00
if ( child instanceof THREE.Mesh ) parseMesh( child );
} );
2019-07-18 00:02:07 +08:00
// mtl output
var mtlOutput = '# Made in Blockbench '+appVersion+'\n';;
for (var key in materials) {
if (materials.hasOwnProperty(key) && materials[key]) {
var tex = materials[key];
2020-07-16 15:32:59 +08:00
mtlOutput += 'newmtl m_' +key+ '\n'
2019-07-18 00:02:07 +08:00
mtlOutput += `map_Kd ${tex.name} \n`;
}
2018-10-18 01:50:25 +08:00
}
2019-07-18 00:02:07 +08:00
mtlOutput += 'newmtl none'
2018-10-18 01:50:25 +08:00
2019-07-19 23:31:22 +08:00
scene.position.copy(old_scene_position)
2018-10-18 01:50:25 +08:00
2019-07-18 00:02:07 +08:00
_obj_export = {
obj: output,
mtl: mtlOutput,
images: materials
}
2020-03-05 03:56:17 +08:00
this.dispatchEvent('compile', {model: output, mtl: mtlOutput, images: materials});
2019-07-18 00:02:07 +08:00
return options.all_files ? _obj_export : output;
},
write(content, path) {
2019-07-19 23:31:22 +08:00
var scope = this;
2018-10-18 01:50:25 +08:00
2019-07-18 00:02:07 +08:00
var mtl_path = path.replace(/\.obj$/, '.mtl')
content = this.compile({mtl_name: pathToName(mtl_path, true)})
Blockbench.writeFile(path, {content}, path => scope.afterSave(path));
2018-10-18 01:50:25 +08:00
2019-07-18 00:02:07 +08:00
Blockbench.writeFile(mtl_path, {content: _obj_export.mtl});
for (var key in _obj_export.images) {
var texture = _obj_export.images[key]
if (texture && !texture.error) {
var name = texture.name;
if (name.substr(-4) !== '.png') {
name += '.png';
}
var image_path = path.split(osfs)
image_path.splice(-1, 1, texture.name)
Blockbench.writeFile(image_path.join(osfs), {
content: texture.source,
savetype: 'image'
})
}
}
},
export() {
var scope = this;
if (isApp) {
Blockbench.export({
2020-04-26 02:25:07 +08:00
resource_id: 'obj',
2019-07-18 00:02:07 +08:00
type: this.name,
extensions: [this.extension],
name: this.fileName(),
custom_writer: (a, b) => scope.write(a, b),
})
} else {
var archive = new JSZip();
var content = this.compile()
archive.file((Project.name||'model')+'.obj', content)
archive.file('materials.mtl', _obj_export.mtl)
for (var key in _obj_export.images) {
var texture = _obj_export.images[key]
if (texture && !texture.error && texture.mode === 'bitmap') {
archive.file(pathToName(texture.name) + '.png', texture.source.replace('data:image/png;base64,', ''), {base64: true});
}
}
archive.generateAsync({type: 'blob'}).then(content => {
Blockbench.export({
type: 'Zip Archive',
extensions: ['zip'],
name: 'assets',
content: content,
savetype: 'zip'
}, path => scope.afterDownload(path));
})
}
2018-10-18 01:50:25 +08:00
}
2019-07-18 00:02:07 +08:00
})
BARS.defineActions(function() {
codec.export_action = new Action({
id: 'export_obj',
icon: 'icon-objects',
category: 'file',
click: function () {
codec.export()
}
})
})
})()