标签:
 
 
 
本系列文章由@浅墨_毛星云 出品,转载请注明出处。  
 文章链接: http://blog.csdn.net/poem_qianmo/article/details/40723789
 
 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442
 邮箱: happylifemxy@163.com
 
 
-   
-   
- Shader "浅墨Shader编程/0.TheFirstShader"   
- {  
-     
-     Properties   
-     {  
-         _MainTex ("【纹理】Texture", 2D) = "white" {}  
-         _BumpMap ("【凹凸纹理】Bumpmap", 2D) = "bump" {}  
-         _RimColor ("【边缘颜色】Rim Color", Color) = (0.17,0.36,0.81,0.0)  
-         _RimPower ("【边缘颜色强度】Rim Power", Range(0.6,9.0)) = 1.0  
-     }  
-   
-     
-     SubShader   
-     {  
-         
-         Tags { "RenderType" = "Opaque" }  
-   
-         
-         CGPROGRAM  
-   
-         
-         #pragma surface surf Lambert  
-           
-         
-         struct Input   
-         {  
-             float2 uv_MainTex;
-             float2 uv_BumpMap;
-             float3 viewDir;
-         };  
-   
-         
-         sampler2D _MainTex;
-         sampler2D _BumpMap;
-         float4 _RimColor;
-         float _RimPower;
-   
-         
-         void surf (Input IN, inout SurfaceOutput o)  
-         {  
-             
-             o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;  
-             
-             o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));  
-             
-             half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));  //saturate 把输入的值限制在0到1之间
-             
-             o.Emission = _RimColor.rgb * pow (rim, _RimPower);  //pow(x,y)x的y次方
-         }  
-   
-         
-         ENDCG  
-     }   
-   
-     
-     Fallback "Diffuse"  
- }  
 
由于这是第一篇Shader系列文章,已经涉及到很多内容了,所以浅墨不可能展开讲解这段代码的具体思路和写法,不过已经详细注释,大家应该会多少有点明白。随着稍后文章的深入,这段代码就显得很简单易懂了。
拷贝完成,保存一下这段代码,unity会自动检测和编译被保存的代码,我只需返回Unity窗口,等待编译完成即可。若没有错误,在“0.TheFirstShader”的inspector面板中得到的结果应该是有红色的错误提示的。
 
需要注意的是,Shader想要使用到游戏物体上,一般得有个媒介,这个媒介就是我们的老朋友——材质(Material)。我们把Shader作用于材质,接着再把材质对应地作用于给游戏物体,这样写的Shader就间接地给物体表面使用了。
 
 
 
而这一层关系,在Unity中完全可以通过点点鼠标,拖动来完成。下面我们就来讲一讲如何将一个着色程序的结果显示到物体表面上。
 
知道以上原理了就很简单了,在“0.TheFirstShader.shader”的同一目录下创建一个Material。同样是可以通过Create下拉菜单->Material或者空白处右键->create->Material来完成。

 
为了到时候方便对应,我们将这个材质也取名为0.TheFirstShader。
 
 
接着,将0.TheFirstShader.shader拖动到0.TheFirstShader材质身上然后释放。
 
 
拖动完成后,我们单击0.TheFirstShader材质,打开他的面板,发现他已经和一开始不一样了,泛着蓝光:

 
 
还没完,接下来我们还得给这个材质添加两张纹理图片。图片浅墨也已经提前准备好了,在名为Textures01 by QianMo.unitypackage的Unity包中,同样双击这个包然后打开导入到项目中。
 
【Textures01 by QianMo.unitypackage单独下载请点我】
 
我们在Textures文件夹下找到这两张纹理,接下来做的就是将他们拖动到0.TheFirstShader材质对应的纹理区域中,如下:
 
 
 
或者点击这里的Select分别选择,操作如下:

 
 
两张纹理选择完毕后,我们的材质就准备好了,最后的结果,有点黑科技,如各种科幻游戏和电影中发光的矿石,非常炫酷:
 
 
 
 
OK,那么就只剩下最后一步了,就是在场景中创建一个物体,然后将我们做好的材质拖拽到物体身上赋给这个物体就行了。
 
