2018-02-26 14:07:20 qq_15559109 阅读数 7820
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

在游戏开发中,经常会用到一些配置文件保存一些数据,然后项目运行中读取这些配置文件中的数据在游戏中使用。


如:配置血条:根据角色类型(人物、动物、怪物等)配置不同的血条,包括血条大小,血条名或血条预设,血条颜色等一些简单数据。


如:配置子弹:子弹类型(真子弹、假子弹、追踪子弹等),子弹速度,伤害数值,子弹关联的特效等。


诸如此类的配置很多种,可创建一个可序列化的类存储数据,或者创建 XML 、JSON 文件保存数据,创建 Excel 文件,创建 TXT 文件,皆可完成需求,灵活使用这些方法保存配置数据。


在此介绍一下使用可序列化类保存配置,并且将可序列化类保存成Unity的自定义文件(.asset),然后配置自定义文件(.asset)。


优点:
可以保存数据类型多样(int、string、Vector3、GameObject、Transform、Texture等)如关联预设,关联图片等资源数据,而XML、TXT等只能保存(int、string、Vector3 等基本数据类型)。


缺点:
如果配置数据中保存了(GameObject、Texture)等资源数据,当关联的资源被删除时,配置数据将丢失,需要重新将新的资源再次关联到配置数据上。


下面做个简单的子弹配置数据

方式一:

// 创建一个可序列化的子弹类

Bullet.CSusing UnityEngine;

using System.Collections;

using System;

// 子弹类型枚举

public enum BulletType

{ DirectAttack = 0, // 直接攻击  

Phony, // 假子弹  

Real, // 真子弹 

Track, // 追踪子弹}

/// <summary>/// 可序列化/// </summary>

[Serializable]

public class Bullet : ScriptableObject { // Bullet 类直接继承自 ScriptableObject  

// 子弹类型 public BulletType bulletType = BulletType.DirectAttack;

// 子弹速度
    public int speed = 10;


    // 伤害数值
    public int damage = 5;


    // 子弹关联的特效
    public GameObject effectObj;
}

1
2
using UnityEngine;
using System.Collections;
using UnityEditor;
using System.IO;


public class CreateAsset : Editor {


    // 在菜单栏创建功能项
    [MenuItem("CreateAsset/Asset")]
    static void Create()
    {
        // 实例化类  Bullet
        ScriptableObject bullet = ScriptableObject.CreateInstance<Bullet>();


        // 如果实例化 Bullet 类为空,返回
        if (!bullet)
        {
            Debug.LogWarning("Bullet not found");
            return;
        }
        // 自定义资源保存路径
        string path = Application.dataPath + "/BulletAeeet";
        // 如果项目总不包含该路径,创建一个
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }


        //将类名 Bullet 转换为字符串
        //拼接保存自定义资源(.asset) 路径
        path = string.Format("Assets/BulletAeeet/{0}.asset", (typeof(Bullet).ToString()));

        // 生成自定义资源到指定路径
        AssetDatabase.CreateAsset(bullet, path);
    }
}

如果想自定义 文件的 Inspector面板,使用编辑器类重写 Bullet.cs 的Inspector面板, 代码如下

using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(Bullet))]
public class BulletInspector : Editor {

    // 子弹类型
    public SerializedProperty bulletType;

    // 子弹速度
    public SerializedProperty speed;

    // 伤害数值
    public SerializedProperty damage;

    // 子弹关联的特效
    public SerializedProperty effectObj;

    private void OnEnable()
    {
        bulletType = serializedObject.FindProperty("bulletType");
        speed = serializedObject.FindProperty("speed");
        damage = serializedObject.FindProperty("damage");
        effectObj = serializedObject.FindProperty("effectObj");
    }

    public override void OnInspectorGUI()
    {
        serializedObject.Update();

        EditorGUI.indentLevel = 1;

        EditorGUILayout.PropertyField(bulletType, new GUIContent("子弹类型"));
        GUILayout.Space(5);

        EditorGUILayout.PropertyField(speed, new GUIContent("子弹速度"));

      GUILayout.Space(5);        EditorGUILayout.PropertyField(damage, new GUIContent("伤害数值"));

        GUILayout.Space(5);
        EditorGUILayout.PropertyField(effectObj, new GUIContent("特效对象"));
        GUILayout.Space(10);
        // 打印数据
        if (GUILayout.Button("Debug"))
        {
            Debug.Log("bulletType    :" + (BulletType)bulletType.enumValueIndex);
            Debug.Log("speed         :" + speed.intValue);
            Debug.Log("damage        :" + damage.intValue);


            if (effectObj.objectReferenceValue)
            {
                Debug.Log("effectObj    :" + effectObj.objectReferenceValue);
            }
        }


        if (GUI.changed)
        {
            EditorUtility.SetDirty(target);
        }

serializedObject.ApplyModifiedProperties();
    }

}

