Rewrite OBJ exporter to support quads

This commit is contained in:
JannisX11 2021-08-30 19:27:08 +02:00
parent ab15270057
commit 92d8d13c17

View File

@ -8,11 +8,19 @@ function getMtlFace(obj, index) {
if (tex === null) {
return false
} else if (!tex || typeof tex === 'string') {
return 'usemtl none\n'
return 'usemtl none'
} else {
return 'usemtl m_' + tex.id + '\n';
return 'usemtl m_' + tex.id;
}
}
const cube_face_normals = {
north: '0 0 -1',
east: '1 0 0',
south: '0 0 1',
west: '-1 0 0',
up: '0 1 0',
down: '0 -1 0',
}
var codec = new Codec('obj', {
name: 'OBJ Wavefront Model',
@ -29,7 +37,7 @@ var codec = new Codec('obj', {
*/
let materials = {};
let output = '# Made in Blockbench '+appVersion+'\n';
let output = ['# Made in Blockbench '+appVersion];
let indexVertex = 0;
let indexVertexUvs = 0;
let indexNormals = 0;
@ -39,7 +47,7 @@ var codec = new Codec('obj', {
const uv = new THREE.Vector2();
const face = [];
output += 'mtllib ' + (options.mtl_name||'materials.mtl') +'\n';
output.push('mtllib ' + (options.mtl_name||'materials.mtl') +'\n');
var scale = 1/16;
@ -57,16 +65,153 @@ var codec = new Codec('obj', {
if (element.export === false) return;
if (element instanceof Cube) {
output.push(`o ${element.name||'cube'}`)
function addVertex(x, y, z) {
vertex.set(x - element.origin[0], y - element.origin[1], z - element.origin[2]);
vertex.applyMatrix4( mesh.matrixWorld );
output.push('v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z);
nbVertex++;
}
addVertex(element.to[0] - element.inflate, element.to[1] - element.inflate, element.to[2] - element.inflate);
addVertex(element.to[0] - element.inflate, element.to[1] - element.inflate, element.from[2] - element.inflate);
addVertex(element.to[0] - element.inflate, element.from[1] - element.inflate, element.to[2] - element.inflate);
addVertex(element.to[0] - element.inflate, element.from[1] - element.inflate, element.from[2] - element.inflate);
addVertex(element.from[0] - element.inflate, element.to[1] - element.inflate, element.from[2] - element.inflate);
addVertex(element.from[0] - element.inflate, element.to[1] - element.inflate, element.to[2] - element.inflate);
addVertex(element.from[0] - element.inflate, element.from[1] - element.inflate, element.from[2] - element.inflate);
addVertex(element.from[0] - element.inflate, element.from[1] - element.inflate, element.to[2] - element.inflate);
for (let key in element.faces) {
if (element.faces[key].texture != null) {
let face = element.faces[key];
output.push(`vt ${face.uv[0] / Project.texture_width} ${1 - face.uv[1] / Project.texture_height}`);
output.push(`vt ${face.uv[2] / Project.texture_width} ${1 - face.uv[1] / Project.texture_height}`);
output.push(`vt ${face.uv[2] / Project.texture_width} ${1 - face.uv[3] / Project.texture_height}`);
output.push(`vt ${face.uv[0] / Project.texture_width} ${1 - face.uv[3] / Project.texture_height}`);
nbVertexUvs += 4;
}
}
for (let key in element.faces) {
if (element.faces[key].texture != null) {
output.push(`vn ${cube_face_normals[key]}`)
nbNormals += 1;
}
}
let mtl;
let i = 0;
for (let key in element.faces) {
if (element.faces[key].texture != null) {
let tex = element.faces[key].getTexture()
if (tex && tex.uuid && !materials[tex.id]) {
materials[tex.id] = tex;
}
let mtl_new = (!tex || typeof tex === 'string')
? 'none'
: 'm_' + tex.id;
if (mtl_new != mtl) {
mtl = mtl_new;
output.push('usemtl '+mtl);
}
let vertices;
switch (key) {
case 'north': vertices = [2, 5, 7, 4]; break;
case 'east': vertices = [1, 2, 4, 3]; break;
case 'south': vertices = [1, 6, 8, 3]; break;
case 'west': vertices = [5, 6, 8, 7]; break;
case 'up': vertices = [5, 2, 1, 6]; break;
case 'down': vertices = [8, 3, 4, 7]; break;
}
output.push('f '+[
`${vertices[0] + indexVertex}/${i*4 + 1 + indexVertexUvs}/${i+1+indexNormals}`,
`${vertices[1] + indexVertex}/${i*4 + 2 + indexVertexUvs}/${i+1+indexNormals}`,
`${vertices[2] + indexVertex}/${i*4 + 3 + indexVertexUvs}/${i+1+indexNormals}`,
`${vertices[3] + indexVertex}/${i*4 + 4 + indexVertexUvs}/${i+1+indexNormals}`,
].join(' '));
i++;
}
}
} else if (element instanceof Mesh) {
output.push(`o ${element.name||'mesh'}`)
let vertex_keys = [];
function addVertex(x, y, z) {
vertex.set(x - element.origin[0], y - element.origin[1], z - element.origin[2]);
vertex.applyMatrix4( mesh.matrixWorld );
output.push('v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z);
nbVertex++;
}
for (let vkey in element.vertices) {
addVertex(...element.vertices[vkey]);
vertex_keys.push(vkey);
}
let mtl;
let i = 0;
let vertexnormals = [];
let faces = [];
for (let key in element.faces) {
if (element.faces[key].texture != null && element.faces[key].vertices.length >= 3) {
let face = element.faces[key];
let vertices = face.getSortedVertices();
let tex = element.faces[key].getTexture();
vertices.forEach(vkey => {
output.push(`vt ${face.uv[vkey][0] / Project.texture_width} ${1 - face.uv[vkey][1] / Project.texture_height}`);
nbVertexUvs += 1;
})
vertexnormals.push(`vn ${face.getNormal(true).join(' ')}`)
nbNormals += 1;
if (tex && tex.uuid && !materials[tex.id]) {
materials[tex.id] = tex;
}
let mtl_new = (!tex || typeof tex === 'string')
? 'none'
: 'm_' + tex.id;
if (mtl_new != mtl) {
mtl = mtl_new;
faces.push('usemtl '+mtl);
}
let triplets = [];
vertices.forEach((vkey, vi) => {
let triplet = [
vertex_keys.indexOf(vkey) + 1 + indexVertex,
nbVertexUvs - vertices.length + vi + 1 + indexVertexUvs,
i+1+indexNormals,
]
triplets.push(triplet.join('/'));
})
faces.push('f ' + triplets.join(' '));
i++;
}
}
output.push(...vertexnormals);
output.push(...faces);
} else {
const vertices = geometry.getAttribute( 'position' );
const normals = geometry.getAttribute( 'normal' );
const uvs = geometry.getAttribute( 'uv' );
const indices = geometry.getIndex(); // name of the mesh object
const indices = geometry.getIndex();
output += 'o ' + mesh.name + '\n'; // name of the mesh material
output.push('o ' + mesh.name); // name of the mesh material
if ( mesh.material && mesh.material.name ) {
output += 'usemtl ' + mesh.material.name + '\n';
output.push('usemtl ' + mesh.material.name);
} // vertices
@ -81,7 +226,7 @@ var codec = new Codec('obj', {
vertex.applyMatrix4( mesh.matrixWorld ); // transform the vertex to export format
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
output.push('v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z);
}
@ -95,7 +240,7 @@ var codec = new Codec('obj', {
uv.x = uvs.getX( i );
uv.y = uvs.getY( i ); // transform the uv to export format
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
output.push('vt ' + uv.x + ' ' + uv.y);
}
@ -114,7 +259,7 @@ var codec = new Codec('obj', {
normal.applyMatrix3( normalMatrixWorld ).normalize(); // transform the normal to export format
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
output.push('vn ' + normal.x + ' ' + normal.y + ' ' + normal.z );
}
@ -137,7 +282,7 @@ var codec = new Codec('obj', {
if (f_mat) {
if (i % 2 === 0) {
output += f_mat
output.push(f_mat)
}
for ( let m = 0; m < 3; m ++ ) {
@ -148,7 +293,7 @@ var codec = new Codec('obj', {
} // transform the face to export format
output += 'f ' + face.join( ' ' ) + '\n';
output.push('f ' + face.join( ' ' ) );
}
}
@ -164,11 +309,12 @@ var codec = new Codec('obj', {
} // transform the face to export format
output += 'f ' + face.join( ' ' ) + '\n';
output.push('f ' + face.join( ' ' ) );
}
}
}
// update index
indexVertex += nbVertex;
@ -196,6 +342,8 @@ var codec = new Codec('obj', {
scene.position.copy(old_scene_position)
output = output.join('\n');
_obj_export = {
obj: output,
mtl: mtlOutput,