IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> unity 导出 stl -> 正文阅读

[游戏开发]unity 导出 stl

Unity导出stl格式

stl是常用的3D打印格式,目前有不少文章介绍stl的,这里不多介绍。
导出stl分为ascii形式和二进制形式,区别在于ascii可以直接用文本文件打开查看,而二进制直接打开是乱码,但是二进制形式读写速度较快,生成的文件也比ascii要小很多。

开发环境

unity:2018.2.16 2019.3.15
模型查看工具:Meshlab2020.09CAD Assistant
测试模型:assetstore 上 的 office building

核心模块

  • ASCII形式 将单个mesh写出为stl
		/// <summary>
        /// 将单个mesh数据使用StreamWrite写出为stl
        /// </summary>
        /// <param name="mesh">待导出的mesh</param>
        /// <param name="sw">输出流</param>
        /// <param name="trans">mesh对应的transform,用于将顶点法线转到世界空间</param>
        /// <param name="exchangeCoordinate">是否需要变换坐标手系,unity是左手坐标系,默认变换到右手坐标系</param>
        private static void ExportMeshToStl(Mesh mesh, StreamWriter sw, Transform trans, bool exchangeCoordinate = true)
        {
            for (int j = 0; j < mesh.subMeshCount; j++)
            {
                int[] tris;
                if (mesh.subMeshCount == 1)
                {
                    sw.Write("\nsolid " + mesh.name + "\n");
                    tris = mesh.triangles;
                }
                else
                {
                    sw.Write("\nsolid " + mesh.name + "_" + j + "\n");
                    tris = mesh.GetIndices(j);
                }
                Vector3[] vertices = mesh.vertices;
                Vector3[] normals = mesh.normals;
                for (int i = 0; i < tris.Length / 3; i++)
                {
                	//法线变换到世界空间
                    Vector3 nor1 = trans.TransformDirection(normals[tris[i * 3]]);
                    Vector3 nor2 = trans.TransformDirection(normals[tris[i * 3 + 1]]);
                    Vector3 nor3 = trans.TransformDirection(normals[tris[i * 3 + 2]]);
					//顶点变换到世界空间
                    Vector3 worldPos1 = trans.TransformPoint(vertices[tris[i * 3]]);
                    Vector3 worldPos2 = trans.TransformPoint(vertices[tris[i * 3 + 1]]);
                    Vector3 worldPos3 = trans.TransformPoint(vertices[tris[i * 3 + 2]]);
					//如果需要从左手系变换到右手系
                    if (exchangeCoordinate)
                    {
                        nor1.x *= -1;
                        nor2.x *= -1;
                        nor3.x *= -1;
                        worldPos1.x *= -1;
                        worldPos2.x *= -1;
                        worldPos3.x *= -1;
                    }

                    Vector3 normal = (nor1 + nor2 + nor3) / 3;
                    sw.Write("\tfacet normal " + normal.x + " " + normal.y + " " + normal.z);
                    sw.Write("\n\t\touter loop\n");

                    sw.Write("\t\t\tvertex " + worldPos1.x + " " + worldPos1.y + " " + worldPos1.z + "\n");
                    if (exchangeCoordinate)
                    {
                        sw.Write("\t\t\tvertex " + worldPos3.x + " " + worldPos3.y + " " + worldPos3.z + "\n");
                        sw.Write("\t\t\tvertex " + worldPos2.x + " " + worldPos2.y + " " + worldPos2.z + "\n");
                    }
                    else
                    {
                        sw.Write("\t\t\tvertex " + worldPos2.x + " " + worldPos2.y + " " + worldPos2.z + "\n");
                        sw.Write("\t\t\tvertex " + worldPos3.x + " " + worldPos3.y + " " + worldPos3.z + "\n");
                    }
                    sw.Write("\t\tendloop\n");
                    sw.Write("\tendfacet\n");
                }
                if (mesh.subMeshCount == 1)
                {
                    sw.Write("endsolid " + mesh.name);
                }
                else
                {
                    sw.Write("endsolid " + mesh.name + "_" + j);
                }
            }
        }
  • 二进制形式 将单个mesh写出为stl
		/// <summary>
        /// 将单个mesh数据使用StreamWrite写出为stl,二进制格式
        /// </summary>
        /// <param name="mesh">待导出的mesh</param>
        /// <param name="bw">BinaryWriter 写出二进制数据的类</param>
        /// <param name="trans">mesh对应的transform,用于将顶点法线转到世界空间</param>
        /// <param name="exchangeCoordinate">是否需要变换坐标手系,unity是左手坐标系,默认变换到右手坐标系</param>
        private static void ExportMeshToStl(Mesh mesh, BinaryWriter bw, Transform trans, bool exchangeCoordinate = true)
        {

            Vector3[] vertices = mesh.vertices;
            Vector3[] normals = mesh.normals;
            int[] tris = mesh.triangles;
            //每个三角面片固定占用50个字节
            for (int i = 0; i < tris.Length / 3; i++)
            {
                Vector3 nor1 = trans.TransformDirection(normals[tris[i * 3]]);
                Vector3 nor2 = trans.TransformDirection(normals[tris[i * 3 + 1]]);
                Vector3 nor3 = trans.TransformDirection(normals[tris[i * 3 + 2]]);

                Vector3 worldPos1 = trans.TransformPoint(vertices[tris[i * 3]]);
                Vector3 worldPos2 = trans.TransformPoint(vertices[tris[i * 3 + 1]]);
                Vector3 worldPos3 = trans.TransformPoint(vertices[tris[i * 3 + 2]]);

                if (exchangeCoordinate)
                {
                    nor1.x *= -1;
                    nor2.x *= -1;
                    nor3.x *= -1;
                    worldPos1.x *= -1;
                    worldPos2.x *= -1;
                    worldPos3.x *= -1;
                }

                Vector3 normal = (nor1 + nor2 + nor3) / 3;
                bw.Write(normal.x);
                bw.Write(normal.y);
                bw.Write(normal.z);
                bw.Write(worldPos1.x);
                bw.Write(worldPos1.y);
                bw.Write(worldPos1.z);
                if (exchangeCoordinate)
                {
                    bw.Write(worldPos3.x);
                    bw.Write(worldPos3.y);
                    bw.Write(worldPos3.z);
                    bw.Write(worldPos2.x);
                    bw.Write(worldPos2.y);
                    bw.Write(worldPos2.z);
                }
                else
                {
                    bw.Write(worldPos2.x);
                    bw.Write(worldPos2.y);
                    bw.Write(worldPos2.z);
                    bw.Write(worldPos3.x);
                    bw.Write(worldPos3.y);
                    bw.Write(worldPos3.z);
                }
                
                //填充两个字节  三角面片的最后2个字节用来描述三角面片的属性信息(包括颜色属性等)暂时没有用
                bw.Seek(2, SeekOrigin.Current);
            }
        }