方式二:


读取asset文件



2019-10-12 19:58:37 YasinXin 阅读数 0
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

 

一、首先问题来了,为什么要把Excel转成Asset文件呢

1.Excel的不兼容性。首先PC上打包的程序就比编辑器模式下要多添加几个dll才能读取,移动端对Excel的支持就更差。

2.读取速度慢。这个我亲测过,一份Excel文件,一份该Excel转成的Asset文件。如下图,Excel第一次读取为88毫秒,后面基本维持在40毫秒左右,而Asset文件一直是0毫秒。

为了了解读取Asset文件到底有多快,我使用循环读取来看看,

读取10次和读100次都如下图第一次1毫秒,后面都是0毫秒

读取1000次

这么牛逼吗,10000次试试

一万次才7、8毫秒,又试了一下都一万次Excel,Unity直接卡死了!

后面又试了一下读空Excel,一次大概耗时15毫秒左右,着说名随内容增加,时间也会增加很多。

结论:用Asset文件吧!

二、读取Excel的方法

要先把Excel转成Asset文件,首先还是要读取Excel,介绍两种方式吧。

方法一

1.引入几个读取Excel需要的dll,如图

Excel.dll和ICSharpCode.SharpZipLib.dll的下载链接 https://download.csdn.net/download/yasinxin/11861899

System.Data.dll 在D:\Program Files\Unity2017.2\Editor\Data\Mono\lib\mono\2.0

如过要在PC打包版本读取还需要加加几个

I18N开头的dll 在 D:\Program Files\Unity2017.2\Editor\Data\Mono\lib\mono\unity

备注:Unity2017.2 为你的unity版本,去对应的安装目录中取dll

2.读取方法

 public static DataSet ReadExcel(string path)
    {
        FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.Read);
        IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
        DataSet result = excelReader.AsDataSet();
        return result;
    }

DataSet 为Unity中的一个Excel类,读完就存在里面,然后通过类的属性取想要的数据

Path 为Excel存放路径,如:string path = Application.dataPath + "/Resources/PreparationPatientItem.xlsx";

方法二

csv格式读取

这个方法直接写成编辑模式窗口打开的方式

    /// <summary>
    /// 文件转存数组内容
    /// </summary>
    static string[][] array = null;

    /// <summary>
    /// 打开csv文件
    /// </summary>
    [MenuItem("Tool/OpenCsv")]
    static void OpenFile(string functionName)
    {
        EditorUtility.DisplayDialog("选择文件夹", "请选择路径!", "OK");

        string CompentPath = string.Empty;

        //如果按下弹窗的OK按钮
        CompentPath = EditorUtility.OpenFilePanel("Overwrite with csv", "", "csv,xls,xlsx");

        if (CompentPath.Length != 0)
        {
            Debug.Log(CompentPath);

            if (!CompentPath.EndsWith(".csv") && !CompentPath.EndsWith(".CSV") && !CompentPath.EndsWith(".xls") && !CompentPath.EndsWith(".xlsx"))
            {
                Debug.LogWarning("请选择Excel文件");
                return;
            }

            string str = File.ReadAllText(CompentPath);

            //读取每一行的内容  
            string[] lineArray = str.Split("\r"[0]);
            Debug.Log(lineArray[5]);
            //创建二维数组  
            array = new string[lineArray.Length][];

            //把csv中的数据储存在二位数组中  
            for (int i = 0; i < lineArray.Length; i++)
            {
                array[i] = lineArray[i].Split(',');
            }

            PreparationPatientItemFunction();
        }
    }

这样就把数据存放到了二维数组array里面了。

备注: 方法二只能读取csv格式,因为只有csv格式有UTF-8的编码方式,如图:

试了其他格式打开会成乱码。不过读csv格式比xlsx要快一些,但和读Asset比还不是一个级别的。

但读csv可以不用导入dll就能读取。

三、把数据转成Asset文件

