shader 编程入门(一)

 

本系列文章由@浅墨_毛星云 出品,转载请注明出处。

文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789

作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442

邮箱: [email protected]

[cpp] view plain copy

print?

    1. //-----------------------------------------------【Shader说明】----------------------------------------------
    2. //      Shader功能:   凹凸纹理显示+自选边缘颜色和强度
    3. //     使用语言:   Shaderlab
    4. //     开发所用IDE版本:Unity4.5 06f 、Monodevelop
    5. //     2014年11月2日  Created by 浅墨
    6. //     更多内容或交流请访问浅墨的博客:http://blog.csdn.net/poem_qianmo
    7. //---------------------------------------------------------------------------------------------------------------------
    8. Shader "浅墨Shader编程/0.TheFirstShader"
    9. {
    10. //-------------------------------【属性】-----------------------------------------
    11. Properties
    12. {
    13. _MainTex ("【纹理】Texture", 2D) = "white" {}
    14. _BumpMap ("【凹凸纹理】Bumpmap", 2D) = "bump" {}
    15. _RimColor ("【边缘颜色】Rim Color", Color) = (0.17,0.36,0.81,0.0)
    16. _RimPower ("【边缘颜色强度】Rim Power", Range(0.6,9.0)) = 1.0
    17. }
    18. //----------------------------【开始一个子着色器】---------------------------
    19. SubShader
    20. {
    21. //渲染类型为Opaque,不透明
    22. Tags { "RenderType" = "Opaque" }
    23. //-------------------开始CG着色器编程语言段-----------------
    24. CGPROGRAM
    25. //使用兰伯特光照模式
    26. #pragma surface surf Lambert
    27. //输入结构
    28. struct Input
    29. {
    30. float2 uv_MainTex;//纹理贴图
    31. float2 uv_BumpMap;//法线贴图
    32. float3 viewDir;//观察方向
    33. };
    34. //变量声明
    35. sampler2D _MainTex;//主纹理
    36. sampler2D _BumpMap;//凹凸纹理
    37. float4 _RimColor;//边缘颜色
    38. float _RimPower;//边缘颜色强度
    39. //表面着色函数的编写
    40. void surf (Input IN, inout SurfaceOutput o)
    41. {
    42. //表面反射颜色为纹理颜色
    43. o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    44. //表面法线为凹凸纹理的颜色
    45. o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
    46. //边缘颜色
    47. half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));  //saturate 把输入的值限制在0到1之间
    48. //边缘颜色强度
    49. o.Emission = _RimColor.rgb * pow (rim, _RimPower);  //pow(x,y)x的y次方
    50. }
    51. //-------------------结束CG着色器编程语言段------------------
    52. ENDCG
    53. }
    54. //“备胎”为普通漫反射
    55. Fallback "Diffuse"
    56. }

由于这是第一篇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,其详细注释的代码如下:

[csharp] view plain copy

print?

  1. //-----------------------------------------------【脚本说明】-------------------------------------------------------
  2. //      脚本功能:    在场景中和游戏窗口中分别显示给任意物体附加的文字标签信息
  3. //      使用语言:   C#
  4. //      开发所用IDE版本:Unity4.5 06f 、Visual Studio 2010
  5. //      2014年10月 Created by 浅墨
  6. //      更多内容或交流,请访问浅墨的博客:http://blog.csdn.net/poem_qianmo
  7. //---------------------------------------------------------------------------------------------------------------------
  8. //-----------------------------------------------【使用方法】-------------------------------------------------------
  9. //      第一步:在Unity中拖拽此脚本到某物体之上,或在Inspector中[Add Component]->[浅墨‘s Toolkit v1.0]->[ShowObjectInfo]
  10. //      第二步:在Inspector里,Show Object Info 栏中的TargetCamera参数中选择需面向的摄像机,如MainCamera
  11. //      第三步:在text参数里填需要显示输出的文字。
  12. //      第四步:完成。运行游戏或在场景编辑器Scene中查看显示效果。
  13. //      PS:默认情况下文本信息仅在游戏运行时显示。
  14. //      若需要在场景编辑时在Scene中显示,请勾选Show Object Info 栏中的[Show Info In Scene Editor]参数。
  15. //      同理,勾选[Show Info In Game Play]参数也可以控制是否在游戏运行时显示文本信息
  16. //---------------------------------------------------------------------------------------------------------------------
  17. //预编译指令,检测到UNITY_EDITOR的定义,则编译后续代码
  18. #if UNITY_EDITOR
  19. //------------------------------------------【命名空间包含部分】----------------------------------------------------
  20. //  说明:命名空间包含
  21. //----------------------------------------------------------------------------------------------------------------------
  22. using UnityEngine;
  23. using UnityEditor;
  24. using System.Collections;
  25. //添加组件菜单
  26. [AddComponentMenu("浅墨‘s Toolkit v1.0/ShowObjectInfo")]
  27. //开始ShowObjectInfo类
  28. public class ShowObjectInfo : MonoBehaviour
  29. {
  30. //------------------------------------------【变量声明部分】----------------------------------------------------
  31. //  说明:变量声明部分
  32. //------------------------------------------------------------------------------------------------------------------
  33. public string text="键入你自己的内容 by浅墨";//文本内容
  34. public Camera TargetCamera;//面对的摄像机
  35. public bool ShowInfoInGamePlay = true;//是否在游戏运行时显示此信息框的标识符
  36. public bool ShowInfoInSceneEditor = false;//是否在场景编辑时显示此信息框的标识符
  37. private static GUIStyle style;//GUI风格
  38. //------------------------------------------【GUI 风格的设置】--------------------------------------------------
  39. //  说明:设定GUI风格
  40. //------------------------------------------------------------------------------------------------------------------
  41. private static GUIStyle Style
  42. {
  43. get
  44. {
  45. if (style == null)
  46. {
  47. //新建一个largeLabel的GUI风格
  48. style = new GUIStyle(EditorStyles.largeLabel);
  49. //设置文本居中对齐
  50. style.alignment = TextAnchor.MiddleCenter;
  51. //设置GUI的文本颜色
  52. style.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
  53. //设置GUI的文本字体大小
  54. style.fontSize = 26;
  55. }
  56. return style;
  57. }
  58. }
  59. //-----------------------------------------【OnGUI()函数】-----------------------------------------------------
  60. // 说明:游戏运行时GUI的显示
  61. //------------------------------------------------------------------------------------------------------------------
  62. void OnGUI( )
  63. {
  64. //ShowInfoInGamePlay为真时,才进行绘制
  65. if (ShowInfoInGamePlay)
  66. {
  67. //---------------------------------【1.光线投射判断&计算位置坐标】-------------------------------
  68. //定义一条射线
  69. Ray ray = new Ray(transform.position + TargetCamera.transform.up * 6f, -TargetCamera.transform.up);
  70. //定义光线投射碰撞
  71. RaycastHit raycastHit;
  72. //进行光线投射操作,第一个参数为光线的开始点和方向,第二个参数为光线碰撞器碰到哪里的输出信息,第三个参数为光线的长度
  73. collider.Raycast(ray, out raycastHit, Mathf.Infinity);
  74. //计算距离,为当前摄像机位置减去碰撞位置的长度
  75. float distance = (TargetCamera.transform.position - raycastHit.point).magnitude;
  76. //设置字体大小,在26到12之间插值
  77. float fontSize = Mathf.Lerp(26, 12, distance / 10f);
  78. //将得到的字体大小赋给Style.fontSize
  79. Style.fontSize = (int)fontSize;
  80. //将文字位置取为得到的光线碰撞位置上方一点
  81. Vector3 worldPositon = raycastHit.point + TargetCamera.transform.up * distance * 0.03f;
  82. //世界坐标转屏幕坐标
  83. Vector3 screenPosition = TargetCamera.WorldToScreenPoint(worldPositon);
  84. //z坐标值的判断,z值小于零就返回
  85. if (screenPosition.z <= 0){return;}
  86. //翻转Y坐标值
  87. screenPosition.y = Screen.height - screenPosition.y;
  88. //获取文本尺寸
  89. Vector2 stringSize = Style.CalcSize(new GUIContent(text));
  90. //计算文本框坐标
  91. Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);
  92. //设定文本框中心坐标
  93. rect.center = screenPosition - Vector3.up * rect.height * 0.5f;
  94. //----------------------------------【2.GUI绘制】---------------------------------------------
  95. //开始绘制一个简单的文本框
  96. Handles.BeginGUI();
  97. //绘制灰底背景
  98. GUI.color = new Color(0f, 0f, 0f, 0.8f);
  99. GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
  100. //绘制文字
  101. GUI.color = new Color(1, 1, 1, 0.8f);
  102. GUI.Label(rect, text, Style);
  103. //结束绘制
  104. Handles.EndGUI();
  105. }
  106. }
  107. //-------------------------------------【OnDrawGizmos()函数】---------------------------------------------
  108. // 说明:场景编辑器中GUI的显示
  109. //------------------------------------------------------------------------------------------------------------------
  110. void OnDrawGizmos()
  111. {
  112. //ShowInfoInSeneEditor为真时,才进行绘制
  113. if (ShowInfoInSceneEditor)
  114. {
  115. //----------------------------------------【1.光线投射判断&计算位置坐标】----------------------------------
  116. //定义一条射线
  117. Ray ray = new Ray(transform.position + Camera.current.transform.up * 6f, -Camera.current.transform.up);
  118. //定义光线投射碰撞
  119. RaycastHit raycastHit;
  120. //进行光线投射操作,第一个参数为光线的开始点和方向,第二个参数为光线碰撞器碰到哪里的输出信息,第三个参数为光线的长度
  121. collider.Raycast(ray, out raycastHit, Mathf.Infinity);
  122. //计算距离,为当前摄像机位置减去碰撞位置的长度
  123. float distance = (Camera.current.transform.position - raycastHit.point).magnitude;
  124. //设置字体大小,在26到12之间插值
  125. float fontSize = Mathf.Lerp(26, 12, distance / 10f);
  126. //将得到的字体大小赋给Style.fontSize
  127. Style.fontSize = (int)fontSize;
  128. //将文字位置取为得到的光线碰撞位置上方一点
  129. Vector3 worldPositon = raycastHit.point + Camera.current.transform.up * distance * 0.03f;
  130. //世界坐标转屏幕坐标
  131. Vector3 screenPosition = Camera.current.WorldToScreenPoint(worldPositon);
  132. //z坐标值的判断,z值小于零就返回
  133. if (screenPosition.z <= 0) { return; }
  134. //翻转Y坐标值
  135. screenPosition.y = Screen.height - screenPosition.y;
  136. //获取文本尺寸
  137. Vector2 stringSize = Style.CalcSize(new GUIContent(text));
  138. //计算文本框坐标
  139. Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);
  140. //设定文本框中心坐标
  141. rect.center = screenPosition - Vector3.up * rect.height * 0.5f;
  142. //----------------------------------【2.GUI绘制】---------------------------------------------
  143. //开始绘制一个简单的文本框
  144. Handles.BeginGUI();
  145. //绘制灰底背景
  146. GUI.color = new Color(0f, 0f, 0f, 0.8f);
  147. GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
  148. //绘制文字
  149. GUI.color = new Color(1, 1, 1, 0.8f);
  150. GUI.Label(rect, text, Style);
  151. //结束绘制
  152. Handles.EndGUI();
  153. }
  154. }
  155. }
  156. //预编译命令结束
  157. #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,全文到此结束。