完整代码

/****************************************************
    文件:Exporter.cs
	作者:TKB
    邮箱: 544726237@qq.com
    日期:2021/7/24 23:9:12
	功能:导出stl
*****************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;

namespace TLib
{
    public class Exporter
    {
     	#region 导出stl
        /// <summary>
        /// 导出Transfrom及其子mesh为单个stl
        /// </summary>
        /// <param name="trans">待导出的transfrom</param>
        /// <param name="outputPath">导出的stl完整路径,如D:/TKB/output.stl</param>
        /// <param name="exchangeCoordinate">是否要变换坐标系,从左手坐标系(unity)变换到右手坐标系,默认为true</param>
        /// <param name="isBinary">是否以格式导出</param>
        public static void ExportStl(Transform trans, string outputPath, bool exchangeCoordinate = true, bool isBinary = true)
        {
            ExportStl(trans.gameObject, outputPath, exchangeCoordinate, isBinary);
        }

        /// <summary>
        /// 导出GameObject及其子mesh为单个stl
        /// </summary>
        /// <param name="go">待导出的GameObject</param>
        /// <param name="outputPath">导出的stl完整路径,如D:/TKB/output.stl</param>
        /// <param name="exchangeCoordinate">是否要变换坐标系,从左手坐标系(unity)变换到右手坐标系,默认为true</param>
        /// <param name="isBinary">是否以格式导出</param>
        public static void ExportStl(GameObject go, string outputPath, bool exchangeCoordinate = true, bool isBinary = true)
        {
            if (!go) return;
            if (!Directory.Exists(Path.GetDirectoryName(outputPath)))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
            }
            if (File.Exists(outputPath))
            {
                try
                {
                    File.Delete(outputPath);
                    Debug.LogWarning("该路径已存在同名文件,已删除!" + outputPath);
                }
                catch (Exception e)
                {
                    Debug.LogError(e + "该路径已存在同名文件并且删除失败!" + outputPath);
                    return;
                }
            }

            MeshFilter[] meshFilters = go.GetComponentsInChildren<MeshFilter>();
            SkinnedMeshRenderer[] skinnedMeshRenderers = go.GetComponentsInChildren<SkinnedMeshRenderer>();
            int meshCount = meshFilters.Length + skinnedMeshRenderers.Length;
            try
            {
                FileStream meshFS = new FileStream(outputPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); ;
                StreamWriter meshSW = null;
                BinaryWriter meshBW = null;
                if (!isBinary)
                {
                    meshSW = new StreamWriter(meshFS, Encoding.UTF8);
                }
                else
                {
                    meshBW = new BinaryWriter(meshFS, Encoding.UTF8);
                    //文件的起始80字节是文件头存储零件名,可以放入任何文字信息
                    meshBW.Write(go.name);
                    meshBW.Seek(80, SeekOrigin.Begin);
                    //紧随着用4个字节的整数来描述实体的三角面片个数
                    int count = 0;
                    for (int i = 0; i < meshFilters.Length; i++)
                    {
                        Mesh mesh;
#if UNITY_EDITOR
                        mesh = meshFilters[i].sharedMesh;
                        
#else
                        mesh = meshFilters[i].mesh;
#endif
                        count += mesh.triangles.Length;
                    }
                    for (int i = 0; i < skinnedMeshRenderers.Length; i++)
                    {
                        Mesh mesh;
#if UNITY_EDITOR
                        mesh = skinnedMeshRenderers[i].sharedMesh;
                        
#else
                        mesh = meshFilters[i].mesh;
#endif
                        count += mesh.triangles.Length;
                    }
                    meshBW.Write(count/3);
                }

                for (int i = 0; i < meshFilters.Length; i++)
                {
                    Mesh mesh;
#if UNITY_EDITOR
                    mesh = meshFilters[i].sharedMesh;
                    UnityEditor.EditorUtility.DisplayProgressBar("导出Stl", mesh.name + ":" + i + "/" + meshCount, i * 1.0f / meshCount);
#else
                    mesh = meshFilters[i].mesh;
#endif
                    if (!isBinary)
                        ExportMeshToStl(mesh, meshSW, meshFilters[i].transform, exchangeCoordinate);
                    else
                        ExportMeshToStl(mesh, meshBW, meshFilters[i].transform, exchangeCoordinate);
                }
                for (int i = 0; i < skinnedMeshRenderers.Length; i++)
                {
                    Mesh mesh;
#if UNITY_EDITOR
                    mesh = skinnedMeshRenderers[i].sharedMesh;
                    UnityEditor.EditorUtility.DisplayProgressBar("导出Stl", mesh.name + ":" + (i + meshFilters.Length) + "/" + meshCount, i * 1.0f / meshCount);
#else
                    mesh = meshFilters[i].mesh;
#endif
                    if (!isBinary)
                        ExportMeshToStl(mesh, meshSW, skinnedMeshRenderers[i].transform, exchangeCoordinate);
                    else
                        ExportMeshToStl(mesh, meshBW, skinnedMeshRenderers[i].transform, exchangeCoordinate);
                }
                if (!isBinary)
                {
                    meshSW.Close();
                }
                else
                {
                    meshBW.Close();
                }
                meshFS.Close();
            }
            catch (Exception e)
            {
                Debug.LogError(e);
            }
            finally
            {
                UnityEditor.EditorUtility.ClearProgressBar();
            }
           
        }

        /// <summary>
        /// 将Transform及其子对象导出为多个stl,每个mesh对应一个
        /// </summary>
        /// <param name="trans">待导出的Transform</param>
        /// <param name="outputDir">导出的文件夹路径,stl存放的位置</param>
        /// <param name="exchangeCoordinate">是否要变换坐标系,从左手坐标系(unity)变换到右手坐标系,默认为true</param>
        ///  <param name="isBinary">是否以格式导出</param>
        public static void ExportStls(Transform trans, string outputDir, bool exchangeCoordinate = true, bool isBinary = true)
        {
            ExportStls(trans.gameObject, outputDir, exchangeCoordinate, isBinary);
        }

        /// <summary>
        ///  将GameObject及其子对象导出为多个stl,每个mesh对应一个
        /// </summary>
        /// <param name="go">待导出的GameObject</param>
        /// <param name="outputDir">导出的文件夹路径,stl存放的位置</param>
        /// <param name="exchangeCoordinate">是否要变换坐标系,从左手坐标系(unity)变换到右手坐标系,默认为true</param>
        ///  <param name="isBinary">是否以格式导出</param>
        public static void ExportStls(GameObject go, string outputDir, bool exchangeCoordinate = true, bool isBinary = true)
        {
            if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir);
            MeshFilter[] meshFilters = go.GetComponentsInChildren<MeshFilter>();
            SkinnedMeshRenderer[] skinnedMeshRenderers = go.GetComponentsInChildren<SkinnedMeshRenderer>();
            Dictionary<string, int> meshNameDic = new Dictionary<string, int>();
            int meshCount = meshFilters.Length + skinnedMeshRenderers.Length;
            for (int i = 0; i < meshFilters.Length; i++)
            {
                try
                {
                    string name = meshFilters[i].gameObject.name;
                    if (meshNameDic.ContainsKey(name))
                    {
                        meshNameDic[name]++;
                        name += meshNameDic[name];
                    }
                    else meshNameDic.Add(name, 0);
                    string stlPath = Path.Combine(outputDir, name + ".stl");
                    FileStream meshFS = new FileStream(stlPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                    StreamWriter meshSW = null;
                    BinaryWriter meshBW = null;

                    Mesh mesh;
#if UNITY_EDITOR
                    mesh = meshFilters[i].sharedMesh;
                    UnityEditor.EditorUtility.DisplayProgressBar("导出Stl", mesh.name + ":" + i + "/" + meshCount, i * 1.0f / meshCount);
#else
                    mesh = meshFilters[i].mesh;
#endif
                    if (!isBinary)
                    {
                        meshSW = new StreamWriter(meshFS, Encoding.UTF8);
                        ExportMeshToStl(mesh, meshSW, meshFilters[i].transform, exchangeCoordinate);
                        meshSW.Close();
                    }
                    else
                    {
                        meshBW = new BinaryWriter(meshFS, Encoding.UTF8);
                        //文件的起始80字节是文件头存储零件名,可以放入任何文字信息
                        meshBW.Write(name);
                        meshBW.Seek(80, SeekOrigin.Begin);
                        meshBW.Write(mesh.triangles.Length / 3);
                        ExportMeshToStl(mesh, meshBW, meshFilters[i].transform, exchangeCoordinate);
                        meshBW.Close();
                    }
                    meshFS.Close();
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }
            }
            for (int i = 0; i < skinnedMeshRenderers.Length; i++)
            {
                try
                {
                    string name = skinnedMeshRenderers[i].gameObject.name;
                    if (meshNameDic.ContainsKey(name))
                    {
                        name += meshNameDic[name];
                        meshNameDic[name]++;
                    }
                    else meshNameDic.Add(name, 1);
                    string stlPath = Path.Combine(outputDir, name + ".stl");
                    FileStream meshFS = new FileStream(stlPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                    StreamWriter meshSW = null;
                    BinaryWriter meshBW = null;

                    Mesh mesh;
#if UNITY_EDITOR
                    mesh = skinnedMeshRenderers[i].sharedMesh;
                    UnityEditor.EditorUtility.DisplayProgressBar("导出Stl", mesh.name + ":" + (i + meshFilters.Length) + "/" + meshCount, i * 1.0f / meshCount);
#else
                    mesh = meshFilters[i].mesh;
materials;
#endif
                    if (!isBinary)
                    {
                        meshSW = new StreamWriter(meshFS, Encoding.UTF8);
                        ExportMeshToStl(mesh, meshSW, skinnedMeshRenderers[i].transform, exchangeCoordinate);
                        meshSW.Close();
                    }
                    else
                    {
                        meshBW = new BinaryWriter(meshFS, Encoding.UTF8);
                        //文件的起始80字节是文件头存储零件名,可以放入任何文字信息
                        meshBW.Write(name);
                        meshBW.Seek(80, SeekOrigin.Begin);
                        meshBW.Write(mesh.triangles.Length / 3);
                        ExportMeshToStl(mesh, meshBW, skinnedMeshRenderers[i].transform, exchangeCoordinate);
                        meshBW.Close();
                    }
                    meshFS.Close();
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }
            }
            UnityEditor.EditorUtility.ClearProgressBar();
        }
        /// <summary>
        /// 将单个mesh数据使用StreamWrite写出为stl
        /// </summary>
        /// <param name="mesh">待导出的mesh</param>
        /// <param name="sw">输出流</param>
        /// <param name="trans">mesh对应的transform,用于将顶点法线转到世界空间</param>
        /// <param name="exchangeCoordinate">是否需要变换坐标手系,unity是左手坐标系,默认变换到右手坐标系</param>
        private static void ExportMeshToStl(Mesh mesh, StreamWriter sw, Transform trans, bool exchangeCoordinate = true)
        {
            for (int j = 0; j < mesh.subMeshCount; j++)
            {
                int[] tris;
                if (mesh.subMeshCount == 1)
                {
                    sw.Write("\nsolid " + mesh.name + "\n");
                    tris = mesh.triangles;
                }
                else
                {
                    sw.Write("\nsolid " + mesh.name + "_" + j + "\n");
                    tris = mesh.GetIndices(j);
                }
                Vector3[] vertices = mesh.vertices;
                Vector3[] normals = mesh.normals;
                for (int i = 0; i < tris.Length / 3; i++)
                {
                    Vector3 nor1 = trans.TransformDirection(normals[tris[i * 3]]);
                    Vector3 nor2 = trans.TransformDirection(normals[tris[i * 3 + 1]]);
                    Vector3 nor3 = trans.TransformDirection(normals[tris[i * 3 + 2]]);

                    Vector3 worldPos1 = trans.TransformPoint(vertices[tris[i * 3]]);
                    Vector3 worldPos2 = trans.TransformPoint(vertices[tris[i * 3 + 1]]);
                    Vector3 worldPos3 = trans.TransformPoint(vertices[tris[i * 3 + 2]]);

                    if (exchangeCoordinate)
                    {
                        nor1.x *= -1;
                        nor2.x *= -1;
                        nor3.x *= -1;
                        worldPos1.x *= -1;
                        worldPos2.x *= -1;
                        worldPos3.x *= -1;
                    }

                    Vector3 normal = (nor1 + nor2 + nor3) / 3;
                    sw.Write("\tfacet normal " + normal.x + " " + normal.y + " " + normal.z);
                    sw.Write("\n\t\touter loop\n");

                    sw.Write("\t\t\tvertex " + worldPos1.x + " " + worldPos1.y + " " + worldPos1.z + "\n");
                    if (exchangeCoordinate)
                    {
                        sw.Write("\t\t\tvertex " + worldPos3.x + " " + worldPos3.y + " " + worldPos3.z + "\n");
                        sw.Write("\t\t\tvertex " + worldPos2.x + " " + worldPos2.y + " " + worldPos2.z + "\n");
                    }
                    else
                    {
                        sw.Write("\t\t\tvertex " + worldPos2.x + " " + worldPos2.y + " " + worldPos2.z + "\n");
                        sw.Write("\t\t\tvertex " + worldPos3.x + " " + worldPos3.y + " " + worldPos3.z + "\n");
                    }
                    sw.Write("\t\tendloop\n");
                    sw.Write("\tendfacet\n");
                }
                if (mesh.subMeshCount == 1)
                {
                    sw.Write("endsolid " + mesh.name);
                }
                else
                {
                    sw.Write("endsolid " + mesh.name + "_" + j);
                }
            }
        }

        /// <summary>
        /// 将单个mesh数据使用StreamWrite写出为stl,二进制格式
        /// </summary>
        /// <param name="mesh">待导出的mesh</param>
        /// <param name="bw">BinaryWriter 写出二进制数据的类</param>
        /// <param name="trans">mesh对应的transform,用于将顶点法线转到世界空间</param>
        /// <param name="exchangeCoordinate">是否需要变换坐标手系,unity是左手坐标系,默认变换到右手坐标系</param>
        private static void ExportMeshToStl(Mesh mesh, BinaryWriter bw, Transform trans, bool exchangeCoordinate = true)
        {

            Vector3[] vertices = mesh.vertices;
            Vector3[] normals = mesh.normals;
            int[] tris = mesh.triangles;
            //每个三角面片固定占用50个字节
            for (int i = 0; i < tris.Length / 3; i++)
            {
                Vector3 nor1 = trans.TransformDirection(normals[tris[i * 3]]);
                Vector3 nor2 = trans.TransformDirection(normals[tris[i * 3 + 1]]);
                Vector3 nor3 = trans.TransformDirection(normals[tris[i * 3 + 2]]);

                Vector3 worldPos1 = trans.TransformPoint(vertices[tris[i * 3]]);
                Vector3 worldPos2 = trans.TransformPoint(vertices[tris[i * 3 + 1]]);
                Vector3 worldPos3 = trans.TransformPoint(vertices[tris[i * 3 + 2]]);

                if (exchangeCoordinate)
                {
                    nor1.x *= -1;
                    nor2.x *= -1;
                    nor3.x *= -1;
                    worldPos1.x *= -1;
                    worldPos2.x *= -1;
                    worldPos3.x *= -1;
                }

                Vector3 normal = (nor1 + nor2 + nor3) / 3;
                bw.Write(normal.x);
                bw.Write(normal.y);
                bw.Write(normal.z);
                bw.Write(worldPos1.x);
                bw.Write(worldPos1.y);
                bw.Write(worldPos1.z);
                if (exchangeCoordinate)
                {
                    bw.Write(worldPos3.x);
                    bw.Write(worldPos3.y);
                    bw.Write(worldPos3.z);
                    bw.Write(worldPos2.x);
                    bw.Write(worldPos2.y);
                    bw.Write(worldPos2.z);
                }
                else
                {
                    bw.Write(worldPos2.x);
                    bw.Write(worldPos2.y);
                    bw.Write(worldPos2.z);
                    bw.Write(worldPos3.x);
                    bw.Write(worldPos3.y);
                    bw.Write(worldPos3.z);
                }
                
                //填充两个字节  三角面片的最后2个字节用来描述三角面片的属性信息(包括颜色属性等)暂时没有用
                bw.Seek(2, SeekOrigin.Current);
            }
        }
    }
    #endregion
}

测试脚本

/****************************************************
    文件:ExportStlExample.cs
	作者:TKB
    邮箱: 544726237@qq.com
    日期:2021/7/26 22:19:56
	功能:编辑器环境测试将选中的物体导出stl   
*****************************************************/

