2013-03-01 00:48:22 jeksonal 阅读数 33640

动态更改材质球纹理的步骤:

1:找到对应的材质球

2:更改材质球纹理 ---->  renderer.material.mainTexture = "目标纹理";



代码如下:


点击按钮,就能实现对应功能



2013-01-26 23:13:02 yuyingwin 阅读数 662

材质更换:
              通过点击物体选取,并通过按钮给物体赋予不同的贴图

截屏:通过按钮截取屏幕,并实现本地存储,适用于PC机单机作品

下载路径:http://115.com/u/84345888    文件名 更换物体材质及截屏存储(本地)

2017-07-19 19:50:25 jxw167 阅读数 2850

笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

在游戏开发中,UI是经常需要变动的,一款游戏从开发到结束,UI至少更换好多版,这就给替换UI的人增加了很多负担,认为的因素很难将旧的UI彻底删除掉,这样就会出现很多冗余的资源,在项目后期要将这些冗余的资源清除掉,如果单靠人工操作难免会出现各种错误,其实我们完全可以通过工具将它们删除掉。下面把删除冗余的工具代码给读者展示如下:

using UnityEngine;
using UnityEditor;

using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Text;
using System;

public static class LinqHelper {
    public static TSource Fold<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func, TSource id)
    {
        TSource r = id;
        foreach (var s in source)
        {
            r = func(r, s);
        }
        return r;
    }
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (T element in source)
            action(element);
    }
    public static IEnumerable<U> SelectI<U, T>(this IEnumerable<T> source, Func<T, int, U> action)
    {
        int i = 0;
        foreach (var s in source)
        {
            yield return action(s, i);
            i += 1;
        }
    }
    public static TSource Reduce<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func) where TSource : new()
    {
        return Fold<TSource>(source, func, new TSource());
    }
    public static void ForEachI<T>(this IEnumerable<T> source, Action<T, int> action)
    {
        int i = 0;
        foreach (T element in source)
        {
            action(element, i);
            i += 1;
        }

    }
}
public static class FindUnUnUsedUITexture
{


    static List<string> getUUIDsInFile(string path)
    {
        StreamReader file = new StreamReader(path);
        List<string> uuids = new List<string>();
        string line;
        while ((line = file.ReadLine()) != null)
        {
            var reg = new Regex(@"([a-f0-9]{32})");
            var m = reg.Match(line);
            if (m.Success)
            {
                uuids.Add(m.Groups[0].Value);
            }
        }
        file.Close();
        return uuids;
    }
    // Use this for initialization
    [MenuItem("Tools/UI冗余图片扫描")]
    public static void Scan()
    {

        var uiPrefabRootDir = EditorUtility.OpenFolderPanel("选择UIPrefab目录",  "Assets","");
        if (string.IsNullOrEmpty(uiPrefabRootDir))
        {
            return;
        }

        var uiPicRootDir = EditorUtility.OpenFolderPanel("选择UIPrefab目录", "Assets", "");
        if (string.IsNullOrEmpty(uiPicRootDir))
        {
            return;
        }
        
        //find all meta and pic path
        var uuidReg = new Regex(@"guid: ([a-f0-9]{32})");
        var pngs = Directory.GetFiles(uiPicRootDir, "*.meta", SearchOption.AllDirectories)
        .Select(p => "Assets/" + p.Replace('\\','/').Substring(Application.dataPath.Length+1))
        .Where(p =>
        {
            return p.EndsWith(".png.meta") || p.EndsWith(".jpg.meta") || p.EndsWith(".tag.meta");
        }).ToList();
        var uuid2path = new Dictionary<string, string>();
        pngs.ForEachI((png, i) =>
        {
            var matcher = uuidReg.Match(File.ReadAllText(png));
            var uuid = matcher.Groups[1].Value;
            if (uuid2path.ContainsKey(uuid))
            {
                Debug.LogError("uuid dup" + uuid + " \n" + png + "\n" + uuid2path[uuid]);
            }
            else
            {
                uuid2path.Add(uuid, png.Substring(0,png.Length-5));
            }
            EditorUtility.DisplayProgressBar("扫描图片中", png, (float)i / pngs.Count);

        });

        //find all prefab and search pic uuid
        var prefabs = Directory.GetFiles(uiPrefabRootDir, "*.prefab", SearchOption.AllDirectories);
        var anims = Directory.GetFiles("Assets/", "*.anim", SearchOption.AllDirectories).Where(p => !p.Replace('\\', '/').Contains("Characters/"));
        var allFiles = prefabs.Concat(anims).ToList();
        var alluuids = allFiles
        .SelectI((f, i) => {
            EditorUtility.DisplayProgressBar("获取引用关系", f, (float)i / allFiles.Count);
            return getUUIDsInFile(f);
        }).ToList().Aggregate((a, b) => a.Concat(b).ToList()).ToList();
        EditorUtility.ClearProgressBar();
        //rm used pic uuid
        var uuidshashset = new HashSet<string>(alluuids);
        var em = uuidshashset.GetEnumerator();
        while(em.MoveNext())
        {
            var uuid = em.Current;
            uuid2path.Remove(uuid);
        }

        StringBuilder sb = new StringBuilder();
        sb.Append("UnUsedFiles: ");
        sb.Append(uuid2path.Count);
        sb.Append("\n");
        uuid2path.ForEach(kv => sb.Append(kv.Value +"\n"));

        File.WriteAllText("Assets/unusedpic.txt", sb.ToString());
        EditorUtility.DisplayDialog("扫描成功", string.Format("共找到{0}个冗余图片\n请在Assets/unsedpic.txt查看结果",uuid2path.Count), "ok");
    }
}
将该脚本放置到Editor文件夹下面,然后在Tool菜单下点击UI冗余图片扫描就会弹出窗口将冗余的UI图片列出来,非常方便。