如下图是我数据样式

 

 

 根据样式创建相应的数据类

public class PreparationPatientItemDatas : ScriptableObject
{
    public List<PreparationPatientItemData> PreparationPatientItemDataList = new List<PreparationPatientItemData>();
}

[System.Serializable]
public class PreparationPatientItemData
{
    public string id;
    public string itemKey;
    public string itemContent;
    public GMMedicalProjectType internalMedicineType = GMMedicalProjectType.None;
    public string questionKey;
    public string questionContents;
    public string answerKey;
    public string answerContents;
}

/// <summary>
/// 医学项目类型 +400
/// </summary>
public enum GMMedicalProjectType
{
    None,
    Chest,
    Abdoment,
    Marrow,
    Lumber,
    Pericardium,
    Thyrocricoid,
    MarrowChild,
    LumberChild,
    KneeJoint,
    MarrowTibiaChild,
    Culdocentesis,
    KneeJointChild,
    MaleCatheterization,
    FemaleCatheterization,
    AbdomentChild,
    ChestChild,
    GastricLavage,
    NasogastricGavage
}

 

 

 然后把从Excel读到的数据填到类中,再生成Asset文件,这里以第二种读取为例

    static void PreparationPatientItemFunction()
    {
        if (array == null || array.Length < 1)
        {
            Debug.LogWarning("未读csv!!!");
            return;
        }

        string assetName = GetDataByRowAndCol(0, 0);
        Debug.Log(assetName);
        PreparationPatientItemDatas preparationPatientItemDatas = new PreparationPatientItemDatas();

        for (int i = 3; i < array.Length - 1; i++)
        {
            PreparationPatientItemData preparationPatientItemData = new PreparationPatientItemData();
            preparationPatientItemData.id = array[i][0].Replace("\n", "");
            Debug.Log(i);
            preparationPatientItemData.itemKey = array[i][1];
            preparationPatientItemData.itemContent = array[i][2];
            preparationPatientItemData.internalMedicineType = (GMMedicalProjectType)(int.Parse(array[i][3]) - 400);
            preparationPatientItemData.questionKey = array[i][4];
            preparationPatientItemData.questionContents = array[i][5];
            preparationPatientItemData.answerKey = array[i][6];
            preparationPatientItemData.answerContents = array[i][7];

            preparationPatientItemDatas.PreparationPatientItemDataList.Add(preparationPatientItemData);
        }

        AssetDatabase.CreateAsset(preparationPatientItemDatas, "Assets/Resources/" + assetName + ".asset");

        Debug.Log("Save it");
    }

    static string GetDataByRowAndCol(int nRow, int nCol)
    {
        if (array.Length <= 0 || nRow >= array.Length)
            return "";
        if (nCol >= array[0].Length)
            return "";

        return array[nRow][nCol];
    }

 最后生成的Asset如下

 

2017-03-08 18:34:00 cartzhang 阅读数 17092
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/60878354
作者:cartzhang

一、前言


美术想要一个把unity中*.asset的模型导出来,导成3D Max可以打开的模式,fbx或obj.

需要导出的格式:

这里写图片描述
图1

也就是需要一个工具,个人觉得这个问题,肯定之前Unity的前辈就有解决方法了。于是乎网上一通下载和测试。

二、解包工具集合


网络上找来了各种测试,但是没有一个适合我的,很多都是失败,打不开。
参考宣雨松的博客,找了还是没有结果。

这里写图片描述
图3

解包工具有很多种类,
disunity github地址: https://github.com/ata4/disunity

还有就是AssetAssetsExport,还有Unity Studio.
别人的博客里面都有比较多的介绍和说明,这里就详细说了。

最后还网上wiki里,找到了一个合适的我自己的解包。
http://wiki.unity3d.com/index.php?title=ObjExporter

三、初步成果


找到了一个网站:http://wiki.unity3d.com/index.php?title=ObjExporter

可以导出部分对象。
如下图:

这里写图片描述
图0

而原来unity中模型是这个样子的。

这里写图片描述
图4

导出的只有武器和头盔,没有人物主体body.

四、bug修改

其实也不能算bug,也许人家没有这样的需要呢。

 Component[] meshfilter = selection[i].GetComponentsInChildren<MeshFilter>();
            MeshFilter[] mf = new MeshFilter[meshfilter.Length];
            int m = 0;
            for (; m < meshfilter.Length; m++)
            {
                exportedObjects++;
                mf[m] = (MeshFilter)meshfilter[m];
            }


代码中是要查找所有组件中的MeshFilter,发现SkinnedMeshRender组件居然没有这个MeshFilter这个组件,所以总会导出少一个,而这个居然是人的主体。

这里写图片描述
图5

本来说让美术自己添加一个MeshFilter组件,然后根据mesh render中的mesh自己来添加一个对应的mesh.

既然是程序,那就想办法,思路很明显,既然是有meshrender,就从这入手呗。

代码还是不难度。

// 没有meshFilter,添加一个meshFilter.
            SkinnedMeshRenderer[] meshfilterRender = selection[i].GetComponentsInChildren<SkinnedMeshRenderer>();
            for (int j = 0; j < meshfilterRender.Length; j++)
            {   
                if (meshfilterRender[j].GetComponent<MeshFilter>() == null)
                {
                    meshfilterRender[j].gameObject.AddComponent<MeshFilter>();
                    meshfilterRender[j].GetComponent<MeshFilter>().sharedMesh = Instantiate(meshfilterRender[j].sharedMesh);
                }
            }


这样修改过,就会自动在没有MeshFilter,但是有skinnedMeshRender组件的节点下,添加一个MeshFilter,然后就可以正常导出成.obj文件,与.FBX是类似的,都可以被3D max编辑使用。

这里写图片描述
图7

最后的在VS中看的模型,因为没有安装3Dmax.

这里写图片描述
图6

虽然看起来简陋,但是满足他们小需要,就好了。

贴出主要的代码:

/*
Based on ObjExporter.cs, this "wrapper" lets you export to .OBJ directly from the editor menu.

This should be put in your "Editor"-folder. Use by selecting the objects you want to export, and select
the appropriate menu item from "Custom->Export". Exported models are put in a folder called
"ExportedObj" in the root of your Unity-project. Textures should also be copied and placed in the
same folder.
N.B. there may be a bug so if the custom option doesn't come up refer to this thread http://answers.unity3d.com/questions/317951/how-to-use-editorobjexporter-obj-saving-script-fro.html 

Updated for Unity 5.3

2017-03-07
@cartzhang
fixed can not create obj file in folder.
*/

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

struct ObjMaterial
{
    public string name;
    public string textureName;
}

public class EditorObjExporter : ScriptableObject
{
    private static int vertexOffset = 0;
    private static int normalOffset = 0;
    private static int uvOffset = 0;


    //User should probably be able to change this. It is currently left as an excercise for
    //the reader.
    private static string targetFolder = "ExportedObj";


    private static string MeshToString(MeshFilter mf, Dictionary<string, ObjMaterial> materialList)
    {
        Debug.Assert(null != mf);
        Mesh m = mf.sharedMesh;
        Material[] mats = mf.GetComponent<Renderer>().sharedMaterials;

        StringBuilder sb = new StringBuilder();
        if (null == m)
            return sb.ToString();

        sb.Append("g ").Append(mf.name).Append("\n");
        foreach (Vector3 lv in m.vertices)
        {
            Vector3 wv = mf.transform.TransformPoint(lv);

            //This is sort of ugly - inverting x-component since we're in
            //a different coordinate system than "everyone" is "used to".
            sb.Append(string.Format("v {0} {1} {2}\n", -wv.x, wv.y, wv.z));
        }
        sb.Append("\n");

        foreach (Vector3 lv in m.normals)
        {
            Vector3 wv = mf.transform.TransformDirection(lv);

            sb.Append(string.Format("vn {0} {1} {2}\n", -wv.x, wv.y, wv.z));
        }
        sb.Append("\n");

        foreach (Vector3 v in m.uv)
        {
            sb.Append(string.Format("vt {0} {1}\n", v.x, v.y));
        }

        for (int material = 0; material < m.subMeshCount; material++)
        {
            sb.Append("\n");
            sb.Append("usemtl ").Append(mats[material].name).Append("\n");
            sb.Append("usemap ").Append(mats[material].name).Append("\n");

            //See if this material is already in the materiallist.
            try
            {
                ObjMaterial objMaterial = new ObjMaterial();

                objMaterial.name = mats[material].name;

                if (mats[material].mainTexture)
                    objMaterial.textureName = AssetDatabase.GetAssetPath(mats[material].mainTexture);
                else
                    objMaterial.textureName = null;

                materialList.Add(objMaterial.name, objMaterial);
            }
            catch (ArgumentException)
            {
                //Already in the dictionary
            }


            int[] triangles = m.GetTriangles(material);
            for (int i = 0; i < triangles.Length; i += 3)
            {
                //Because we inverted the x-component, we also needed to alter the triangle winding.
                sb.Append(string.Format("f {1}/{1}/{1} {0}/{0}/{0} {2}/{2}/{2}\n",
                    triangles[i] + 1 + vertexOffset, triangles[i + 1] + 1 + normalOffset, triangles[i + 2] + 1 + uvOffset));
            }
        }

        vertexOffset += m.vertices.Length;
        normalOffset += m.normals.Length;
        uvOffset += m.uv.Length;

        return sb.ToString();
    }

    private static void Clear()
    {
        vertexOffset = 0;
        normalOffset = 0;
        uvOffset = 0;
    }

    private static Dictionary<string, ObjMaterial> PrepareFileWrite()
    {
        Clear();

        return new Dictionary<string, ObjMaterial>();
    }

    private static void MaterialsToFile(Dictionary<string, ObjMaterial> materialList, string folder, string filename)
    {
        using (StreamWriter sw = new StreamWriter(folder + Path.DirectorySeparatorChar + filename + ".mtl"))
        {
            foreach (KeyValuePair<string, ObjMaterial> kvp in materialList)
            {
                sw.Write("\n");
                sw.Write("newmtl {0}\n", kvp.Key);
                sw.Write("Ka  0.6 0.6 0.6\n");
                sw.Write("Kd  0.6 0.6 0.6\n");
                sw.Write("Ks  0.9 0.9 0.9\n");
                sw.Write("d  1.0\n");
                sw.Write("Ns  0.0\n");
                sw.Write("illum 2\n");

                if (kvp.Value.textureName != null)
                {
                    string destinationFile = kvp.Value.textureName;


                    int stripIndex = destinationFile.LastIndexOf(Path.DirectorySeparatorChar);

                    if (stripIndex >= 0)
                        destinationFile = destinationFile.Substring(stripIndex + 1).Trim();


                    string relativeFile = destinationFile;

                    destinationFile = folder + Path.DirectorySeparatorChar + destinationFile;

                    Debug.Log("Copying texture from " + kvp.Value.textureName + " to " + destinationFile);

                    try
                    {
                        //Copy the source file
                        File.Copy(kvp.Value.textureName, destinationFile);
                    }
                    catch
                    {

                    }


                    sw.Write("map_Kd {0}", relativeFile);
                }

                sw.Write("\n\n\n");
            }
        }
    }

    private static void MeshToFile(MeshFilter mf, string folder, string filename)
    {
        Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();

        using (StreamWriter sw = new StreamWriter(folder + Path.DirectorySeparatorChar + filename + ".obj"))
        {
            sw.Write("mtllib ./" + filename + ".mtl\n");

            sw.Write(MeshToString(mf, materialList));
        }

        MaterialsToFile(materialList, folder, filename);
    }

    private static void MeshesToFile(MeshFilter[] mf, string folder, string filename)
    {
        Dictionary<string, ObjMaterial> materialList = PrepareFileWrite();

        using (StreamWriter sw = new StreamWriter(folder + Path.DirectorySeparatorChar + filename + ".obj"))
        {
            sw.Write("mtllib ./" + filename + ".mtl\n");

            for (int i = 0; i < mf.Length; i++)
            {
                sw.Write(MeshToString(mf[i], materialList));
            }
        }

        MaterialsToFile(materialList, folder, filename);
    }

    private static bool CreateTargetFolder()
    {
        try
        {
            System.IO.Directory.CreateDirectory(targetFolder);
        }
        catch
        {
            EditorUtility.DisplayDialog("Error!", "Failed to create target folder!", "");
            return false;
        }

        return true;
    }

    [MenuItem("Custom/Export/Export whole selection to single OBJ")]
    static void ExportWholeSelectionToSingle()
    {
        if (!CreateTargetFolder())
            return;


        Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);

        if (selection.Length == 0)
        {
            EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
            return;
        }

        int exportedObjects = 0;

        ArrayList mfList = new ArrayList();

        for (int i = 0; i < selection.Length; i++)
        {
            Component[] meshfilter = selection[i].GetComponentsInChildren(typeof(MeshFilter));

            for (int m = 0; m < meshfilter.Length; m++)
            {
                exportedObjects++;
                mfList.Add(meshfilter[m]);
            }
        }