新的游戏编程之旅已经开启,下周一,我们不见不散。

时间: 2024-10-11 05:45:13

shader 编程入门(一)的相关文章

Unity3D着色器Shader编程入门(一)

自学Unity3D也有大半年了,对Shader一直不敢入坑,最近看了些资料,以及通过自己的实践,对Shader还是有一点了解了,分享下仅作入门参考. 因Shader是对图像图像渲染的,学习前可以去了解下图形图像学及GPU编程相关的知识.强烈推荐<GPU 编程与CG 语言之阳春白雪下里巴人>,这本书网上有电子版. 还有一本是关于Unity3D的Shader开发的<Unity着色器和屏幕特效开发秘笈>该书是<Unity Shaders and Effects Cookbook&g

【浅墨Unity3D Shader编程】之二 雪山飞狐篇:Unity的基本Shader框架写法&amp;颜色、光照与材质

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40955607 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] 本篇文章中,我们学习了Unity Shader的基本写法框架,以及学习了Shader中Properties(属性)的详细写法,光照.材质与颜色的具体写法.写了6个Shader作为本文S

【浅墨Unity3D Shader编程】之一 游戏场景的创建 &amp; 第一个Shader的书写

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] 作为一个系统介绍Unity3D中Shader编写的系列文章的开篇,本文的第一部分系列文章的前言,然后第二部分介绍了这个系列文章中我们会使用的游戏场景创建方式,最后一部分讲解了如何在Un