另外,在游戏中经常出现脚本丢失情况,自己查找非常麻烦,这个也可以通过工具去查找,代码如下所示:

using System.Linq;
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.IO;
using System;

public static class MissingScriptFinder 
{
    private const string MENU_ROOT = "Tool/Missing References/";
    public static string GetHierarchyName(Transform t)
    {
        if (t == null)
            return "";

        var pname =  GetHierarchyName(t.parent);
        if (pname != "")
        {
            return pname + "/" + t.gameObject.name;
        }
        return t.gameObject.name;
    }

    public static TSource Fold<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func,TSource id)
    {
        TSource r = id;
        foreach(var s in source)
        {
            r = func(r,s);
        }
        return r;
    }
    public static void ForEachI<T>(this IEnumerable<T> source, Action<T,int> action)
    {
        int i = 0;
        foreach (T element in source)
        {
            action(element,i);
            i += 1;
        }
            
    }
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (T element in source)
        {
            action(element);
        }
            
    }

    static HashSet<string> findAllScriptUUIDsInAssets()
    {
        var uuids = Directory.GetFiles("Assets/", "*.cs.meta", SearchOption.AllDirectories)
            .Select(p =>
            {
                return File.ReadAllLines(p)[1].Substring(6);
            }).ToList();
        //find dll uuids
        var dlluuids = Directory.GetFiles(EditorApplication.applicationContentsPath, "*.dll", SearchOption.AllDirectories)
        .Select(p =>
        {
            return AssetDatabase.AssetPathToGUID(p.Replace('\\', '/'));
        }).Where(s => s!= "").ToList();
        return new HashSet<string>(uuids.Concat(dlluuids));
    }
    static Regex s_scriptUUIDReg = new Regex(@"m_Script: \{fileID: [0-9]+, guid: ([0-9a-f]{32}), type: 3\}");
    static string getScriptUUID(string line)
    {
        var m = s_scriptUUIDReg.Match(line);
        if (m.Success)
        {
            return m.Groups[1].Value;
        }
        if(line.Contains("m_Script: {fileID: 0}")) //missing script
        {
            return "0";
        }
        return null;
    }
    static Dictionary<string,HashSet<string>> findAllPrefabScriptRefInDir(string dir,Action<int> onBeginFinding,Action<int,string,int> onFinding, Action onEndFinding )
    {
        var allPrefabs = Directory.GetFiles(dir, "*.prefab", SearchOption.AllDirectories);
        onBeginFinding(allPrefabs.Length);
        Dictionary<string, HashSet<string>> r = new Dictionary<string, HashSet<string>>();
        
        for (int i =0;i<allPrefabs.Length;++i)
        {
            onFinding(i, allPrefabs[i],allPrefabs.Length);
            File.ReadAllLines(allPrefabs[i]).ForEach(line =>
            {
                string s = getScriptUUID(line);
                if (s != null)
                {
                    HashSet<string> files = null;
                    r.TryGetValue(s, out files);
                    if (files == null)
                    {
                        files = new HashSet<string>();
                        r.Add(s, files);
                    }
                    files.Add(allPrefabs[i]);
                }
            });
        }
        onEndFinding();
        return r;
    }


    private static void FindMissionRefInGo(GameObject go)
    {
        var components = go.GetComponents<MonoBehaviour>();
        foreach (var c in components)
        {
            // Missing components will be null, we can't find their type, etc.
            if (!c)
            {
                var assetPath =  AssetDatabase.GetAssetPath(go);
                if(assetPath != "" && assetPath != null)
                {
                    Debug.LogError("missing script: " + GetHierarchyName(go.transform) + "-->" + assetPath);
                }
                else
                {
                    Debug.LogError("missing script: " + GetHierarchyName(go.transform));
                }
                continue;
            }
        }
        foreach(Transform t in go.transform)
        {
            FindMissionRefInGo(t.gameObject);
        }
    }
    public static IEnumerable<GameObject> SceneRoots()
    {
        var prop = new HierarchyProperty(HierarchyType.GameObjects);
        var expanded = new int[0];
        while (prop.Next(expanded))
        {
            yield return prop.pptrValue as GameObject;
        }
    }
    [MenuItem(MENU_ROOT + "search in scene")]
    public static void FindMissingReferencesInCurrentScene()
    {
        var objs = SceneRoots();
        int count = objs.Count();
        objs.ForEachI((prefab, i) =>
        {
            EditorUtility.DisplayProgressBar("check missing prefabs", prefab.ToString(), (float)i / count);
            FindMissionRefInGo(prefab);
        });
        EditorUtility.ClearProgressBar();
    }

    [MenuItem(MENU_ROOT + "search in all assets")]
    public static void MissingSpritesInAssets()
    {
        var allScriptsIds = findAllScriptUUIDsInAssets();
        var refScriptIds = findAllPrefabScriptRefInDir("Assets/",
        (count) =>
        {
            EditorUtility.DisplayProgressBar("scanning","",0);
        },
        (idx,file,count) =>
        {
            EditorUtility.DisplayProgressBar("scanning", file, (float) idx/count);
        },
        () =>
        {
            EditorUtility.ClearProgressBar();
        });
        var missingScriptsFiles = refScriptIds
        .Where(kv => !allScriptsIds.Contains(kv.Key))
        .Select(kv => kv.Value)
        .ToList()
        .Fold((a,b)=>new HashSet<string>(a.Concat(b)),new HashSet<string>());
        Debug.LogError("----------------------------------------->\nMissingFiles: "  + missingScriptsFiles.Count);
        missingScriptsFiles.ForEachI((f, i) =>
        {
            EditorUtility.DisplayProgressBar("check missing prefabs", f, (float)i / missingScriptsFiles.Count);
            var prefab = AssetDatabase.LoadAssetAtPath(f, typeof(GameObject)) as GameObject;
            FindMissionRefInGo(prefab);
        });
        EditorUtility.ClearProgressBar();
    }

}
同样需要将该脚本放置到Editor文件夹下面,点击菜单栏中的Tool/Missing Reference 即可实现丢失脚本的查找,它可以分成多个部分查找,自己可以去测试一下。