        if (exportedObjects > 0)
        {
            MeshFilter[] mf = new MeshFilter[mfList.Count];

            for (int i = 0; i < mfList.Count; i++)
            {
                mf[i] = (MeshFilter)mfList[i];
            }

            string filename = EditorSceneManager.GetActiveScene().name + "_" + exportedObjects;

            int stripIndex = filename.LastIndexOf(Path.DirectorySeparatorChar);

            if (stripIndex >= 0)
                filename = filename.Substring(stripIndex + 1).Trim();

            MeshesToFile(mf, targetFolder, filename);


            EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects to " + filename, "");
        }
        else
            EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
    }



    [MenuItem("Custom/Export/Export each selected to single OBJ")]
    static void ExportEachSelectionToSingle()
    {
        if (!CreateTargetFolder())
            return;

        Transform[] selection = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);

        if (selection.Length == 0)
        {
            EditorUtility.DisplayDialog("No source object selected!", "Please select one or more target objects", "");
            return;
        }

        int exportedObjects = 0;


        for (int i = 0; i < selection.Length; i++)
        {
            // 没有meshFilter,添加一个meshFilter.
            SkinnedMeshRenderer[] meshfilterRender = selection[i].GetComponentsInChildren<SkinnedMeshRenderer>();
            for (int j = 0; j < meshfilterRender.Length; j++)
            {   
                if (meshfilterRender[j].GetComponent<MeshFilter>() == null)
                {
                    meshfilterRender[j].gameObject.AddComponent<MeshFilter>();
                    meshfilterRender[j].GetComponent<MeshFilter>().sharedMesh = Instantiate(meshfilterRender[j].sharedMesh);
                }
            }

            Component[] meshfilter = selection[i].GetComponentsInChildren<MeshFilter>();
            MeshFilter[] mf = new MeshFilter[meshfilter.Length];
            int m = 0;
            for (; m < meshfilter.Length; m++)
            {
                exportedObjects++;
                mf[m] = (MeshFilter)meshfilter[m];
            }

            MeshesToFile(mf, targetFolder, selection[i].name + "_" + i);
        }

        if (exportedObjects > 0)
        {
            EditorUtility.DisplayDialog("Objects exported", "Exported " + exportedObjects + " objects", "");
        }
        else
            EditorUtility.DisplayDialog("Objects not exported", "Make sure at least some of your selected objects have mesh filters!", "");
    }

}


可以直接复制到直接的项目中使用。

五、怎么使用呢?


首先把代码拷贝到项目中,直接下载工程也行。

步骤一

这里写图片描述
图8

步骤二

这里写图片描述
图10

步骤三

这里写图片描述
图11

就可以使用你的模型编辑工具来查看了。

五、源码和示例工程


源码地址:

https://github.com/cartzhang/unity_lab/blob/master/ExportFbx/UnityAssetExportFBX/Assets/Editor/OBJExport/EditorObjExporter.cs

示例工程地址:
https://github.com/cartzhang/unity_lab/tree/master/ExportFbx/UnityAssetExportFBX

博客图片地址:
https://github.com/cartzhang/unity_lab/tree/master/ExportFbx/Img

Github readme:
https://github.com/cartzhang/unity_lab/blob/master/ExportFbx/Unity%20asset%E6%96%87%E4%BB%B6%20%E5%AF%BC%E5%87%BAOBJ.md

六、参考

【1】http://www.xuanyusong.com/archives/3618

【2】https://forums.inxile-entertainment.com/viewtopic.php?t=13724

【3】http://www.cnblogs.com/Niger123/p/4261763.html

【4】http://prog3.com/sbdm/download/download/akof1314/9097153

【5】http://wiki.unity3d.com/index.php?title=ObjExporter

【6】https://github.com/KellanHiggins/UnityFBXExporter/tree/master/Assets/Packages/UnityFBXExporter

七,最后但不是不重要


Asset导出成FBX的格式:https://github.com/cartzhang/UnityFBXExporter

与上面介绍的不是一个方法,但是思路都一样。这个源码可以把纹理和材质都匹配上去,当然我也做了稍微的修改,修复了之前的小bug。

非常感谢,欢迎留言!!

2018-09-29 12:29:25 aa20274270 阅读数 1007
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

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

