将三个 js 纹理模型导出到带有 .MTL 文件的 .OBJ

Export a three js textured model to a .OBJ with .MTL file

我希望能够像本例中那样导出 obj 文件 http://threejs.org/examples/#webgl_exporter_obj

但是,我想在.mtl纹理文件中导出带有相应纹理的.obj文件(我见过带有"usemtl someTextureNameFromMTL"的obj文件)

我看过 this question but the exporter seems to be exporting only mesh. I have also found this question 但那只讨论进口商。

我想实现的是制作一个 3d 打印编辑器,它也可以导出 textures/colors,因为已经有一个用于 3d 打印的 .stl 网格导出器。但是,我没有找到三个 js 的 mesh+color/texture 导出器:(

我稍微扩展了 OBJExporter。它将 return 一个包含 .obj 部分和 .mtl 部分的对象。我没有测试就写下来,所以可能有错误,但我希望它是一个开始。

我没有查看所有的 mtl 值,我只是使用了一些除了颜色和纹理信息之外的标准值。也许我以后会改进它。您还需要注意 mtl 文件名。目前,我正在为 obj 部分写一个静态名称。保存文件时,mtl 文件的名称必须与声明的 obj 文件中的名称相同。否则3ds max等无法读取。

/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.OBJExporter = function () {};

THREE.OBJExporter.prototype = {

 constructor: THREE.OBJExporter,

 parse: function ( object ) {

 var output = '';
  var materials = {};

  var indexVertex = 0;
  var indexVertexUvs = 0;
  var indexNormals = 0;
       
 var mtlFileName = 'objmaterial'; // maybe this value can be passed as parameter
 output += 'mtllib ' + mtlFileName +  '.mtl\n';

  var parseMesh = function ( mesh ) {

   var nbVertex = 0;
   var nbVertexUvs = 0;
   var nbNormals = 0;

   var geometry = mesh.geometry;
   var material = mesh.material;

   if ( geometry instanceof THREE.Geometry ) {

    output += 'o ' + mesh.name + '\n';

    var vertices = geometry.vertices;

    for ( var i = 0, l = vertices.length; i < l; i ++ ) {

     var vertex = vertices[ i ].clone();
     vertex.applyMatrix4( mesh.matrixWorld );

     output += 'v ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n';

     nbVertex ++;

    }

    // uvs

    var faces = geometry.faces;
    var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
    var hasVertexUvs = faces.length === faceVertexUvs.length;

    if ( hasVertexUvs ) {

     for ( var i = 0, l = faceVertexUvs.length; i < l; i ++ ) {

      var vertexUvs = faceVertexUvs[ i ];

      for ( var j = 0, jl = vertexUvs.length; j < jl; j ++ ) {

       var uv = vertexUvs[ j ];

       output += 'vt ' + uv.x + ' ' + uv.y + '\n';

       nbVertexUvs ++;

      }

     }

    }

    // normals

    var normalMatrixWorld = new THREE.Matrix3();
    normalMatrixWorld.getNormalMatrix( mesh.matrixWorld );

    for ( var i = 0, l = faces.length; i < l; i ++ ) {

     var face = faces[ i ];
     var vertexNormals = face.vertexNormals;

     if ( vertexNormals.length === 3 ) {

      for ( var j = 0, jl = vertexNormals.length; j < jl; j ++ ) {

       var normal = vertexNormals[ j ].clone();
       normal.applyMatrix3( normalMatrixWorld );

       output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';

       nbNormals ++;

      }

     } else {

      var normal = face.normal.clone();
      normal.applyMatrix3( normalMatrixWorld );

      for ( var j = 0; j < 3; j ++ ) {

       output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';

       nbNormals ++;

      }

     }

    }
              
   // material
              
   if (material.name !== '')
    output += 'usemtl ' + material.name + '\n';
   else
    output += 'usemtl material' + material.id + '\n';
              
   materials[material.id] = material;

    // faces


    for ( var i = 0, j = 1, l = faces.length; i < l; i ++, j += 3 ) {

     var face = faces[ i ];

     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';

    }

   } else {

    console.warn( 'THREE.OBJExporter.parseMesh(): geometry type unsupported', mesh );
    // TODO: Support only BufferGeometry and use use setFromObject()

   }

   // update index
   indexVertex += nbVertex;
   indexVertexUvs += nbVertexUvs;
   indexNormals += nbNormals;

  };

  object.traverse( function ( child ) {

   if ( child instanceof THREE.Mesh ) parseMesh( child );

  } );
        
 // mtl output
      
 var mtlOutput = '';
      
 for (var key in materials) {
        
  var mat = materials[key];
          
  if (mat.name !== '')
   mtlOutput += 'newmtl ' + mat.name + '\n';
  else
   mtlOutput += 'newmtl material' + mat.id + '\n';
          
  mtlOutput += 'Ns 10.0000\n';
  mtlOutput += 'Ni 1.5000\n';
  mtlOutput += 'd 1.0000\n';
  mtlOutput += 'Tr 0.0000\n';
  mtlOutput += 'Tf 1.0000 1.0000 1.0000\n';
  mtlOutput += 'illum 2\n';
  mtlOutput += 'Ka ' + mat.color.r + ' ' + mat.color.g + ' ' + mat.color.b + ' ' + '\n';
  mtlOutput += 'Kd ' + mat.color.r + ' ' + mat.color.g + ' ' + mat.color.b + ' ' + '\n';
  mtlOutput += 'Ks 0.0000 0.0000 0.0000\n';
  mtlOutput += 'Ke 0.0000 0.0000 0.0000\n';
          
  if (mat.map && mat.map instanceof THREE.Texture) {
          
   var file = mat.map.image.currentSrc.slice( mat.map.image.currentSrc.slice.lastIndexOf("/"), mat.map.image.currentSrc.length - 1 );
            
   mtlOutput += 'map_Ka ' + file + '\n';
   mtlOutput += 'map_Kd ' + file + '\n';
            
  }
          
 }

 return {
  obj: output,
  mtl: mtlOutput
 }

 }

};

以下是使用文件保护程序和 JSZip 进行保存的方法

var oexporter = new THREE.OBJExporter();
var result = oexporter.parse(scene);
zip.file('mymodel.obj', result.obj);
zip.file('objmaterial.mtl', result.mtl);
var zz=zip.generate({ type: 'blob' });
saveAs(zz, 'mymodel.zip');

但是,我的问题是,当我使用 3DBuilder 加载模型时,我从文件加载到场景中的 3D 模型不是 saved.Only 我使用 three.js 函数创建的东西。