using UnityEngine;

namespace TLib
{
    public class ExportStlExample
    {
#if UNITY_EDITOR
		//将当前选中的物体下所有mesh导出到一个stl中
        [UnityEditor.MenuItem("Tools/导出stl", false)]
        private static void OnClickExportObj()
        {
            GameObject go = UnityEditor.Selection.activeObject as GameObject;
            Exporter.ExportStl(go.transform, Application.dataPath +"/"+ go.name+".stl",true,false);
            UnityEditor.AssetDatabase.Refresh();
        }
        //将当前选中的物体下的mesh分别导出为stl
        [UnityEditor.MenuItem("Tools/导出stls", false)]
        private static void OnClickExportObj1()
        {
            GameObject go = UnityEditor.Selection.activeObject as GameObject;
            Exporter.ExportStls(go, Application.dataPath + "/Exports");
            UnityEditor.AssetDatabase.Refresh();
        }
#endif
    }
}

效果

unity中的模型截图:
unity中的模型
选择导出为stl 在meshlab中的截图:
stl外部
内部细节
选择导出为stls时导出了3000+的模型:
请添加图片描述

注意

这个测试模型导出二进制格式时使用meshlab打开报错,但是用CAD Assistant可以打开,原因还不清楚

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-10-21 12:43:55  更:2021-10-21 12:45:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 0:33:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码