Skip to content

Instantly share code, notes, and snippets.

@jcarletto27
Last active September 25, 2023 16:34
Show Gist options
  • Save jcarletto27/35b19f811c657ec73b0238d78413f88d to your computer and use it in GitHub Desktop.
Save jcarletto27/35b19f811c657ec73b0238d78413f88d to your computer and use it in GitHub Desktop.
Three.js OBJExporter, updated to work with bufferGeometry. Adds support for bones and morph data.
THREE.OBJExporter = function () {};
THREE.OBJExporter.prototype = {
constructor: THREE.OBJExporter,
parse: function (object) {
var output = '';
var indexVertex = 0;
var indexVertexUvs = 0;
var indexNormals = 0;
var vertex = new THREE.Vector3();
var normal = new THREE.Vector3();
var uv = new THREE.Vector2();
var i,
j,
l,
m,
face = [];
var parseMesh = function (mesh) {
var nbVertex = 0;
var nbNormals = 0;
var nbVertexUvs = 0;
var geometry = mesh.geometry;
var normalMatrixWorld = new THREE.Matrix3();
if (geometry instanceof THREE.Geometry) {
geometry = new THREE.BufferGeometry().setFromObject(mesh);
}
if (geometry instanceof THREE.BufferGeometry) {
var vertices = geometry.getAttribute('position');
var normals = geometry.getAttribute('normal');
var uvs = geometry.getAttribute('uv');
var indices = geometry.getIndex();
var skinIndices = geometry.getAttribute('skinIndex');
var weights = geometry.getAttribute('skinWeight');
var morphVector;
// name of the mesh object
output += 'o ' + mesh.name + '\n';
// vertices
if (vertices !== undefined) {
for (i = 0, l = vertices.count; i < l; i++, nbVertex++) {
if (skinIndices == undefined) {
vertex.x = vertices.getX(i);
vertex.y = vertices.getY(i);
vertex.z = vertices.getZ(i);
//vertex.applyMatrix4(mesh.matrixWorld);
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
} else {
vertex.x = vertices.getX(i);
vertex.y = vertices.getY(i);
vertex.z = vertices.getZ(i);
//vertex.applyMatrix4(mesh.matrixWorld);
skinIndex = [];
skinIndex[0] = skinIndices.getX(i);
skinIndex[1] = skinIndices.getY(i);
skinIndex[2] = skinIndices.getZ(i);
skinIndex[3] = skinIndices.getW(i);
skinWeight = [];
skinWeight[0] = weights.getX(i);
skinWeight[1] = weights.getY(i);
skinWeight[2] = weights.getZ(i);
skinWeight[3] = weights.getW(i);
inverses = [];
inverses[0] = mesh.skeleton.boneInverses[skinIndex[0]];
inverses[1] = mesh.skeleton.boneInverses[skinIndex[1]];
inverses[2] = mesh.skeleton.boneInverses[skinIndex[2]];
inverses[3] = mesh.skeleton.boneInverses[skinIndex[3]];
skinMatrices = [];
skinMatrices[0] = mesh.skeleton.bones[skinIndex[0]].matrixWorld;
skinMatrices[1] = mesh.skeleton.bones[skinIndex[1]].matrixWorld;
skinMatrices[2] = mesh.skeleton.bones[skinIndex[2]].matrixWorld;
skinMatrices[3] = mesh.skeleton.bones[skinIndex[3]].matrixWorld;
var finalVector = new THREE.Vector4();
if (geometry.morphTargetInfluences !== undefined) {
var morphAttributes = geometry.morphAttributes.position;
//console.log("Mesh Name:" + mesh.name);
morphMatricesX = [];
morphMatricesY = [];
morphMatricesZ = [];
morphMatricesInfluence = [];
var morphLength = geometry.morphAttributes.position.length;
//console.log("Morph Length " + morphLength);
for (var mt = 0; mt < morphLength; mt++) {
//collect the needed vertex info
morphMatricesX[mt] = morphAttributes[mt].getX(i);
morphMatricesY[mt] = morphAttributes[mt].getY(i);
morphMatricesZ[mt] = morphAttributes[mt].getZ(i);
morphMatricesInfluence[mt] = mesh.morphTargetInfluences[mt];
}
}
if (geometry.morphTargetInfluences !== undefined) {
morphVector = new THREE.Vector4(vertex.x, vertex.y, vertex.z);
var morphLength = geometry.morphAttributes.position.length;
for (var mt = 0; mt < morphLength; mt++) {
//not pretty, but it gets the job done
morphVector.lerp(new THREE.Vector4(morphMatricesX[mt], morphMatricesY[mt], morphMatricesZ[mt], 1), morphMatricesInfluence[mt]);
}
}
for (var k = 0; k < 4; k++) {
if (geometry.morphTargetInfluences !== undefined) {
var tempVector = new THREE.Vector4(morphVector.x, morphVector.y, morphVector.z);
} else {
var tempVector = new THREE.Vector4(vertex.x, vertex.y, vertex.z);
}
tempVector.multiplyScalar(skinWeight[k]);
//the inverse takes the vector into local bone space
//which is then transformed to the appropriate world space
tempVector.applyMatrix4(inverses[k]).applyMatrix4(skinMatrices[k]);
finalVector.add(tempVector);
}
// transform the vertex to export format
output += 'v ' + finalVector.x + ' ' + finalVector.y + ' ' + finalVector.z + '\n';
}
}
}
// uvs
if (uvs !== undefined) {
for (i = 0, l = uvs.count; i < l; i++, nbVertexUvs++) {
uv.x = uvs.getX(i);
uv.y = uvs.getY(i);
// transform the uv to export format
output += 'vt ' + uv.x + ' ' + uv.y + '\n';
}
}
// normals
if (normals !== undefined) {
normalMatrixWorld.getNormalMatrix(mesh.matrixWorld);
for (i = 0, l = normals.count; i < l; i++, nbNormals++) {
normal.x = normals.getX(i);
normal.y = normals.getY(i);
normal.z = normals.getZ(i);
// transfrom the normal to world space
normal.applyMatrix3(normalMatrixWorld);
// transform the normal to export format
output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
}
}
// faces
if (indices !== null) {
for (i = 0, l = indices.count; i < l; i += 3) {
for (m = 0; m < 3; m++) {
j = indices.getX(i + m) + 1;
face[m] = (indexVertex + j) + '/' + (uvs ? (indexVertexUvs + j) : '') + '/' + (indexNormals + j);
}
// transform the face to export format
output += 'f ' + face.join(' ') + "\n";
}
} else {
for (i = 0, l = vertices.count; i < l; i += 3) {
for (m = 0; m < 3; m++) {
j = i + m + 1;
face[m] = (indexVertex + j) + '/' + (uvs ? (indexVertexUvs + j) : '') + '/' + (indexNormals + j);
}
// transform the face to export format
output += 'f ' + face.join(' ') + "\n";
}
}
} else {
console.warn('THREE.OBJExporter.parseMesh(): geometry type unsupported', geometry);
}
// update index
indexVertex += nbVertex;
indexVertexUvs += nbVertexUvs;
indexNormals += nbNormals;
};
var parseLine = function (line) {
var nbVertex = 0;
var geometry = line.geometry;
var type = line.type;
if (geometry instanceof THREE.Geometry) {
geometry = new THREE.BufferGeometry().setFromObject(line);
}
if (geometry instanceof THREE.BufferGeometry) {
// shortcuts
var vertices = geometry.getAttribute('position');
var indices = geometry.getIndex();
// name of the line object
output += 'o ' + line.name + '\n';
if (vertices !== undefined) {
for (i = 0, l = vertices.count; i < l; i++, nbVertex++) {
vertex.x = vertices.getX(i);
vertex.y = vertices.getY(i);
vertex.z = vertices.getZ(i);
// transfrom the vertex to world space
vertex.applyMatrix4(line.matrixWorld);
// transform the vertex to export format
output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';
}
}
if (type === 'Line') {
output += 'l ';
for (j = 1, l = vertices.count; j <= l; j++) {
output += (indexVertex + j) + ' ';
}
output += '\n';
}
if (type === 'LineSegments') {
for (j = 1, k = j + 1, l = vertices.count; j < l; j += 2, k = j + 1) {
output += 'l ' + (indexVertex + j) + ' ' + (indexVertex + k) + '\n';
}
}
} else {
console.warn('THREE.OBJExporter.parseLine(): geometry type unsupported', geometry);
}
// update index
indexVertex += nbVertex;
};
object.traverse(function (child) {
if (child instanceof THREE.Mesh) {
parseMesh(child);
}
if (child instanceof THREE.Line) {
parseLine(child);
}
});
return output;
}
};
@EmmanueleVilla
Copy link

I know, I ask about how you config it to arrive to this mesh, I can get as T pose fairly but no more.

El 1 nov 2020, a las 9:45, Emmanuele Villa @.***> escribió: @EmmanueleVilla commented on this gist. Do you have any idea why? How you did it get working? What do you mean "working"? My example doesn't work at all, the exported model is a complete random mess — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://gist.github.com/35b19f811c657ec73b0238d78413f88d#gistcomment-3512061, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPMFVQU6KKUCXP77MWB2P3SNUN2NANCNFSM4SL7JYSQ.

I've changed the two lines that I wrote in my first comment, from skinWeigth to skinWeight0

@Wirpy
Copy link

Wirpy commented Sep 25, 2023

Does this work ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment