AssetDatabase.LoadAssetAtPath 获取FBX资源空指针问题

问题一  LoadAssetAtPath 返回空

public class ProcessModel : AssetPostprocessor
{
    
    private void OnPostprocessModel(GameObject input)
    {
        if (input.name != "Enemy2b") return;

        //取得导入模型相关信息
        ModelImporter importer = assetImporter as ModelImporter;

        //将该模型从工程中读取出来
        string path = "Assets/airplane/Enemy2b.FBX";
        path = importer.assetPath;

        GameObject tar = AssetDatabase.LoadAssetAtPath<GameObject>(path);

        Debug.Log(importer.assetPath);
        Debug.Log(tar);
    }
}

  如上所示的代码,这是从一本书《Unity 3D/2D手机游戏开发 从学习到产品》中看到的一段代码。

  书中最后写到在工程窗口中选择Enemy2b,然后右键选择Reimport重新导入Enemy2b.FBX,上述代码会运行。

  但是经过试验后,发现上述代码 tar 是一个空对象,也就是说 AssetDatabase.LoadAssetAtPath方法返回的是空,也就是说这个path是找不到FBX资源,所以自然返回空对象。

  我在Project窗口中,将Enemy2b.FBX删除,没有触发OnPostprocessModel方法,然后Import New Assets后触发了OnPostprocessModel方法,依旧tar是空。

 

  我将上述代码注释掉if后,然后在Enemy.FBX上Reimport,结果tar不为空,那么也就是说,LoadAssetAtPath只能获取已经加载了的FBX资源,Reimport应该是删除再导入的操作咯?

public class ProcessModel : AssetPostprocessor
{
    
    private void OnPostprocessModel(GameObject input)
    {
        // if (input.name != "Enemy2b") return;

        //取得导入模型相关信息
        ModelImporter importer = assetImporter as ModelImporter;

        //将该模型从工程中读取出来
        string path = "Assets/airplane/Enemy2b.FBX";
        // path = importer.assetPath;

        GameObject tar = AssetDatabase.LoadAssetAtPath<GameObject>(path);

        Debug.Log(importer.assetPath);
        Debug.Log(tar);
    }
}

 

 然后我去unity手册里面查了下,如下网址

https://docs.unity.cn/cn/2020.2/ScriptReference/AssetPostprocessor.OnPostprocessModel.html

 我对标红的地方理解就是,这个OnPostprocessModel是用于模型导入后调用的,模型的话也就是FBX文件。

 关于创建prefab这段我觉得还是看英文好一点,从英文来看,当模型导入后,所有对游戏对象和网格的引用将失效,因此当fbx模型有mesh信息时,无法使用OnPostprocessModel方法从导入的fbx文件去创建一个预制体。

 而如下图这个模型,拥有col,enemy2两个mesh信息,大概是不能创建预制体。

  但是这里有个疑问,为啥我在Enemy2b导入完成后,Reimport  Enemy.FBX可以获取到Enemy2b.FBX的信息呢,不应该无法获取信息么?

  

问题二 创建预制体失败

  在第二步中,根据资源创建预制体,当返回unity界面,Reimport  Enemy.FBX来创建Enemy2b.FBX的预制体时,会发现预制体文件创建了, 但代码中prefab是空对象。

//将这个模型创建为Prefab
//GameObject prefab = PrefabUtility.SaveAsPrefabAsset(tar, "Assets/Prefabs/Enemey2b_0.prefab");
GameObject prefab = PrefabUtility.CreatePrefab("Assets/Prefabs/Enemey2b_0.prefab",tar);

prefab.tag = "Enemy";

  当我有了Enemey2b_0.prefab文件时,再Reimport Enemy.FBX时会运行成功,没有任何报错。

  也就是说此时prefab不是空对象了。

  那么上述操作其实是异步操作?

 

一段代码两个问题点没搞明白,我也是服了我自己了。

  

完整代码

using UnityEngine;
using UnityEditor;

public class ProcessModel : AssetPostprocessor
{
    
    private void OnPostprocessModel(GameObject input)
    {
        //if (input.name != "Enemy2b") return;

        //取得导入模型相关信息
        ModelImporter importer = assetImporter as ModelImporter;

        //将该模型从工程中读取出来
        string path = "Assets/airplane/Enemy2b.FBX";
        //path = importer.assetPath;

        GameObject tar = AssetDatabase.LoadAssetAtPath<GameObject>(path);

        //Debug.Log(importer.assetPath);
        Debug.Log(tar);
        //return;

        //将这个模型创建为Prefab
        //GameObject prefab = PrefabUtility.SaveAsPrefabAsset(tar, "Assets/Prefabs/Enemey2b_0.prefab");
        GameObject prefab = PrefabUtility.CreatePrefab("Assets/Prefabs/Enemey2b_0.prefab",tar);

        prefab.tag = "Enemy";

        foreach (Transform obj in prefab.GetComponentInChildren<Transform>())
        {
            if (obj.name == "col")
            {
                //取消碰撞模型的显示
                MeshRenderer r = obj.GetComponent<MeshRenderer>();
                r.enabled = false;

                //添加Mesh 碰撞体
                if (obj.gameObject.GetComponent<MeshCollider>() == null)
                {
                    obj.gameObject.AddComponent<MeshCollider>();
                }
                obj.tag = "Enemy";
            }
        }

        //设置刚体
        Rigidbody rigid = prefab.AddComponent<Rigidbody>();
        rigid.useGravity = false;
        rigid.isKinematic = true;

        //为prefab 添加音乐组件
        prefab.AddComponent<AudioSource>();

        //获取子弹prefab
        GameObject rocket = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Prefabs/EnemyRocket.prefab");

        //取得爆炸效果prefab
        GameObject fx = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/FX/Explosion.prefab");

        //添加敌人脚本
        SuperEnemy enemy = prefab.AddComponent<SuperEnemy>();
        enemy.m_life = 5;
        enemy.m_point = 5;
        enemy.m_rocket = rocket.transform;
        enemy.m_explosionFx = fx.transform; 
    }
}

 

posted @ 2023-10-01 17:54  伟衙内  阅读(215)  评论(0编辑  收藏  举报