菜单栏【GameObject】->【Create Other】->【Capsule】或者【Create】下拉菜单->【Capsule】来在场景中创建一个胶囊装的物体。把他拖动到和我们的第一人称摄像机【First Person Controller】很近的地方,这样方便观察,接着就可以把我们的“0.TheFirstShader”材质直接拖拽给场景中的这个胶囊,或者Hierachy面板中【Capsule】名字上就行了,操作如下图中的箭头所示:
 
 
 
 
 
经过拖拽,Capsule加上Material后的效果如下:

 
 
 
 
 
 
 
 
4.1 给使用Shader的物体加上文字说明
 
 
 
为了以后介绍多个Shader写法时能更清晰更方便,浅墨专门在QianMo’s Toolkit中做了一个可以在场景中和游戏窗口中分别显示附加给任意物体文字标签信息的工具脚本,叫做ShowObjectInfo,其详细注释的代码如下:
 
 
 
-   
-   
-   
-   
- #if UNITY_EDITOR      
-   
-   
- using UnityEngine;  
- using UnityEditor;  
- using System.Collections;  
-   
- [AddComponentMenu("浅墨‘s Toolkit v1.0/ShowObjectInfo")]  
-   
-   
- public class ShowObjectInfo : MonoBehaviour  
- {  
-   
-     
-     
-     
-     public string text="键入你自己的内容 by浅墨";
-     public Camera TargetCamera;
-     public bool ShowInfoInGamePlay = true;
-     public bool ShowInfoInSceneEditor = false;
-     private static GUIStyle style;
-   
-   
-   
-     
-     
-     
-     private static GUIStyle Style  
-     {  
-         get  
-         {  
-             if (style == null)  
-             {  
-                 
-                 style = new GUIStyle(EditorStyles.largeLabel);  
-                 
-                 style.alignment = TextAnchor.MiddleCenter;  
-                 
-                 style.normal.textColor = new Color(0.9f, 0.9f, 0.9f);  
-                 
-                 style.fontSize = 26;  
-             }  
-             return style;  
-         }  
-   
-     }  
-   
-   
-   
-   
-     
-     
-     
-     void OnGUI( )  
-     {  
-         
-         if (ShowInfoInGamePlay)  
-         {  
-             
-             
-             Ray ray = new Ray(transform.position + TargetCamera.transform.up * 6f, -TargetCamera.transform.up);  
-             
-             RaycastHit raycastHit;  
-             
-             collider.Raycast(ray, out raycastHit, Mathf.Infinity);  
-               
-             
-             float distance = (TargetCamera.transform.position - raycastHit.point).magnitude;  
-             
-             float fontSize = Mathf.Lerp(26, 12, distance / 10f);  
-             
-             Style.fontSize = (int)fontSize;  
-             
-             Vector3 worldPositon = raycastHit.point + TargetCamera.transform.up * distance * 0.03f;  
-             
-             Vector3 screenPosition = TargetCamera.WorldToScreenPoint(worldPositon);  
-             
-             if (screenPosition.z <= 0){return;}  
-             
-             screenPosition.y = Screen.height - screenPosition.y;  
-               
-             
-             Vector2 stringSize = Style.CalcSize(new GUIContent(text));  
-             
-             Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);  
-             
-             rect.center = screenPosition - Vector3.up * rect.height * 0.5f;  
-   
-   
-             
-             
-             Handles.BeginGUI();  
-             
-             GUI.color = new Color(0f, 0f, 0f, 0.8f);  
-             GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);  
-             
-             GUI.color = new Color(1, 1, 1, 0.8f);  
-             GUI.Label(rect, text, Style);  
-             
-             Handles.EndGUI();  
-         }  
-     }  
-   
-     
-     
-     
-     void OnDrawGizmos()  
-     {  
-         
-         if (ShowInfoInSceneEditor)  
-         {  
-             
-             
-             Ray ray = new Ray(transform.position + Camera.current.transform.up * 6f, -Camera.current.transform.up);  
-             
-             RaycastHit raycastHit;  
-             
-             collider.Raycast(ray, out raycastHit, Mathf.Infinity);  
-               
-             
-             float distance = (Camera.current.transform.position - raycastHit.point).magnitude;  
-             
-             float fontSize = Mathf.Lerp(26, 12, distance / 10f);  
-             
-             Style.fontSize = (int)fontSize;  
-             
-             Vector3 worldPositon = raycastHit.point + Camera.current.transform.up * distance * 0.03f;  
-             
-             Vector3 screenPosition = Camera.current.WorldToScreenPoint(worldPositon);  
-             
-             if (screenPosition.z <= 0) { return; }  
-             
-             screenPosition.y = Screen.height - screenPosition.y;  
-               
-             
-             Vector2 stringSize = Style.CalcSize(new GUIContent(text));  
-             
-             Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);  
-             
-             rect.center = screenPosition - Vector3.up * rect.height * 0.5f;  
-   
-   
-   
-             
-             
-             Handles.BeginGUI();  
-             
-             GUI.color = new Color(0f, 0f, 0f, 0.8f);  
-             GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);  
-             
-             GUI.color = new Color(1, 1, 1, 0.8f);  
-             GUI.Label(rect, text, Style);  
-             
-             Handles.EndGUI();  
-   
-         }  
-   
-     }  
-   
- }  
-   
- #endif  
 
 
 
