想要从 Unity 中导出 SketchUp 支持的 3D 模型

问题描述 投票:0回答:1

我正在开发一个橱柜设计中心,我正在寻找一种方法来导出我在 Unity 中设计的 3D 模型。需要导出的所有网格体和材质都位于一个父级中(参见图片)。具体来说,我想导出与 SketchUp 兼容的 3d 文件(不支持 .fbx)。你知道如何做到这一点吗?

我尝试导出 .obj 文件,但我在导出的文件中只得到几何图形,而不是彩色材质,这是该方法的脚本。

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

public class OBJExporter : MonoBehaviour
{
    public bool onlySelectedObjects = false;
    public bool applyPosition = true;
    public bool applyRotation = true;
    public bool applyScale = true;
    public bool generateMaterials = true;
    public bool exportTextures = true;
    public bool splitObjects = true;
    public bool autoMarkTexReadable = false;
    public bool objNameAddIdNum = false;
    string exportPath = "";
    private string lastExportFolder;
    private string versionString = "v2.0";
    public Transform targetObject;


    string MaterialToString(Material m)
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("newmtl " + m.name);

        // Add properties for URP Lit material
        // Base color
        if (m.HasProperty("_BaseColor"))
        {
            Color baseColor = m.GetColor("_BaseColor");
            //Debug.Log(ColorToHex(baseColor));
            sb.AppendLine("Kd " + baseColor.r.ToString() + " " + baseColor.g.ToString() + " " + baseColor.b.ToString());
            if (baseColor.a < 1.0f)
            {
                sb.AppendLine("Tr " + (1f - baseColor.a).ToString());
                sb.AppendLine("d " + baseColor.a.ToString());
            }
        }

