unity3d 信息提示狂_unity3d界面介绍 unity3d.com - CSDN
  • unity提示消息窗口

    千次阅读 2016-03-12 10:50:14
    本贴是自用提示消息窗口,仅供参考。 1.首先要有一个提示消息框的预制体。 2.本框架注意加载资源的地方需要改一下。 MessageBox sing UnityEngine ; /// /// 通用对话框通用类 /// public class MessageBox...

    本贴是自用提示消息窗口,仅供参考。

    1.首先要有一个提示消息框的预制体。

    2.本框架注意加载资源的地方需要改一下。

    MessageBox

    sing UnityEngine ;
    
    /// <summary>
    /// 通用对话框通用类
    /// </summary>
    public class MessageBox : MonoBehaviour
    {
        public delegate void MessageDelegate( System.Object obj);
        public MessageDelegate OkClick ;
        public MessageDelegate CancelClick ;
    
        private string customTextOK ;
        public string TextOK
        {
            get { return textOK. text; }
            set
            {
                textOK.text = value;
                customTextOK = value ;
            }
        }
    
        private string customTextCancel ;
        public string TextCancel
        {
            get { return textCancel. text; }
            set
            {
                textCancel.text = value;
                customTextCancel = value ;
            }
        }
    
        public int WidthOK
        {
            get { return widgetOK. width; }
            set
            {
                widgetOK.width = value;
            }
        }
    
        public int WidthCancel
        {
            get { return widgetCancel. width; }
            set
            {
                widgetCancel.width = value;
            }
        }
    
        public string Content
        {
            get { return content. text; }
            set
            {
                content.text = value;
            }
        }
    
        public int WitdhContent
        {
            get { return content. width; }
            set
            {
                content.width = value;
            }
        }
    
        public int StartingRenderQueue
        {
            get { return uiPanel. startingRenderQueue; }
            set
            {
                uiPanel.startingRenderQueue = value;
            }
        }
    
        public UIWidget.Pivot ContentPivot
        {
            get { return content. pivot; }
            set
            {
                content.pivot = value;
            }
        }
    
        // 延迟启用确定按钮
        private float delayOkTime = 0;
        public float DelayOkTime
        {
            get { return delayOkTime; }
            set
            {
                delayOkTime = value ;
            }
        }
    
        // 延迟启用取消按钮
        private float delayCancelTime = 0;
        public float DelayCancelTime
        {
            get { return delayCancelTime; }
            set
            {
                delayCancelTime = value ;
            }
        }
    
        public enum Type
        {
            OK,
            OKCancel,
            Custom1Btn,         // 自定义一个按钮
            Custom2Btn,         // 自定义两个按钮
        };
        public Type type { get; private set; }
        // 点背景是不是可以关闭对话框
        public bool CanCloseByFadeBGClicked = true;
        // 点击背景是否关闭对话框,只是关闭,不执行其他
        public bool IsCloseByFadeBGClicked = false;
    
        public System.Object userData { get; private set; }
    
        private UIPanel uiPanel ;
        private UISprite messageBoxBg ;
        private UILabel content ;
        public UIButton btnOK ;
        private UILabel textOK ;
        private UIWidget widgetOK ;
        private UIButton btnCancel ;
        private UILabel textCancel ;
        private UIWidget widgetCancel ;
    
        private GameObject fadeBG ;
    
        void Awake()
        {
            this.transform .localPosition = new Vector3 (0, 0, -3200 + GameUIManager. UI_Z_OFFEST);
    
            uiPanel = this .GetComponent< UIPanel>();
            messageBoxBg = this .transform. FindChild("WinBG" ).GetComponent< UISprite>();
            content = messageBoxBg .transform. FindChild("Content" ).GetComponent< UILabel>();
            btnOK = messageBoxBg .transform. FindChild("OK" ).GetComponent< UIButton>();
            textOK = btnOK .transform. FindChild("Label" ).GetComponent< UILabel>();
            widgetOK = btnOK .transform. GetComponent<UIWidget >();
            btnCancel = messageBoxBg .transform. FindChild("Cancel" ).GetComponent< UIButton>();
            textCancel = btnCancel .transform. FindChild("Label" ).GetComponent< UILabel>();
            widgetCancel = btnCancel .transform. GetComponent<UIWidget >();
    
            fadeBG = this .transform. FindChild("FadeBG" ).gameObject;
    
            UIEventListener.Get (btnOK.gameObject). onClick += this .OnOKClicked;
            UIEventListener.Get (btnCancel. gameObject).onClick += this.OnCancelClicked;
            UIEventListener.Get (fadeBG). onClick += this .OnFadeBGClicked;
        }
    
        void OnDisable()
        {
            OkClick = null ;
            CancelClick = null ;
            userData = null ;
        }
    
        void DestroySelf()
        {
            DestroyImmediate(this .gameObject);
        }
    
        protected void Close ()
        {
            btnOK.gameObject .collider. enabled = false ;
            btnCancel.gameObject .collider. enabled = false ;
            fadeBG.collider .enabled = false;
            GameUITools.PlayCloseWindowAnim (messageBoxBg. transform, null , false);
            // 自己维护自己的对象销毁时机,避免HOTween生命周期导致的回调函数没有被执行的问题
            Invoke("DestroySelf" , 0.25f);
        }
    
        void Update()
        {
            if (delayOkTime > 0)
            {
                delayOkTime -= RealTime .deltaTime;
                if (delayOkTime <= 0)
                {
                    btnOK.isEnabled = true;
                    if (!string .IsNullOrEmpty( customTextOK))
                    {
                        textOK.text = customTextOK;
                    }
                }
                else
                {
                    btnOK.isEnabled = false;
                     //这里显示倒计时本来是为了检测到加速器是显示倒计时,实际使用加速器之后倒计时也被加速了
                    if (!string .IsNullOrEmpty( customTextOK))
                    {
                        textOK.text = string. Format("{0}({1})" , customTextOK, ( int)(delayOkTime + 1));
                    }
                }
            }
    
            if (delayCancelTime > 0)
            {
                delayCancelTime -= RealTime .deltaTime;
                if (delayCancelTime <= 0)
                {
                    btnCancel.isEnabled = true;
                    if (!string .IsNullOrEmpty( customTextCancel))
                    {
                        textCancel.text = customTextCancel;
                    }
                }
                else
                {
                    btnCancel.isEnabled = false;
                    if (!string .IsNullOrEmpty( customTextCancel))
                    {
                        textCancel.text = string. Format("{0}({1})" , customTextCancel, ( int)(delayOkTime + 1));
                    }
                }
            }
        }
    
        public void OnOKClicked (GameObject go)
        {
            if (Globals .Instance. GameMgr.Status != GameManager. EGameStatus.EGS_None )
            {
                Globals.Instance .EffectSoundMgr. Play("ui/ui_001" );
            }
          
            Close();
            if (OkClick != null)
            {
                OkClick(userData );
            }
        }
    
        public void OnFadeBGClicked (GameObject go)
        {
            if (CanCloseByFadeBGClicked )
            {
                OnCancelClicked(go );
            }
            else if (IsCloseByFadeBGClicked)
            {
                Close();
            }
        }
    
        public void OnCancelClicked (GameObject go)
        {
            if (Globals .Instance. GameMgr.Status != GameManager. EGameStatus.EGS_None )
            {
                Globals.Instance .EffectSoundMgr. Play("ui/ui_002" );
            }
    
            Close();
            if (CancelClick != null)
            {
                CancelClick(userData );
            }
        }
    
        public MessageBox Show (string text, MessageBox .Type type, System. Object data )
        {
            gameObject.SetActive (true);
            GameUITools.PlayOpenWindowAnim (messageBoxBg. transform, null , false);
    
            content.text = text;
            TextOK = StringManager .Instance. GetString("OK" );
            TextCancel = StringManager .Instance. GetString("Cancel" );
    
            bool isOnlyOneBtn = (type == Type.OK || type == MessageBox.Type .Custom1Btn);
            Vector3 pos = btnOK.transform. localPosition;
            pos.x = isOnlyOneBtn ? 0 : 90.5f;
            btnOK.transform .localPosition = pos;
            NGUITools.SetActive (btnCancel. gameObject, !isOnlyOneBtn );
    
            OkClick = null ;
            CancelClick = null ;
            userData = data ;
            delayOkTime = 0;
            delayCancelTime = 0;
            widgetOK.width = 83;
            widgetCancel.width = 83;
    
            btnOK.gameObject .collider. enabled = true ;
            btnCancel.gameObject .collider. enabled = true ;
            fadeBG.collider .enabled = true;
            CancelInvoke("DestroySelf" );
    
            if (Globals .Instance. TutorialMgr != null )
            {
                Globals.Instance .TutorialMgr. InitializationCompleted(this );
            }
    
            return this ;
        }
    
        public MessageBox Show (string text, MessageBox .Type type, Object userData, MessageDelegate OkCallback, MessageDelegate CancelCallback)
        {
            MessageBox msg = Show(text, type, userData);
            this.OkClick = OkCallback;
            this.CancelClick = CancelCallback;
            return msg ;
        }
    }
    

    接着是他的父类:

    using UnityEngine ;
    using System .Collections;
    /// <summary>
    /// 游戏中通用的确认框
    /// </summary>
    ///
    public class GameMessageBox : MessageBox
    {
        public static GameMessageBox Instance = null;
    
        /// 通用弹出对话框接口
        /// </summary>
        /// <param name="content"> 提示文本</param>
        /// <param name="type"> 按钮类型,决定按钮布局和显示的文字 </param>
        /// <param name="userData"> 允许记录一个中间数据,给回调函数 </param>
        /// <returns></returns>
        public static GameMessageBox ShowMessageBox( string content , Type type, System. Object userData )
        {
            if (string .IsNullOrEmpty( content))
            {
                return null ;
            }
            if (Instance == null)
            {
                GameObject prefab = Res.LoadGUI( "GUI/MessageBox");
                if (prefab == null)
                {
                    Debug.LogError ("Res.Load GUI/MessageBox error");
                    return null ;
                }
                GameObject go = NGUITools. AddChild(GameUIManager .mInstance. uiCamera.gameObject , prefab);
                if (go == null)
                {
                    Debug.LogError ("AddChild error");
                    return null ;
                }
                // 修改一下z值,为了适应界面上的材质表现
                Vector3 pos = go.transform. localPosition;
                pos.z += GameUIManager. UI_Z_OFFEST;
                go.transform .localPosition = pos;
    
    
                Instance = go .AddComponent< GameMessageBox>();
            }
            if (Instance != null)
            {
                Instance.Show (content, type, userData );
            }
            return Instance ;
        }
                    
    }
    

    测试界面,别忘了拖到摄像机上。

    using UnityEngine ;
    using System .Collections;
    
    public class CutTest : MonoBehaviour {
    
                     void OnGUI ()
        {
            if (GUI .Button( new Rect (10, 10, 100, 20), "OKMessage"))
            {
                GameMessageBox messageBox = GameMessageBox. ShowMessageBox("这是OK信息框" , MessageBox.Type .OK, null);
                messageBox.CanCloseByFadeBGClicked = false;
                messageBox.OkClick += OnOkClick;
            }
            if (GUI .Button( new Rect (10, 30, 100, 20), "OKCanelMessage"))
            {
                GameMessageBox messageBox = GameMessageBox. ShowMessageBox("这是OKCancel信息框" , MessageBox.Type .OKCancel, null);
                messageBox.OkClick += OnOkClick;
                messageBox.CancelClick += OnCancelClick;
                messageBox.CanCloseByFadeBGClicked = true;
            }
            if (GUI .Button( new Rect (10, 50, 100, 20), "Custom1Message"))
            {
                GameMessageBox messageBox = GameMessageBox. ShowMessageBox("这是Custom1信息框" , MessageBox.Type .Custom1Btn, null);
                messageBox.OkClick += OnCustome1Click;
                messageBox.ContentPivot = UIWidget. Pivot.Center ;// 居中显示
                messageBox.WidthOK = 132;
                messageBox.CanCloseByFadeBGClicked = false;
            }
            if (GUI .Button( new Rect (10, 70, 100, 20), "Custom2Message"))
            {
                GameMessageBox messageBox = GameMessageBox. ShowMessageBox("这是Custome2信息框" , MessageBox.Type .Custom2Btn, null);
                messageBox.OkClick += OnOkClick;
                messageBox.CancelClick += OnCancelClick;
                messageBox.CanCloseByFadeBGClicked = true;
            }
           
        }
        private void OnCustome1Click (System. Object o )
        {
            Debug.Log ("Custom1Message");
        }
        private void OnOkClick (System. Object o )
        {
            Debug.Log ("OKMessage");
        }
        private void OnCancelClick (System. Object o )
        {
            Debug.Log ("CancelMessage");
        }
    }
    








    展开全文
  • Unity3D Shader 入门第一天

    千次阅读 2018-07-18 15:21:26
    刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步。该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D中的表面着色器...

    刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步。该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D中的表面着色器(Surface Shader)的,为学习更复杂的Shader编程打下基础。

    动机

    如果你是刚刚接触Shader编程的新手,你可能不知道从何开始踏出Shader编程的第一步。本教程将带你一步步完成一个表面着色器(Surface Shader)和片段着色器(Fragment Shader)。本教程也将介绍在Unity3D Shader编程中所使用的一些函数和变量,这些内容可能和你在网上看到的不一样哦!

    如果你满足下面的条件,我觉得你应该看看这篇文章:

    • 如果你是shader编程的新手。
    • 你想在你的游戏中使用shader做一些很炫酷的效果,但是你在网上找不到可用的Shader(译者注:o(╯□╰)o自己动手丰衣足食)。
    • 由于缺乏对基础知识的了解,造成不能随心所欲使用Strumpy着色器编辑器(译者注:Strumpy Shader Editor,一种图形化编写shader的方式,看着很诱人!)。
    • 你想在你的shader代码中手动处理纹理(Textures)

    本文是该系列教程的第一篇文章,随后我们会制作一些更复杂的shader。相比起来,第一篇文章确实很简单。

     

    My reason for getting into shader programming was to build something that I needed for a world populated with an endless array of different characters.  I needed to build a combined mesh out of multiple parts so I only have one draw call per character.

    通过打开和关闭角色的穿衣效果,我使用Megafiers(一个变形插件)修改了角色的基本网格(base meshes)。其中的困难在于我只有一个纹理(texture),但是我却想给每个角色的皮肤,服饰以及其他的特征使用不同的颜色。我想到一个方法----对每个角色使用不同的3个4x4纹理,并使用一个shader来给模型上色。我将在整个教程中详细描述我做的这个shader,但是现在—我想你们已经迫不及待地想看我创建的角色表演一段即兴的快闪舞(flash mob dance)(译者注:网上截的图片)。

    技术分享

    着色器和材质(shaders&materials)

    一个shader所做的就是将一个模型的网格(mesh)渲染到屏幕上。Shader可以被定义为一系列的属性(译者注:就像一个函数里面的参数一样,你可以改变函数的不同赋值来改变函数的输出结果),你可以通过改变这些属性来改变模型渲染到屏幕上的效果。而这些属性被存放起来,放到一个叫做材质(material)的地方。

    Unity3D Shader有以下几种

    • 表面着色器(surface shader)----后台自动为你做的绝大部分的工作,减少了你工作量,并且适合绝大多数需要shader的情况。
    • 片段着色器(fragment shader)----可以让你做更多的效果,但是此shader更难写。你也可以用它做一些底层的工作,比如顶点光照(Vertex lighting,即在每个顶点存储该点的光照信息)。顶点光照对于移动设备很有用(译者注:估计省内存吧)。该shader对于一些需要多通道(multiple passes)的高级渲染效果也很有效。

    本文中我们将关注点放在表面着色器上。

    学习Shader的资源

    如果你要学习Shader编程,我向你推荐下面几个资源

    • Martin Kraus‘s fantastic Wiki Book GLSL Programming/Unity
    • Unity‘s Shader Reference
    • NVidia‘s tutorial on the CG programming language
    • CreativeTD‘s video series on writing surface shaders

    Shader的流水化工作方式

    (译者注:Shader的工作方式也称为shader流水线(pipeline),因为shader工作方式很类似汽车流水线,将模型上一系列顶点数据和其他各种数据作为输入,用这个shader组成的流水线加工下,出来的就成了炫酷的效果了。)

    你将在shader流水线中看到不明觉厉的各种术语,我将用我自己的语言尽量降低理解的难度。

    Shader的工作就是输入一些3D几何信息,经过shader处理后将其变为2D的像素呈现在屏幕上。好处是在shader处理过程中,你只需要改变少数几个属性就可以产生不同的效果。对于表面着色器,该工作流程看起来像下面这样:

    技术分享

    (译者注:简单讲解一下这个流程图,首先要渲染的物体将自己的几何信息传递到Shader中,并且系统得到了该物体的顶点信息,然后你可以选择经不经过Vertex Function来处理这些顶点信息,随后经过光栅化(将三维几何信息映射到二维屏幕上,打个不恰当的比喻,相当于把3D模型拍扁到屏幕上,然后你就可以专心处理屏幕上的像素了),每个像素经过你的shader代码将得到最终的颜色值)

    注意在表面着色器(Surface Shader)中的函数退出之前,像素的颜色还没有计算出来。这意味着你可以再次之前传入顶点的法向量来影响光照的计算。

    片段着色器(Fragment Shader)有着同样的工作流程,但事实上,片段着色器中必须有Vertex Function(上图中的Vertex Function部分就是可选的(Optional)),而且需要在像素处理阶段做很多的工作才能产生最终的像素。而表面着色器隐藏了这些。(译者注:给我的感觉就是片段着色器向用户提供了更多的接口进行更高级的渲染)。

    下图展示了你的代码如何被调用以及代码构成

    技术分享

    从上图我们可以看到,当你写一个shader的时候,你可能得有一些属性值(properties),并且有一个或多个Subshaders。具体使用哪个Subshader进行处理取决于你的运行平台。你应该还要指定一个Fallback shader,当你的subshader没有一个能运行在你的目标设备上,将使用Fallback shader(译者注:有点像备胎)。

    每个Subshader都至少有一个通道(pass)作为数据的输入和输出。你可以使用多个通道(passes)执行不同的操作,比如在一个Grab Pass中,你可以获取将要呈现到屏幕上的像素值(译者注:类似于glsl中的fragment buffer)。当你想制作高级的扭曲效果,这非常有用。虽然当你开始学习shader编程时,你可能并不会使用到它。另外一个使用多通道(multiple passes)的原因是在不同时刻,你可能需要写入或者禁止写入深度缓存的使用。

    当你写表面着色器时,我们将直接在Subshader这个层次上写代码,系统将把我们的代码编译成若干个合适的通道(pass)。

    尽管shader最终产生的是二维像素,但是其实这些像素除了保存xy坐标外,本身保存着深度值(即每个像素点上的内容在原先3D场景中离照相机的远近),这样距离照相机近的物体就会把距离照相机远的物体遮挡住,在屏幕上显示时,就是将其像素值覆盖。

    你可以控制是否在你的shader中使用深度缓存(Z-buffer)产生一些特效,或者在Pass中使用一些指令决定shader是否可以写入Z-buffer:比如使用ZWrite Off时,任何你输出的东西都不会更新Z-buffer的值,即关闭的Z-Buffer的写入功能。

    你可以使用Z-buffer技术在别的物体上掏出一个洞,你可以先写入需要打洞区域的深度值,但不输出打洞区域所属的像素值,然后在你模型后面的物体的深度值将无法写入(因为Z-buffer觉得你的模型已经挡住了后面的物体)(译者注:这样你打洞区域显示的就是一开始使用的背景色,会造成一个洞穿过了这些物体的效果)。

    下面是一些shader代码:

    技术分享

    希望你能看出上面代码是由Properties,SubShader,Fallback三段代码组成的。

    理解Shader代码

    文章剩下的部分将讲述上面那段简单代码到底做了什么?真正的干货马上就来了,你必须好好掌握这些内容。

    当你进行shader编程时,你必须使用正确的变量名和函数名来调用它们,事实上变量的名称在某些情况下能让人一眼看出它的特定含义。

    创建并使用默认Shader

    (译者注:在详细介绍Shader之前,我们先简单介绍下shader如何使用。)

    1. 我们先打开Unity(我的版本是4.6.1),创建新工程,并在Assets文件夹下创建三个目录,如下:

    技术分享

    2. 我们再创建一个cube。

    技术分享

    可以在Inspector面板看到新创建的cube所使用的Material如下。

    技术分享

    3. 打开Material文件夹,我们在其中创建一个Shader和一个Material。

    技术分享

    此时New Material的默认Shader为Diffuse。

    技术分享

    我们将NewShader拖到New Material上。

    技术分享

    可以看到该材质所使用的Shader变成我们新建的NewShader了。当然你也可以直接点击材质编辑器中Shader下拉框,选择相应的Shader。

    4. 最后将New Material拖到cube上。可以看到cube所使用的材质和Shader都变成了我们新创建的材质和Shader了。

    技术分享

    Properties(属性值)简介

    你在shader代码中的Properties{…}部分定义Shader中的属性值(属性值就是用户传入给shader的数据,比如纹理之类的,然后shader处理这些纹理,产生特效。可以理解为属性值相当于一种全局变量,而Shader就是那个主函数,Unity的优势在于给这个全局变量赋值可以在Inspector面板进行)。注意Properties(属性值)是所有Subshader代码中的共享的,意味着所有SubShader代码中都可以使用这些属性值。

    属性值(property)定义的形式:

    _Name(“Displayed Name”,type) = default value[{options}]

    • _Name 属性值的名称,是在shader代码内部使用的,区别于下面的Displayed Name,后者是在Inspector 面板上显示的,作为外界(用户)的输入提示。
    • Displayed Name 呈现在材质编辑器中的属性值名称,在Inspector面板上显示。

    总结:打开我们创建的NewShader。可以看到_MainTex是在代码中使用的,而Base (RGB)是在材质编辑器中使用的

    技术分享

    • type 属性值的类型,包括:
      • Color – 表示纯色,使用了RGBA表示法
      • 2D – 代表尺寸为2的幂次的纹理(如2,4,8,16…256,512)
      • Rect – 代表纹理(texture),不同于上面的纹理,此处纹理的大小不一定是2的幂次。
      • Cube – 用于3d中的cube map,经常提到的天空盒就是使用了cube map。
      • Range(min, max) – 在min和max之间的一个值,在面板中可用滑动条改变其值大小。
      • Float – 任意一浮点数。
      • Vector – 4维向量值,本质就是4个浮点数组成的类型。

    来张全家福:

    技术分享

    技术分享

    • default value 属性值的初始值,就相当于你的变量初始化的那个值。
      • Color – (red,green,blue,alpha) 使用了RGBA这种格式的颜色,alpha指的是透明度– 比如 (1,1,1,1)
      • 2D/Rect/Cube – 纹理的类型,上面已经介绍过了。初始化值可以使一个空字符串,或者"white", "black", "gray", "bump"(说明此纹理是一个凹凸纹理)
      • Float/Range – 这个没啥说的,跟浮点数初始化一样一样的
      • Vector – 4维向量,其中4个数均为浮点数 (x,y,z,w)
    • { options } 这里注意了,{options} 仅仅用于纹理类型,比如上面提到的2D,Rect,Cube,对于这些类型,如果没有options可填,至少要写一个空的{},否则编译出错。可以使用空格将多个options(选项)分开 ,可用的options(选项)如下:
      •  TexGen texgenmode:纹理坐标自动生成的方式。可以是ObjectLinear, EyeLinear, SphereMap, CubeReflect,CubeNormal其中之一,这些方式和OpenGL中的纹理坐标生成方式相对应,具体详见这篇博文。注意当你写Vertex Function时,纹理坐标产生方式将被忽略。

    下面举几个属性值写法的例子:

    // 定义了一个半透明(alpha=0.5)效果的红色作为默认颜色值
    
    _MainColor(“Main Color”,Color)=(1,0,0,0.5)
    
    // 定义了一个默认值为白色的纹理
    
    _Texture(“Texture”,2D) =”white” {}

    注意属性值的定义末尾处不需添加分号。

    标签(Tags)

    你的表面着色器可以用一个或多个标签(tags)进行修饰。这些标签的作用是告诉硬件何时去调用你的shader代码。

    在我们的例子中,我们使用:Tags {“RenderType” = “Opaque”},这意味着当程序去渲染不透明的几何体时,将调用我们的shader,Unity定义了一系列这样的渲染过程。另一个很容易理解的标签就是Tags {“RenderType” = “Transparent”},意味着我们的shader只会输出半透明或透明的像素值。

    其它一些有用的标签,比如“IgnoreProjector”=“True”,意味着你渲染的物体不会受到projectors(投影仪)的影响。

    “Queue”=“xxxx”(给shader所属的对象贴上渲染队列的标签)。当渲染的对象类型是透明物体时,Queue标签能产生一些非常有趣的效果。该标签决定了物体渲染的顺序(译者注:我猜测它的工作方式是这样的,一个场景中有很多个物体,当这些物体被渲染时,必须有一个渲染的顺序,比如背景应该比其他物体先渲染出来,否则背景会将之前渲染的物体遮挡住,具体方法是将背景使用的shader中贴上一个“Queue”=“Backfround”标签,这样使用该shader的物体将被贴上Background的标签。总之当渲染整个场景时,unity会根据这些渲染队列的标签决定按什么顺序去渲染对应标签所属的物体)。

    • Background – 在所有其他物体渲染之前渲染,被用于天空盒或类似的背景效果。
    • Geometry(默认tags为geometry) – 适用于大多数物体。非透明物体使用这种渲染顺序。
    • AlphaTest – 顺利通过alpha测试的像素(alpha-test是指当前像素的alpha小于一定的值就舍弃该像素)使用该渲染顺序。单独设置该渲染顺序是因为在所有实体渲染过后,该渲染顺序将对渲染经过alpha测试的物体更有效率。
    • Transparent – 该渲染标签所属的物体将在标签为Geometry和AlphaTest之后的物体渲染,并且这些贴着Transparent的所有物体本身是从后往前依次渲染的。任何经过alpha-blended的物体都应该使用该标签(译者注:alpha-blended是指使用当前像素的alpha作为混合因子,来混合之前写入到缓存中像素值,此时注意shader是不能写入深度缓存的,因为如果不关闭写入深度缓存,那么在进行深度检测的时候,它背后的物体本来我们是可以透过它被我们看到的,但由于深度检测时,小于它的深度就被剔除了,从而我们就看不到它后面的物体了),玻璃和粒子效果比较适合该渲染标签。
    • Overlay – 该渲染标签适合覆盖效果,任何最后渲染的效果都可以使用该标签,比如透镜光晕。

    有趣的是你可以给这些基本的渲染标签进行加加减减。这些预定义的值本质上是一组定义整数,Background = 1000, Geometry = 2000, AlphaTest = 2450, Transparent = 3000,最后Overlay = 4000。(译者注:从此处我们也可以一窥究竟,貌似数值大的后渲染。)这些预设值这对透明物体有很大影响,比如一个湖水的平面覆盖了你用广告牌制作的树,你可以对你的树使用“Queue”=”Transparent-102”,这样你的树就会绘制在湖水前面了。

    Shader的整体结构

    让我们回顾下shader代码的结构。

    技术分享

    #pragma surface surf Lambert 这段代码表示其中surface表示这是一个表面着色器,进行结果输出的函数名称为surf,其使用的光照模型为Lambert光照模型。

    我们的CG程序使用了一种经过修饰的类C语言 —— CG语言(是Nvidia和微软共同出品的一种shader语言)。详见Nvidia的文档 —— 我在文中也会介绍一些基本的Cg使用方法。

    浮点数类型(float)和向量值类型(vec)一般都会在末尾加上2,3,4这些数字(float2,float4,vec3…)表示该类型具体有几个元素组成。这种定义方式使数值操作变得更方便,你可以将其当做一个整体使用,或者单独使用其分量。

    //定义一个浮点类型的二维坐标
    
    vec2 coordinate;
    
    //定义一个颜色变量(4个浮点值分量的颜色值)
    
    float4 color;
    
    //通过点乘得到3个浮点值分量的颜色值
    
    float3 multipliedColor = color.rgb * coordinate.x;

    你可以使用.xyzw或.rgba来表明你使用的变量类型具体的含义,比如.xyzw可能表示的是旋转四元数,而.xyz表示位置或法向量,.rgba表示颜色。当然,你可以仅仅使用float作为单个浮点值类型。其实对.rgba等分量访问符的使用也称作swizzle,尤其是对颜色的处理,比如颜色空间的转换可能会用到它,比如color=color.abgr;

    你将会遇到half(半精度)和double(双精度)类型,half(一般16bit)即正常float(一般32bit)的一半精度,double(一般64bit)是正常float的两倍精度(此处的倍数衡量的方式不是指表示的范围,而是表示可以使用的bit位数)。使用half经常是出于性能考虑的原因。还有一种区别于浮点数的定点数fixed,精度更低。

    当你想将颜色值规范到0~1之间时,你可能会想到使用saturate函数(saturate(x)的作用是如果x取值小于0,则返回值为0。如果x取值大于1,则返回值为1。若x在0到1之间,则直接返回x的值.),当然saturate也可以使用变量的swizzled版本,比如saturate(somecolor.rgb);

    你可以使用length函数得到一个向量的长度,比如float size = length(someVec4.xz);

    如何从表面着色器输出信息

    我们的surface function(表面函数)每个像素调用一次,系统已经事先计算出当前处理的像素的输入值(准确来说应该是输入结构体,即Input IN中的Input类型)。 它是根据每个网格上的面片,并进行插值得到的结果。

    来看看我们的surf函数

    void surf (Input IN, inout SurfaceOutput o) {
    
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    
    }

    很明显我们可以看出,我们返回了o.Albeodo值 – 该值是Unity为我们定义的SurfaceOutput结构体中的某个成员。接下来让我们看看SurfaceOutput具体定义了哪些成员。该Albedo表示像素的颜色。

    struct SurfaceOutput {
    
        half3 Albedo; //该像素的颜色值
    
        half3 Normal; //该像素的法向量
    
        half3 Emission; //该像素的辐射光,辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响
    
        half Specular; //该像素的镜面高光
    
        half Gloss; //该像素的发光强度
    
        half Alpha; //该像素的透明度
    
    };

    你只要将该结构体中值交给Unity,Unity会自动根据这些值产生最终效果,而不需要你关心其中的细节。

    我答应你们的干货就在下面

    首先看看作为我们surf函数的输入是啥?

    我们定义了一个输入结构体如下:

    struct Input {
    
        float2 uv_MainTex;
    
    };

    通过简单地创建结构体,我们告诉系统当我们每次调用surf函数时,获取MainTex在该像素的纹理坐标。如果我们有第二个纹理叫做—_OtherTexture,我们可以通过在输入结构体中添加下面代码得到它的纹理坐标

    struct Input {
    
        float2 uv_MainTex;
    
        float2 uv_OtherTexture;
    
    };

    如果对于其他纹理,我们有第二套纹理坐标,我们可以这样做:

    struct Input {
    
        float2 uv_MainTex;
    
        float2 uv2_OtherTexture;
    
    };

    此时对于我们所使用的所有纹理,我们的输入结构体包含一套uv坐标或者一套uv2坐标。

    如果我们的shader很复杂并且需要知道像素的其他相关信息,我们就可以将以下变量包含在输入结构体中,以此来查询其他的相关变量。

    • float3 viewDir – 视图方向( view direction)值。为了计算视差效果(Parallax effects),边缘光照(rim lighting)等,需要包含视图方向(view direction)值。
    • float4  with COLOR semantic(比如float4 currentColor,即用户自定义和颜色相关的变量名称) – 每个顶点(per-vertex)颜色的插值。
    • float4 screenPos – 为了反射效果,需要包含屏幕空间中的位置信息
    • float3 worldPos – 世界空间中的位置
    • float3 worldRefl – 世界空间中的反射向量。如果表面着色器(surface shader) 不为SurfaceOutput结构中的Normal赋值,将包含这个参数。
    • float3 worldNormal – 世界空间中的法线向量(normal vector)。如果表面着色器(surface shader) 不为SurfaceOutput结构中的Normal赋值,将包含这个参数。
    • INTERNAL_DATA – 相对于上面的float3 worldRefl和float3 worldNormal,如果表面着色器为SurfaceOutput结构中的Normal赋值了,将使用该参数。为了获得基于每个顶点法线贴图( per-pixel normal map)的反射向量(reflection vector)需要使用世界反射向量(WorldReflectionVector (IN, o.Normal)),其中o.Normal表示的是切空间的法向量,而非世界坐标系下的法向量。
    • 你可能会问上面的COLOR semantic是什么意思?当你写一个正常的片段着色器时,你得告诉别人你的输入结构体每个变量代表什么意思?如果你够疯狂,你可以试试下面这样定义:float2 MyUncleFred : TEXCOORD0; 并告诉别人MyUncleFred表示该模型的uv坐标。(画外音就是这种变量命名方式很令人费解)在表面着色器中你唯一担心的就是对COLOR类型的定义。float4 currentColor : COLOR;可以看做目前已经经过插值后的像素颜色。当然你也可以不用关心这些,不过建议你命名上最好规范些,方便自己也方便别人。

    该shader实际做了哪些事?

    现在我们还有两行代码没有详细讨论:

    Sampler2D _MainTex;

    对每一个属性值,我们定义了属性值区域(Properties Section),该区域用来定义CG程序中使用的变量。在使用中,我们必须保证属性名称一致。

    技术分享

    注意输入结构体中的uv_MainTex是uv+对应属性值(文中为_MainTex,注意前面带下划线是CG官方推荐的写法),如果你使用uv2,那将写作uv2_MainTex。注意Sampler2D _MainTex中的_MainTex变量是一个Sampler2D(这个Sampler2D,可以理解为引用一个2D Texture),它引用了Properties中的_MainTex(译者注:注意两者同名。解释通了sampler2D是什么之后,还需要解释下为什么在这里需要一句对_MainTex的声明,之前我们不是已经在Properties里声明过它是贴图了么。答案是我们用来实例的这个shader其实是由两个相对独立的块组成的,外层的属性声明,回滚等等是Unity可以直接使用和编译的ShaderLab;而现在我们是在CGPROGRAM...ENDCG这样一个代码块中,这是一段CG程序。对于这段CG程序,要想访问在Properties中所定义的变量的话,必须使用和之前变量相同的名字进行声明。于是其实sampler2D _MainTex;做的事情就是再次声明并链接了_MainTex,使得接下来的CG程序能够使用这个变量。),他可以根据指定的uv坐标来提供对应纹理上的像素值,而此处uv_MainTex的作用就是提供纹理_MainTex的uv坐标值。

    如果我们定义了一个_Color变量,我们可以定义它的属性为

    float4 _Color;

    我们surf函数中唯一一行代码

    o.Albedo = tex2d( _MainTex, IN.uv_MainTex).rgb;

    tex2d的作用是利用IN.uv_MainTex所代表的uv坐标(注意我们上面指定了uv坐标产生的方式,所以此处的IN.uv_MainTex是自动生成的)对纹理_MainTex进行采样。此处,对于o.Albedo我们只取颜色分量中的rgb三分量,其中alpha值(透明度)目前不需要,至少对于非透明物体alpha值得作用不大。

    如果你要设置alpha值的话,可以像下面这样赋值

    float4 texColor = tex2d( _MainTex, IN.uv_MainTex );
    
    o.Albedo = texColor.rgb;
    
    o.Alpha = texColor.a;

    总结

    你已经了解了很多的术语,但是目前我们所写的shader还相当有限,但是当学习完第二部分教程后,我们就可以做一些很酷炫的shader了,因为第二部分我们将开始使用多重纹理,法向量等等酷炫技术。

    • 在第二部分中,我们创建了一个实现积雪效果的shader,根据积雪的程度来修改模型,以呈现不同效果。
    • 在第三部分我们改进了我们的shader来混合岩石边缘的积雪。
    • 在第四部分,我们使用黑色边缘和渐变纹理来创建了具有卡通效果的shader。
    • 在第五部分,我们创建了一个顶点/片段多通道凹凸纹理着色器(vertex/fragment multipass bumped shader) – 其复杂程度远远超越表面着色器
    • 在第六部分,我们创建了一个顶点/片段着色器(vertex/fragment shader)来制作相比于我们第四部分使用表面着色器制作的卡通效果shader更好的shader。
    展开全文
  • Unity3D一个全面整合的专业游戏引擎

    千次阅读 2018-09-07 09:10:54
    Unity3d:https://unity3d.com/cn 参考百度百科:https://baike.baidu.com/item/Unity3D/3064002?fromtitle=Unity&amp;fromid=10793&amp;fr=aladdin Unity3D是由Unity Technologies开发的一个让玩家轻松创建...

    Unity3d:https://unity3d.com/cn

    参考百度百科:https://baike.baidu.com/item/Unity3D/3064002?fromtitle=Unity&fromid=10793&fr=aladdin

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。Unity类似于Director,Blender game engine, Virtools 或 Torque Game Builder等利用交互的图型化开发环境为首要方式的软件。其编辑器运行在Windows 和Mac OS X下,可发布游戏至WindowsMacWiiiPhoneWebGL(需要HTML5)、Windows phone 8和Android平台。也可以利用Unity web player插件发布网页游戏,支持Mac和Windows的网页浏览。它的网页播放器也被Mac 所支持。

    软件版本介绍

    Windows版本:Unity3d 2018.2

    Mac版本:Unity3d 2018.2

    大陆发布版本

    Unity3D PRO虚拟现实、跨平台应用程序开发引擎(商业版)

    unity3d 4.0版本 unity3d 4.0版本

    Unity iOS Pro移动终端发布平台

    Unity3D PRO 虚拟现实、跨平台应用程序开发引擎(教育版)

    2012年11月15日,Unity Technologies公司正式推出Unity 4.0版本,新加入对于DriectX 11的支持和Mecanim动画工具,以及为用户提供Linux及Adobe Flash Player的部署预览功能。

    目前Unity5已经推出。

    Unity是免费的,官方为Unity Pro和Unity iOS Pro提供30天全功能试用期。

    你可以使用C#和JS快速上手它。

    相关新闻

    研讨会

    PC、MAC、iPhone、ipad、PS和Xbox360等众多平台的引擎效能成为了业界关心的焦点问题,而Unity3D游戏引擎技术研讨会在中国的召开,无疑吸引了各家厂商的目光。在上海

    举行的本届研讨会,由韩国国民大学游戏教育学院和中国东华大学联合举办。大会不仅是对Unity3D游戏引擎技术的介绍,更通过此次会议提升中国先进游戏技术的开发能力,培养后备研发人员。

    Unity3D游戏引擎技术研讨会最早于2010年5月在韩国举行。据悉,十种以上的新引擎开发,都是采用了Unity3D游戏引擎技术。部分开发商利用2010年ChinaJoy展会之机,也展示了该引擎的运行效果。已有不少厂商同开发商签订了提前的引擎预定协议。

    Unity引擎宣布放弃支持Flash平台

    相信很多独立游戏以及移动游戏开发者都不会对Unity引擎感到陌生。2013年4月25日Unity公司CEO David Helgason发布消息称,游戏引擎Unity今后将不再支持Flash平台,且于今天起不再销售针对Flash开发者的软件授权。

    Unity全球领袖齐聚Unite Keynote

    Unity3D

    Unity3D(5张)

    2016年4月11日,本年度的Unite Keynote将重装开启,正式拉开Unite大会的序幕,本次Unite Keynote,Unity CEO John Riccitiello首次来到中国Unite,Unity创始人David Helgason也会同台出席并发表主题演讲。而上海的Unite Keynote也将成为John在亚太地区唯一出席的Unite大会,足以见其对中国市场的重视程度。 [1] 

    如何学习

    第一步首先了解unity3d的菜单,视图界面。 [2]  这些是最基本的基础,可以像学word操作一样,大致能明白有几个菜单,几个基本的视图,各自起什么作用的就可以了。当然还要了解人物基本的比例和结构。

    Unity3d代码 Unity3d代码

    第二步理解场景里面的坐标系统,输入系统,简单的向量概念。Unity3D的坐标系统及向量概念如果不理解清楚,不理解世界坐标,局部坐标的关系,即使一个简单的移动,缩放,旋转的几行代码,也会困惑你半天。

    第三步学习创建基本的场景的一些基本概念:游戏对象,组件,脚本。在界面上分别体现在层次视图,项目视图及属性视图,要理清楚彼此之间的关系

    第四步学习资源导入方面的一些基本元素:网格,材质,贴图,动画等。

    第五步学习脚本的生命周期,Start,UpDate,ONGUI这些基本的方法。了解,预制,时间,数学等常用的类及相关方法。理解游戏对象,组件,脚本彼此之间的关系。

    第六步进一步学习摄像机灯光,地形,渲染,粒子系统,物理系统等等,这些每一个深入进去都是一个很复杂的主题。

    第七步一些更高级的概念:向量的加减法点乘叉乘,光照法线贴图,内存管理,图形优化等等。Unity3D入门容易,真的要精通,那是相当难的。

    常见问题

    1:天空盒有接缝怎么解决?

    答:在贴图导入设置里设置Wrap Mode为"Clamp"。

    2:DDS格式怎么不显示?

    答:Unity不支持DDS格式,Unity会将除DDS外的其他格式图片具有为DDS同样的优化。

    3:Unity如何动态载入外部模型等文件?

    答:可以使用AssetBundle。

    4:脚本编辑器有语法提示吗?

    答:有的,Win版使用Ctrl+I,Mac版使用Ctrl+>。

    5:如何使用烘焙贴图(多重纹理)?

    答:不要使用Shell贴图,直接将烘焙图赋予贴图的"自发光"通道之上。

    6:怎么屏蔽Webplayer右键菜单?

    答:<param name="disableContextMenu" value="true" />

    7:为什么水面没有实时反射效果?

    答:只有专业版才支持这种反射效果。

    8:怎么做摄像机漫游动画?

    答:Max正常制作摄像机漫游动画,导到Unity中后,将Unity的Camea拖拽到Max导出的摄像机Gameobject物体之上,作为其子物体即可。

    9:如何自定义Webplayer载入Logo及进度条?

    答:<param name="logoimage" value="Logo文件名" />,<param name="progressbarimage" value="进度条名" />,<param name="progressframeimage" value="进度条外框名" />。

    10:GUI上怎么使用中文字?

    答:导入任意中文字体,然后定义GUISkin字体为该字体即可。

    11:购买一个授权可以安装几台电脑?

    答:可以安装于2个系统之上比如一个Win版一个Mac版。

    12:Max文件扔到Unity中怎么说导入失败?

    答:下载最新版Fbx插件,用Max导出Fbx文件然后扔Unity中。

    13:如何不让摄像头穿透模型,离模型近了就像模型露面了?

    答:设置相机的Near clip plane,调小一点,但是不要给负数。

    14:怎么用双面贴图?

    答:Unity中可设置双面Shader,最简单有效的办法是直接做成双面的实体模型.复杂一点的方法可以在材质脚本中的相应的SubShader中的一个Pass块中加入cull off,即关闭反面裁剪。

    15:导入的Fbx模型尺寸小于Max中的尺寸?

    答:在Unity中该文件的导入设置中设置缩放因子为1。

    16:如何给相机添加Glow效果?

    答:选中相机对象,在菜单中选中Component-Image Effects-Glow赋予该组件即可(专业版才支持此特效)。

    17:怎么设置Webplayer默认尺寸?

    答:到菜单Edit-Project Settings-Player中设置Default Web Screen尺寸即可。

    18:怎么设置可执行文件的启动Banner?

    答:到菜单Edit-Project Settings-Player中设置Resolution Dialog Banner。

    19:如何设置雾效?

    unity

     

    unity(10张)

     

    答:到菜单Edit-Render Settings中开启Fog及设置Fog Color等即可。

    20:如何设定默认Skybox天空盒?

    答:到菜单Edit-Render Settings中设置Skybox Material即可. (欢迎加入unity3d百度唯一问答团队,参考资料)

    21:如何下载Unity3d游戏开发工具?

    Unity3D下载软件开发工具和游戏引擎套件(Unity) v4.5.5 下载Unity3d 4.5.5下载是一个让你轻松创作的多平台的游戏开发工具,是一个全面整合的专业游戏引擎综合编辑通过Unity简单的用户界面

    1. unity3d虚拟现实的设计流程?

    答:max 制作模型,导出fbx,导入unity,设计相机代码,设计ui,build 。

    22:Unity3D-实现水面渲染 [3] 

    在实现上其实有两种大体的思路来实现散射,一种是专门为海底的物体写一个shader,这个shader里包含散射的计算;另外一种是专门用一个相机来渲染海底的场景并计算散射。

    举办活动

    旧金山不眠夜 2013游戏开发者大会盛大开幕

    2013年GDC(Game Developers Conference)将于旧金山当地时间3月25日拉开序幕最早由游戏设计师Chris Crawford(克里斯·克劳福德)于1988年发起至今已举办了27届。

    游戏开发者大会(Game Developers Conference)2013年3月25日开幕,但是27-29日才正式向公众开放,这也是一直延续下来的GDC传统:游戏开发者们之间的讨论聚会。GDC上只有Unity Developer Day排满了长队,可见Unity游戏引擎的火爆程度。届时来自全世界最顶尖的游戏开发者和IT行业从业者将汇聚一堂,展示自己的最新作品,或是阐述自己关于游戏开发和互联网前景的尖端理念。

    2013年Unity亚洲开发者大会——Unite Asia

    2013年Unity全球用户已经超过150万,全新版本的Unity4.0引擎已经能够支持包括MAC OS X、安卓、IOS、Windows等在内的十个平台发布。越来越多的游戏厂商和应用软件开发工作室在使用Unity研发游戏和创造梦想。Unity引擎覆盖了越来越多的国家,而亚洲一直是Unity发展的战略重点。为了促进亚洲地区的游戏产业与文化创意产业的发展,推动网络和手机游戏多元化的进程,Unity将在中国、日本和韩国同时举办“2013Unity亚洲开发者大会“,超过十位来自世界各地的优秀的Unity开发工程师,将在亚洲的三个国家巡回演讲。这是Unity开发者的年度盛会,代表着全球Unity开发的最高水准和最高质量的技术交流。

    Unity开发者大会首次登陆上海,将举办为期两天的开发者大会,共计超过40场技术专题演讲和现场答疑。亚洲的游戏开发者无论在数量还是开发能力上越来越强大,通过这一系列的开发者大会,开发者们可以与Unity官方进行更快速和有效的沟通,可以参与最高质量的Unity技术讲座,更可以与来自世界各地的Unity开发者面对面地分享交流开发经验。

    Unite2013第一天的日程安排如下,我们会分享非常多的技术干货,包括:

    1、Shuriken粒子系统的使用技巧;

    2、Unity的内存管理,告诉你如何让你的Unity游戏不再内存泄露;

    3、如何在移动平台上优化你的3D游戏,告诉你开发3D移动游戏时需要注意的方方面面;

    4、Unity导航网格的使用技巧和疑难杂症解析。

    Unite2013第二天的日程安排如下,主要包括:

    1、Unity的主流GUI解决方案解析,包括NGUI、UniSWF和Scaleform等;

    2、Unity的渲染pipeline技术分享;

    3、Mecanim的系统深入解析和最新特性;

    4、使用Unity开发网页游戏时你需要注意的方方面面;

    5、Assetbundle原理和使用技巧,告诉你如何获得最优的打包效果。

    相关游戏

    网页游戏

    客户端游戏

    手机游戏

    单机游戏

    培训和认证

    认证考试

    Unity Certified User应用能力认证

    考试时间:1小时(50题)
      适合多媒体专业,3D专业,游戏专业,美术专业的学生及Unity初学者。证明您已经拥有Unity引擎的基础知识。

    Unity Certified Professional专业能力认证

    考试时间:1小时(50题)
      熟悉C#或JavaScript的开发者,证明您已经拥有Unity引擎的专业知识,能够依照业界的开发需求来制作专案。

    报名流程

    立即填写报名信息

    收到信息后,会第一时间联系通知

    报名交费

    通知并发放准考证

    考试地点

    北京、上海、香港、杭州、南京、苏州、广州、深圳、成都、台北、新竹、台南、高雄

    适应它团队协作

    Unity没有提供编辑器内的团队协作。

    推荐方案1

    可以客户端,美术,模型等都分别建的项目,然后各自用SVN上传、更新。美术的话只管把UI做好上传就行了,然后客户端这边更新好UI自己再在客户端进行处理,有什么不合适的和美术沟通就行了。

    推荐方案2

    版本管理优先选用AssetServer。Git和SVN什么的也挺好,前提是要培训所有成员正确使用。

    如果项目比较大,建议拆分为2~3个项目:

    AssetsProject:主要存放模型、特效等美术素材。也放一些测试脚本,以便测试美术素材能正确配合脚本运行。

    DataProject:存放策划的数值、关卡编辑器等等。也要放一些测试脚本,以便关卡能跑起来。

    ScriptsProject:程序员专门维护的项目。主要用于逻辑开发,存放部分的美术资源。

    FinalProject: 最终合并的项目。

    开发过程中,视具体情况,上述项目某两个可以合并。

    这样拆分项目肯定会导致额外的工作量,会有冗余的脚本,而且到时候合并也是个问题。这些都是无法避免的。所以前期一定要定好标准。

    展开全文
  • 之前我使用的是unity 3D 2017.3.0 ,jdk是10.0.1,SDK下载了一个安卓9,一个安卓7,但是在打包过程中,会遇见一个问题 提示不能Gradle打包 ,但是换成interal 后就成了不能打包,后来我把JDK 版本降低,用了jdk8,这...

    unity 3D 打包过程中  我遇见了好多问题 简直能把人气死。之前我使用的是unity 3D 2017.3.0  ,jdk是10.0.1,SDK下载了一个安卓9,一个安卓7,但是在打包过程中,会遇见一个问题 提示不能Gradle打包 ,但是换成interal 后就成了不能打包,后来我把JDK 版本降低,用了jdk8,这个问题就解决了。

    另外 在下载SDK的时候,SDK manager会出现闪退的情况,这个时候,可以把android.bat脚本寻找Java.exe 改为它的绝对路径,注意,此时的绝对路径不能含或空格

    展开全文
  • Unity3D Shader 新手教程(1/6)

    千次阅读 2016-11-10 15:59:54
    刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步。该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D中的表面着色器...
  • Unity3D游戏-愤怒的小鸟游戏源码和教程(一) Unity愤怒的小鸟游戏教程 本文提供全流程,中文翻译。Chinar坚持将简单的生活方式,带给世人! Spring Joint 2D : 是Unity提供的一个弹簧关节组件,可通过AddComponent...
  • ubuntu unity 3D桌面效果

    万次阅读 2017-09-14 11:25:33
    不 推荐在Ubuntu 12.10版使用3D桌面特效,因为这个版本正在做较大的修改和测试,把 Unity 2D桌面取消了,这是为了在以后“统一”桌面做准备,所以在Ubuntu 12.10版中使用带3D特效的Unity桌面或者另行安装使用Gnome-...
  • unity3D游戏开发十二之疯狂的小球

    万次阅读 2014-04-12 03:28:11
    该实例通过第三人称视角控制游戏中的小球对象,游戏通过是否与钻石碰撞来界定是否寻找到钻石并获得积分,获得积分满10分后,赢得游戏,当小球冲出跑道时,游戏失败,并提示是否重新开始游戏。 依次打开文件夹...
  • 这个听起来好像很容易实现,后来想了一下很多操作都是在Unity里面进行的,使用batch脚本好像不是那么容易实现。 后来查询官方文档才发现Unity 给了命令行启动的链接。其中最重要的不是启动的链接,而是他给出的一...
  • 欢迎来到unity学习、unity培训、unity企业培训教育专区,这里有很多U3D资源、U3D培训视频、U3D教程、U3D常见问题、U3D项目源码,我们致力于打造业内unity3d培训、学习第一品牌。    昨天把GUI做了点出来,攻击之...
  • unity3d简介

    千次阅读 2015-01-01 14:39:56
    Unity3D编辑 [1] Unity是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。Unity...
  • 随笔 - 39 文章 - 0 评论 - 150本文为翻译,...刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步。该系列教程的第一篇文章(译者注:即本文,后续还...
  • 开发过程 遇到天坑:纯android工程没...unity3d 中调android的HttpURLConnection 必须把整个请求放在Thread中,不过本文打好的renren.jar已解决此问题(要用人人sdk源码封sdk的童鞋们注意更改以下函数)  static ...
  • 【译】Unity3D Shader 新手教程(1/6)

    千次阅读 2015-07-20 12:47:04
    刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步。该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D中的表面着色器...
  • 杂项:Unity3D

    2019-07-31 03:25:12
    ylbtech-杂项:Unity3D Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。...
  • Unity3D 最简单的优化建议

    千次阅读 2017-11-03 10:55:06
    最简单的优化建议: 1.PC平台的话保持场景中显示的顶点数少于200K~3M,移动设备的话少于10W,一切取决于你的目标GPU与CPU。 2.如果你用U3D自带的SHADER,在表现不差的情况下选择Mobile或Unlit目录下的。...
  • Unity3D游戏教程】记忆翻牌游戏

    千次阅读 热门讨论 2017-03-03 12:27:03
    趣味十足的记忆翻牌小游戏的开发教程~
  • 刚开始接触Unity3D Shader编程时,你会发现有关shader的文档相当散,这也造成初学者对Unity3D Shader编程望而却步。该系列教程的第一篇文章(译者注:即本文,后续还有5篇文章)详细介绍了Unity3D中的表面着色器
1 2 3 4 5 ... 10
收藏数 193
精华内容 77
关键字:

unity3d 信息提示狂