2013-07-27 23:55:48 hany3000 阅读数 2991
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚

There is a close relationship between Materials and Shaders in Unity. Shaders contain code that defines what kind of properties and assets to use. Materials allow you to adjust properties and assign assets.

在Unity中材质与着色器之间有着密切的关系。着色器包含着定义了属性和资源使用种类的代码。材质允许你调整属性和分配资源。

色器通过材质来实现
A Shader is implemented through a Material 着色器通过材质来实现

To create a new Material, use Assets->Create->Material from the main menu or the Project View context menu. Once the Material has been created, you can apply it to an object and tweak all of its properties in the Inspector. To apply it to an object, just drag it from the Project View to any object in the Scene or Hierarchy.

要创建新材质,从主菜单或项目视图的环境菜单中,选择Assets->Create->Material来创建。一旦材质已经创建,你可以将它应用到一个对象并在检视视图中调整其所有属性。要将它应用到一个对象,只需将它从项目视图中拖到场景视图或层次视图的某个对象上。

Setting Material Properties 设置材质属性

You can select which Shader you want any particular Material to use. Simply expand the Shader drop-down in the Inspector, and choose your new Shader. The Shader you choose will dictate the available properties to change. The properties can be colors, sliders, textures, numbers, or vectors. If you have applied the Material to an active object in the Scene, you will see your property changes applied to the object in real-time.

你可以选择你想要用于任何特殊材质的着色器。只需在检视视图中展开Shader下拉菜单,并选择你的新着色器。你选择的着色器将支配可用的属性发生变化。这些属性可以是颜色、滑块、纹理、数字、或向量。在场景中如果你已经将材质应用到一个活动对象,你会实时看到属性的更改应用到了对象。

There are two ways to apply a Texture to a property.

有两种方法可以将一个纹理应用到一个属性。

  1. Drag it from the Project View on top of the Texture square 
    从项目视图中拖动它到方形纹理上面
  2. Click the Select button, and choose the texture from the drop-down list that appears 
    单击Select(选择)按钮,然后从出现的下拉列表中选择纹理

Two placement options are available for each Texture:

  • Tiling 平铺
    Scales the texture along the different. 沿着不同的(方向)缩放纹理
  • Offset 偏移
    Slides the texture around. 纹理偏移

Built-in Shaders 内置着色器

There is a library of built-in Shaders that come standard with every installation of Unity. There are over 30 of these built-in Shaders, and six basic families.

Unity的每个标准安装包都有一个内置着色器的库。有超过30个内置着色器和六个基本族。

  • Normal: For opaque textured objects. 
    标准:对于不透明纹理对象
  • Transparent: For partly transparent objects. The texture's alpha channel defines the level of transparency. 
    透明:对于部分透明的对象。纹理的alpha通道定义透明度
  • TransparentCutOut: For objects that have only fully opaque and fully transparent areas, like fences. 
    透明剪影:对于拥有完全不透明和完全透明的区域的对象,比如栅栏
  • Self-Illuminated: For objects that have light emitting parts. 
    自身发光:对于有发光部件的对象
  • Reflective: For opaque textured objects that reflect an environment Cubemap
    反射:对于能反射外界立方体贴图的不透明纹理对象(比如镜子,本身不透明,但其反映的是外界环境的贴图——个人理解)

In each group, built-in shaders range by complexity, from the simple VertexLit to the complex Parallax Bumped with Specular. For more information about performance of Shaders, please read the built-in Shader performance page

在每一组中,内置的着色器按复杂性排列,从简单的顶点光亮到复杂的视差凸起镜面。如需更多有关着色器性能的信息,请阅读内置着色器性能页面

This grid displays a thumbnail of all built-in Shaders:

此网格显示所有内置着色器的缩略图:

Materials and Shaders(材质与着色器)
The builtin Unity shaders matrix

Shader technical details 着色技术细节

Unity has an extensive Shader system, allowing you to tweak the look of all in-game graphics. It works like this:

Unity有一个广泛的着色系统,让你来调整游戏中的所有图形外观。它的工作原理是这样的:

A Shader basically defines a formula for how the in-game shading should look. Within any given Shader is a number of properties (typically textures). Shaders are implemented through Materials, which are attached directly to individual GameObjects. Within a Material, you will choose a Shader, then define the properties (usually textures and colors, but properties can vary) that are used by the Shader.

一个着色器本质上定义了游戏中的明暗应该如何表现的规则。在任意给定的着色器里是一个属性(通常是纹理)的数量。着色器通过材质执行,直接附属到特定的游戏对象。在一个材质里,你可以选择一个着色器,然后定义属性(通常是纹理和色彩,但性质可能不同)由该着色器使用。

This is rather complex, so let's look at a workflow diagram:

这是相当复杂的,所以让我们看看一个工作流程图:

Materials and Shaders(材质与着色器)

On the left side of the graph is the Carbody Shader. 2 different Materials are created from this: Blue car Material and Red car Material. Each of these Materials have 2 textures assigned; the Car Texture defines the main texture of the car, and a Color FX texture. These properties are used by the shader to make the car finish look like 2-tone paint. This can be seen on the front of the red car: it is yellow where it faces the camera and then fades towards purple as the angle increases. The car materials are attached to the 2 cars. The car wheels, lights and windows don't have the color change effect, and must hence use a different Material. At the bottom of the graph there is a Simple Metal Shader. The Wheel Material is using this Shader. Note that even though the same Car Texture is reused here, the end result is quite different from the car body, as the Shader used in the Material is different.

图表的左边是车体着色器。 2个不同的材质是这样创建的:蓝色的汽车材质和红色的汽车材质。这些材质的每一个都有2个给定的纹理;汽车纹理定义汽车的主要纹理,和颜色特效纹理。这些属性被着色器所使用,使完成的汽车看上去像喷涂了两种色调。可以看到在红色车前面:面对相机的地方是黄色,然后随角度的增加消退成紫色。车材质附着到了两辆车上。而车轮、车灯和车窗没有颜色变化效果,因此必须使用不同的材质。在图表的底部有一个简单金属着色器。车轮材质使用这个着色器。请注意,即使同样的汽车纹理在这里被重用,最终车身产生的结果是完全不同的,因为在材质中使用的着色器是不同的。

To be more specific, a Shader defines:

更多具体细节,一个着色器定义了如下内容:

  • The method to render an object. This includes using different methods depending on the graphics card of the end user. 
    方法用以呈现(渲染)一个对象。这包括根据最终用户的图形卡使用不同的方法。
  • Any vertex and fragment programs used to render. 任意顶点和用于渲染的片段程序
  • Some texture properties that are assignable within Materials. 可指派到材质中的一些纹理属性
  • Color and number settings that are assignable within Materials. 
    可指派到材质中的颜色和编号设置

A Material defines:

一个材质定义了:

  • Which textures to use for rendering. 用于渲染的纹理
  • Which colors to use for rendering. 用于渲染的颜色
  • Any other assets, such as a Cubemap that is required by the shader for rendering. 
    一些其它资源,例如一个着色器渲染所必需的立方体贴图

Shaders are meant to be written by graphics programmers. They are created using the ShaderLab language, which is quite simple. However, getting a shader to work well on a variety graphics cards is an involved job and requires a fairly comprehensive knowledge of how graphics cards work.

着色器是图形程序员写的。他们创建使用ShaderLab语言,这很简单。但是要让一个着色器在各种图形卡上运行良好却是一个复杂的工作,需要对图形卡如何工作有一个相当全面的了解。

A number of shaders are built into Unity directly, and some more come in the Standard Assets Library. If you like, there is plenty more shader information in the Built-in Shader Guide.

许多着色器直接内置在Unity中,有些作为标准资源库。如果你喜欢,更多有关着色器的信息参见内置着色器指南

2013-08-24 12:40:00 weixin_34347651 阅读数 97
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚

 

要设置shader里有下划线的属性名,而不是后面字符串的属性名。

 

Color tmp = new Color(1,1,1,alpha);
mat.SetColor("_Color", tmp);

 

2017-10-10 11:30:12 qq_30087879 阅读数 423
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚
unity3d设置材质的shader
paticle.GetComponent<Render>().material.shader = Shader.Find("Particles/Additice");
2013-10-31 23:27:47 a117653909 阅读数 9132
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚
Win7   Unity3D 4.2.0f4
同事给我一些Fbx格式的角色动画,包括几个图片文件夹,和一个Materials文件夹。但我在导入Unity3D时,但主角的材质却丢失。
解决办法是把Materials文件夹删掉,然后那个文件夹上右键选择reimport,即可解决问题。
2017-07-19 19:50:25 jxw167 阅读数 2875
  • Unity3D入门到精通-(3)Unity资源管理精讲

    本次系列课程的目标是让Unity3D初学者掌握Unity3d的资源管理技术进行了全面介绍,特别对AssetBundle资源如何进行更新,以及加载(依赖资源加载)进行了系统的介绍。 适合对象:Unity初学开发者,Unity中级开发者,网络程序开发者,所有对游戏开发有兴趣的人员。 学习条件:有一定的Unity3D基础,了解C#的基本开发知识。

    4646 人正在学习 去看看 张刚

笔者介绍:姜雪伟,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 即可实现丢失脚本的查找,它可以分成多个部分查找,自己可以去测试一下。


Unity3D 材质丢失

阅读数 4331

Unity3D 材质球学习

阅读数 12403

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