【浅墨Unity3D Shader编程】之四 热带雨林篇: 剔除、深度测试、Alpha测试以及基本雾效合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1222/163.html 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] QQ交流群:330595914 更多文章尽在:http://www.hpw123.net 本文介绍了Unity中Shader书写中会用到的剔除.深度测试.Alpha测试以及基

【Unity】Shader编程 基础总结

Shader编程一直是一个比较难入门难上手的主题,本篇对Unity Shader编程的一些基础和要点进行了总结. 包括Shader编程相关知识图谱.Shader编程相关数据类型.Shader核心结构体等(后续继续补充). 每个部分相互独立,可以单独参考,亦可作为一个整体参考. 博文首发:http://blog.csdn.net/duzixi 一.Shader编程知识图谱 个人对Shader编程的理解凝在四个字:色即是光. 无论是要手写Shader程序,还是利用各类Shader制作插件(如Shad

【浅墨Unity3D Shader编程】之一 夏威夷篇:游戏场景的创建 &amp; 第一个Shader的书写

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/40723789 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 邮箱: [email protected] 作为一个系统介绍Unity3D中Shader编写的系列文章的开篇,本文的第一部分为系列文章的前言,然后第二部分介绍了这个系列文章中我们会使用的游戏场景创建方式,最后一部分讲解了如何在U

火云开发课堂 - 《Shader从入门到精通》系列 第一节:Shader介绍与工程搭建

<Shader从入门到精通>系列在线课程 第一节:Shader介绍与工程搭建 视频地址:http://edu.csdn.net/course/detail/1441/22665?auto_start=1 交流论坛:http://www.firestonegames.com/bbs/forum.php 工程下载地址:请成为正式学员获取工程 课程截图: 项目实例: 版权声明:本文为博主原创文章,未经博主允许不得转载.

《鸡啄米C++编程入门系列》系列技术文章整理收藏

<鸡啄米C++编程入门系列>系列技术文章整理收藏 收藏整理鸡啄米C++编程入门系列文章,供个人和网友学习C++时参考 1鸡啄米:C++编程入门系列之前言 2鸡啄米:C++编程入门系列之一(进制数) 3鸡啄米:C++编程入门系列之二(原码.反码与补码) 4鸡啄米:C++编程入门系列之三(VS2010的使用介绍) 5鸡啄米:C++编程入门系列之四(数据类型) 6鸡啄米:C++编程入门系列之五(运算符和表达式) 7鸡啄米:C++编程入门系列之六(算法的基本控制结构之选择结构) 8鸡啄米:C++编程入

编程入门指南

前言 如今编程成为了一个越来越重要的「技能」:作为设计师,懂一些编程可能会帮你更好地理解自己的工作内容:作为创业者,技术创始人的身份则会让你的很多工作显得更容易.而作为刚想入门的新手,面对眼前海量的信息,或许根本不知道从哪里开始:入门轻松度过初级材料的学习后,发现学习越来越困难,陡峭的学习曲线又让你望而却步:你知道如何在页面上打印输出一些文本行,但是你不知道何时该进行一个真正的有用的项目:你不清楚自己还有哪些不知道的东西,你甚至搞不清下一步该学什么. 这篇文章的内容对此不仅会有一些方向性的建议,