这个脚本的用法倒是很简单,在代码的说明部分已经详细写出,在这里我们再列出一遍:
 
第一步:在Unity中拖拽此脚本到某物体之上,或在Inspector中[Add Component]->[浅墨‘s Toolkit v1.0]->[ShowObjectInfo]
第二步:在Inspector里,ShowObject Info 栏中的TargetCamera参数中选择需面向的摄像机,如Main Camera,FirstPerson Controller等
第三步:在text参数里填需要显示输出的文字。
第四步:完成。运行游戏或在场景编辑器Scene中查看显示效果。
 
 
也就是拖拽ShowObjectInfo脚本或者直接添加组件给需要附加文字的物体,然后在Inspector中输入需要显示的文字,然后选择其面对的摄像机就可以了。
 
 
 
我们将ShowObjectInfo脚本拖拽给上文中刚刚变得炫酷外形黑科技的Capsule:

 
那么他在Inspector就多了一个“ShowObject Info(Script)”组件,将该组件的Text项中填上“凹凸纹理+边缘发光效果”,TargetCamera中填上First Person Controller的子物体Main Camera:
 
 
 
最后,得到的效果就是这样:

 
 
 
 
 
 
 
 
 
 
 
 
五、总结、配套资源&最终工程下载
 
 
 
 
好了,本篇的文章到这里就大概结束了。
 
今天讲的内容还是非常多的,对于新接触Unity的朋友们来说或许还得好好消化消化,而熟悉Unity的朋友应该很快就可以看懂,或者觉得浅墨讲了一堆废话,orz。
 
这篇文章的内容说白了就非常简单,也就是新建工程,然后导入三个浅墨提前准备好的unitypackage游戏资源,点一点鼠标拖动拖动脚本,新建一个Shader,写点代码,再创建一个Material,Shader赋给这个Material,最后创建一个胶囊状Capsule,Material赋给这个Capsule,点运行查看最终效果。一切,就是这么简单。:)
 
 
本文配套的三个unitypackage打包请点击此处下载:
 
【浅墨Unity3D Shader编程】之一 配套的三个unitypackage打包下载
 
 
 
本文最终的Unity工程请点击此处下载:
 
【浅墨Unity3D Shader编程】之一 配套Unity工程
 
 
 
最后放几张最终的场景美图吧。
 
站在亭子上看世界:
 
 
 
逼真的光晕:
 
 
 
漂亮的天空:
 
 
 
 
乱真的水面:
 
 
 
蓝天和草地树木交相辉映:
 
 
 
 
OK,全文到此结束。
新的游戏编程之旅已经开启,下周一,我们不见不散。

 
shader 编程入门(一)
标签:
原文地址:http://www.cnblogs.com/lifesteven/p/5613101.html