2019-07-12 19:28:59 qq_42440767 阅读数 115

今天遇到了这样的一个需求觉得很有建设性:在摄像机跟随角色移动的过程中,如果遇到物体遮挡,将其变为透明材质,物体移开后还原初始材质。
下面是我的实现方式:~

1、创建射线。(顺便把透明材质球加载出来)

  private Ray ray;
  
   //透明材质球
  private Material alphaMate;
  
 void Start()
  {
    ray = Camera.main.ScreenPointToRay(transform.position);
	
    alphaMate = Resources.Load<Material>("Ambient Particle");
  }

2、代码方面的准备工作。

 RaycastHit hit;

  //照射到的物体
  private GameObject selectModel;
  
  //遮挡物的所有材质
  private MeshRenderer[] targetMeshs;
  
  //用来存储遮挡物变透明之前的所有材质
  private List<Material> tempMats = new List<Material>();

3、接下来就是替换方法了。

 void ChangeMates()
  {
    //圆柱形射线检测:起点为摄像机位置,圆柱半径0.5,方向沿摄像机Z轴正方向射出500的长度。
    if (Physics.SphereCast(CameraTrans.position, 0.5f, CameraTrans.forward, out hit, 500))
    {
      //通过碰撞物体的名字判断是否为遮挡物
      if (hit.collider.gameObject.name == "Collider")
      {
        //将遮挡物暂存在selectModel中,以便之后的还原材质
        selectModel = hit.collider.gameObject;  
        if (selectModel != null)
        {
          //获取到遮挡物中的所有原始材质球
          targetMeshs = hit.collider.transform.parent.GetComponentsInChildren<MeshRenderer>();
          //更换材质球
          for (int i = 0; i < targetMeshs.Length; i++)
          {
            //暂存遮挡物的原始材质
            tempMats.Add(targetMeshs[i].material);
            //更换透明材质
            targetMeshs[i].material = alphaMate;
          }
        }
       }
      else //遮挡物移开
      {
        //判断遮挡物是否已经被更换完毕
        if (selectModel != null)
        {
          for (int i = 0; i < targetMeshs.Length; i++)
          {
            //还原材质
            targetMeshs[i].material = tempMats[i];
          }
          //清空selectModel信息和list。
          selectModel = null;
          tempMats.Clear();  
        }
      }

有更好的方法欢迎指点。

如果对你有帮助,酌情打赏~

在这里插入图片描述 在这里插入图片描述

2016-03-24 12:00:11 asd237241291 阅读数 3491
作为一名高贵的程序猿,通过代码让电脑代替自己的工作是我们存在的意义。
不管要更换的是什么东西,我们都可以用一个prefab把它们替换掉。

都在代码里,走一个~

using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
/// <summary>
/// 改变Prefab
/// 注:通过名字匹配搜索被替换目标
/// (被选中物体的所有子物体.name包含newPrefab.name则替换)
/// </summary>
public class ChangePrefab : EditorWindow 
{

    [MenuItem("DuanTools/换Prefab")]
    public static void Open()
    {
        EditorWindow.GetWindow(typeof(ChangePrefab));
    }

    public GameObject newPrefab;
    static GameObject tonewPrefab;

    void OnGUI()
    {

        newPrefab = (GameObject)EditorGUILayout.ObjectField(newPrefab, typeof(GameObject),true, GUILayout.MinWidth(100f));
        tonewPrefab = newPrefab;
        if (isChange)
        {
            GUILayout.Button("正在变...");
        }
        else
        {
            if (GUILayout.Button("变变变!"))
                Change();
        }
    }

    static bool isChange = false;

    public static void Change()
    {
        if (tonewPrefab == null)
            return;

        isChange = true;
        List<GameObject> destroy = new List<GameObject>();
        Object[] labels = Selection.GetFiltered(typeof(GameObject), SelectionMode.Deep);
        foreach (Object item in labels)
        {
            GameObject tempGO = (GameObject)item; // (GameObject)item;
            //只要搜到的物体包含新Prefab的名字,就会被替换
            if (tempGO.name.Contains(tonewPrefab.name))
            {
                GameObject newGO = (GameObject)Instantiate(tonewPrefab);
                newGO.transform.SetParent(tempGO.transform.parent);
                newGO.name = tempGO.name;
                newGO.transform.localPosition = tempGO.transform.localPosition;
                newGO.transform.localRotation = tempGO.transform.localRotation;
                newGO.transform.localScale = tempGO.transform.localScale;

                destroy.Add(tempGO);
            }
        }
        foreach (GameObject item in destroy)
        {
            DestroyImmediate(item.gameObject);
        }
        isChange = false;
    }
}

下面是使用方法:
首先打开刚才制作的编辑器窗口,选择一个要替换成的Prefab。
然后在游戏场景内寻则要被替换物体的最父级。
点击“变变变”,所有包含新prefab名字的场景内物体都会被替换掉了。

没有更多推荐了,返回首页