        sb.AppendLine("illum 2");
        return sb.ToString();
    }   

    string TryExportTexture(string propertyName, Material m)
    {
        if (m.HasProperty(propertyName))
        {
            Texture t = m.GetTexture(propertyName);
        }

        return "false";
    }

    Vector3 MultiplyVec3s(Vector3 v1, Vector3 v2)
    {
        return new Vector3(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z);
    }

    Vector3 RotateAroundPoint(Vector3 point, Vector3 pivot, Quaternion angle)
    {
        return angle * (point - pivot) + pivot;
    }

    private string ConstructOBJString(int index)
    {
        string idxString = index.ToString();
        return idxString + "/" + idxString + "/" + idxString;
    }

    void Export()
    {
        exportPath = Application.dataPath + "/testobj.obj";
        //init stuff
        Dictionary<string, bool> materialCache = new Dictionary<string, bool>();
        var exportFileInfo = new System.IO.FileInfo(exportPath);
        lastExportFolder = exportFileInfo.Directory.FullName;
        string baseFileName = System.IO.Path.GetFileNameWithoutExtension(exportPath);
        //get list of required export things
        MeshFilter[] sceneMeshes;
        if (onlySelectedObjects)
        {
            List<MeshFilter> tempMFList = GetAllMeshFiltersInHierarchy(targetObject);
            sceneMeshes = tempMFList.ToArray();
        }
        else
        {
            sceneMeshes = FindObjectsOfType(typeof(MeshFilter)) as MeshFilter[];
        }

        if (Application.isPlaying)
        {
            foreach (MeshFilter mf in sceneMeshes)
            {
                MeshRenderer mr = mf.gameObject.GetComponent<MeshRenderer>();
            }
        }

        //work on export
        StringBuilder sb = new StringBuilder();
        StringBuilder sbMaterials = new StringBuilder();
        sb.AppendLine("# Export of " + Application.loadedLevelName);
        sb.AppendLine("# from Aaro4130 OBJ Exporter " + versionString);
        if (generateMaterials)
        {
            sb.AppendLine("mtllib " + baseFileName + ".mtl");
        }

        float maxExportProgress = (float)(sceneMeshes.Length + 1);
        int lastIndex = 0;
        for (int i = 0; i < sceneMeshes.Length; i++)
        {
            string meshName = sceneMeshes[i].gameObject.name;
            float progress = (float)(i + 1) / maxExportProgress;
            MeshFilter mf = sceneMeshes[i];
            MeshRenderer mr = sceneMeshes[i].gameObject.GetComponent<MeshRenderer>();
            if (splitObjects)
            {
                string exportName = meshName;
                if (objNameAddIdNum)
                {
                    exportName += "_" + i;
                }

                sb.AppendLine("g " + exportName);
            }

            if (mr != null && generateMaterials)
            {
                Material[] mats = mr.sharedMaterials;
                for (int j = 0; j < mats.Length; j++)
                {
                    Material m = mats[j];
                    if (!materialCache.ContainsKey(m.name))
                    {
                        materialCache[m.name] = true;
                        sbMaterials.Append(MaterialToString(m));
                        sbMaterials.AppendLine();
                    }
                }
            }

            //export the meshhh :3
            Mesh msh = mf.sharedMesh;
            int faceOrder = (int)Mathf.Clamp((mf.gameObject.transform.lossyScale.x * mf.gameObject.transform.lossyScale.z), -1, 1);
            //export vector data (FUN :D)!
            foreach (Vector3 vx in msh.vertices)
            {
                Vector3 v = vx;
                if (applyScale)
                {
                    v = MultiplyVec3s(v, mf.gameObject.transform.lossyScale);
                }

                if (applyRotation)
                {
                    v = RotateAroundPoint(v, Vector3.zero, mf.gameObject.transform.rotation);
                }

                if (applyPosition)
                {
                    v += mf.gameObject.transform.position;
                }

                v.x *= -1;
                sb.AppendLine("v " + v.x + " " + v.y + " " + v.z);
            }

            foreach (Vector3 vx in msh.normals)
            {
                Vector3 v = vx;
                if (applyScale)
                {
                    v = MultiplyVec3s(v, mf.gameObject.transform.lossyScale.normalized);
                }

                if (applyRotation)
                {
                    v = RotateAroundPoint(v, Vector3.zero, mf.gameObject.transform.rotation);
                }

                v.x *= -1;
                sb.AppendLine("vn " + v.x + " " + v.y + " " + v.z);
            }

            foreach (Vector2 v in msh.uv)
            {
                sb.AppendLine("vt " + v.x + " " + v.y);
            }

            for (int j = 0; j < msh.subMeshCount; j++)
            {
                if (mr != null && j < mr.sharedMaterials.Length)
                {
                    string matName = mr.sharedMaterials[j].name;
                    sb.AppendLine("usemtl " + matName);
                }
                else
                {
                    sb.AppendLine("usemtl " + meshName + "_sm" + j);
                }

                int[] tris = msh.GetTriangles(j);
                for (int t = 0; t < tris.Length; t += 3)
                {
                    int idx2 = tris[t] + 1 + lastIndex;
                    int idx1 = tris[t + 1] + 1 + lastIndex;
                    int idx0 = tris[t + 2] + 1 + lastIndex;
                    if (faceOrder < 0)
                    {
                        sb.AppendLine("f " + ConstructOBJString(idx2) + " " + ConstructOBJString(idx1) + " " + ConstructOBJString(idx0));
                    }
                    else
                    {
                        sb.AppendLine("f " + ConstructOBJString(idx0) + " " + ConstructOBJString(idx1) + " " + ConstructOBJString(idx2));
                    }
                }
            }

            lastIndex += msh.vertices.Length;
        }

        //write to disk
        System.IO.File.WriteAllText(exportPath, sb.ToString());
        if (generateMaterials)
        {
            System.IO.File.WriteAllText(exportFileInfo.Directory.FullName + "\\" + baseFileName + ".mtl", sbMaterials.ToString());
        }
    }


    public List<MeshFilter> GetAllMeshFiltersInHierarchy(Transform parent)
    {
        List<MeshFilter> meshFilters = new List<MeshFilter>();
        FindMeshFilters(parent, meshFilters);
        return meshFilters;
    }

    private void FindMeshFilters(Transform parent, List<MeshFilter> meshFilters)
    {
        MeshFilter meshFilter = parent.GetComponent<MeshFilter>();
        if (meshFilter != null && meshFilter.gameObject.activeSelf)
        {
            meshFilters.Add(meshFilter);
        }

        foreach (Transform child in parent)
        {
            FindMeshFilters(child, meshFilters);
        }
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            Export();
        }
    }

    string ColorToHex(Color color)
    {
        Color32 color32 = color;
        return string.Format("#{0:X2}{1:X2}{2:X2}", color32.r, color32.g, color32.b);
    }
}
c# unity-game-engine
1个回答
0
投票

这不是一个单一的问题 为此,您必须实现 3D 转换器,因为您要将统一材质等内容与 obj 网格和纹理混合在一起。 您应该根据要导出的文件格式及其限制来创建材料和每个元素:

文件结构

顶点数据

o 几何顶点 (v) o 纹理顶点 (vt) o 顶点法线 (vn) o 参数空间顶点 (vp) 自由曲线/曲面属性 o 曲线或曲面类型的有理或非有理形式: 基础矩阵、Bezier、B 样条、Cardinal、Taylor(cstype) o 度 (deg) o 基础矩阵 (bmat) o 步长(步长)

元素

o 点 (p) o 线 (l) o 面 (f) o 曲线(曲线) o 2D 曲线 (curv2) o 表面(冲浪)

自由曲线/曲面体声明

o 参数值 (parm) o 外部修剪环(修剪) o 内修边环(孔) o 特殊曲线(scrv) o 特殊点 (sp) o 结束语句(结束)

自由曲面之间的连接

o 连接(con)

分组

o 组名 (g) o 平滑组 o 合并基团(mg) o 对象名称 (o)

显示/渲染属性

o 斜角插补(bevel) o 颜色插值 (c_interp) o 溶解插值 (d_interp) o 细节层次 (lod) o 材料名称 (usemtl) o 材料库(mtllib) o 阴影投射 (shadow_obj) o 光线追踪 (trace_obj) o 曲线近似技术(ctech) o 表面近似技术(stech)

© www.soinside.com 2019 - 2024. All rights reserved.