public class Node : ScriptableObject {

    public string Name;
}

 

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


public class FlowNode : Node {

    public string Type;
}

 

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

public class GraphSerializationData : ScriptableObject {

    public List<Node> list = new List<Node>();
}

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class TestSerializationTool {
    [MenuItem("Assets/TestSerialization")]
    static void TestSerialization() {
        Debug.Log("TestSerialization");

        GraphSerializationData data = ScriptableObject.CreateInstance<GraphSerializationData>();

        string filePath = "Assets/testAsset.asset";
        AssetDatabase.DeleteAsset(filePath);
        AssetDatabase.CreateAsset(data, filePath);
        AssetDatabase.Refresh();


        FlowNode fn = ScriptableObject.CreateInstance<FlowNode>();
        fn.Name = "lzz";
        fn.Type = "123";

        data.list.Add(fn);

        AssetDatabase.AddObjectToAsset(fn, data);

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();


    }
}

上面的例子 演示 有继承关系的类都可以存储到.asset中。

可以尝试使用 : [PreferBinarySerialization]

参考:https://answers.unity.com/questions/842058/serializing-a-collection-of-scriptableobjects-to-a.html

2018-05-06 22:19:40 qq_16763249 阅读数 6449
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

简介

在游戏开发中,我们经常要对一些数据预先配置,比如不同角色的属性,武器的各项数值等等,一般可通过XML配置. 此外还可以用Unity自带的.Asset资源配置文件配置数据,下面介绍一下如何灵活快速的创建.Asset文件并使用.

转载请注明出处

相比XML配置文件, Asset文件更加直观而且支持直接配置如 GameObject、Sprite、AudioClip等更加高级的对象,基本上除了接口、事件 都可以通过Asset文件配置 , 所以说灵活性上比XML要更强一点.

插件演示

  • 首先创建一个继承于ScriptableObject 类的对象
[System.Serializable]
public class DemoConfig : ScriptableObject {

    public string userName;

    public int userID;

    public GameObject userObject;

    public Sprite sprite;

    public AudioClip audioClip;

    public void print() {
        Debug.Log(string.Format("name: {0} id: {1}" , userName , userID));
    }
}
  • 使用UConfig创建对应的Asset文件

创建Asset配置文件

创建成功

  • 配置各项属性
    这里写图片描述

创建Asset文件

创建Asset文件的核心代码只有一句, 那就是通过ScriptableObject.CreateInstance()方法, 这个方法允许传入一个类名并创建对应的资源配置文件,以下代码如下.

static void CreateAsset()
        {
            //class_Name表示类名 , config_Name表示要创建的配置文件名称 , file_floder表示创建路径
            if (class_Name.Length == 0 || config_Name.Length == 0 || file_floder.Length == 0)
            {
                Debug.LogError(string.Format("[UConfig]: 创建失败 , 信息不完整!"));
                return;
            }
            ScriptableObject config = ScriptableObject.CreateInstance(class_Name);

            if (config == null)
            {
                Debug.LogError(string.Format("[UConfig]: 创建失败 , 类名无法识别! --> {0}", class_Name));
                return;
            }
            // 自定义资源保存路径
            string path = file_floder;
            //如果项目总不包含该路径,创建一个
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            config_Name = config_Name.Replace(".asset", "");
            path = string.Format("{0}/{1}.asset", file_floder, config_Name);
            string defFilePath = "Assets/" + config_Name + ".asset";
            // 生成自定义资源到指定路径
            AssetDatabase.CreateAsset(config, defFilePath);
            File.Move(Application.dataPath + string.Format("/{0}.asset" , config_Name), path);
            AssetDatabase.Refresh();
            Debug.Log(string.Format("<color=yellow>[UConfig]: 创建成功 ! --> {0}</color>", path));
            configWindow.Close();
        }

读取配置好的Asset文件

通过以上方式创建的配置文件可以作为一个与Prefab资源对待, 并且可以随其他prefab资源一样被打成AssetBundle包动态加载 , 理所当然的可以实现所谓的热更配置表.

加载的代码就用 Resources.Load(“fileName”); 就可以了,也可以预先挂着到某一个代码的属性中,然后直接通过as强转.

其他

有需要的伙伴可以访问我的码云下载源码,有更详细的代码,供大家参考


点击以下图标前往源码 :

Fork me on Gitee

(顺便Stars一下吧 ^_^)