当前位置:首页 > Unity3D游戏开发之在3D场景中选择物体并显示轮廓效果强化版
在上一篇文章中,我们通过自定义着色器实现了一个简单的在3D游戏中选取、显示物体轮廓的实例。更多精彩请关注【狗刨学习网】在文章最后,给大家留下了一个问题,就是我们的这种方法存在一定的问题,无法运用到复杂的模型上。原因是什么呢?这要从这种方法的原理上来说,其实这种方法类似于摄像机的视角方向上对物体进行了一个投影。这样的话,如果模型被其它物体遮挡的话,就会出现渲染不完全的问题,如图所示,有一位朋友在评论中提出了这个问题。那么,怎么解决这个问题呢?对于遮挡的问题,我们一般采取的方法是拉近摄像机,因此,我们这里依然采取这种方法,即如果被渲染的物体前面有遮挡物体,则将摄像机拉近,这样就可以解决这个问题了。
那么解决了上一篇文章中的问题后,我们就来开始学习今天的内容——《Unity3D游戏开发复杂模型的选取与轮廓高亮显示》。首先,我们今天的内容是基于边缘光(RimLight)的方法来实现的,在Unity3D的官方示例中,我们可以找到这个算法,其核心算法是:
1. 2.
o.Emission = _RimColor.rgb * pow (rim, _RimPower);
复制代码
其中,IN.viewDir是当前视角向量,IN.worldNormal是物体的法线。dot是计算视角和法线的点积,等于视角和法线夹角的cos值,如下图:
由于Cos的值域是1到0,所以1-cos就成了0到1,在夹角90度时达到最大值,正好用来模拟侧光的强度(与视角成90度的部分光线最强,就是边缘光了),把这个值的变化率用一个pow函数(rim的_rimPower次方)进行放大,就能强化边缘发亮的效果。但是当物体表面比较平直时(例如立方体),由于各个面上的法向量都是一个方向上的,因此无法体现出变化和轮廓。此外,这种方法在描绘凹的几何体时,凹的部分(包括法线贴图造成的凹凸)的边缘也都会被画出来,并不是真正意义上的边缘轮廓,就是一种侧光效果。好了,下面我们开始具体地来讲通过这种方法来实现物体轮廓高光显示。首先编写Shader:
1. 2. 3. 4. 5. 6. 7. 8. 9.
_Color (\ _SpecColor (\ _Shininess (\ _MainTex (\ _BumpMap (\ //边缘光颜色 _RimColor (\ 10. //放大倍数 11. _RimPower (\ 12. } 13. SubShader { 14. Tags { \ 15. LOD 400 16. 17. CGPROGRAM 18. #pragma surface surf BlinnPhong 19. #pragma target 3.0 20. 21. sampler2D _MainTex; 22. sampler2D _BumpMap; 23. fixed4 _Color; 24. half _Shininess; 25. float4 _RimColor; 26. float _RimPower; 27. 28. struct Input { 29. float2 uv_MainTex; 30. float2 uv_BumpMap; 31. float3 viewDir; 32. }; 33. 34. void surf (Input IN, inout SurfaceOutput o) { 35. 36. fixed4 tex = tex2D(_MainTex, IN.uv_MainTex); 37. o.Albedo = tex.rgb * _Color.rgb; 38. o.Gloss = tex.a; 39. o.Alpha = tex.a * _Color.a; 40. o.Specular = _Shininess; 41. o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap)); 42. //核心算法 43. half rim = 1 - saturate(dot (normalize(IN.viewDir), o.Normal)); 44. o.Emission = _RimColor.rgb * pow (rim, _RimPower); 45. } 46. ENDCG 47. 48. } 49. 50. FallBack \ 51. }
复制代码
在这个着色器脚本中,最重要的一个属性是_RimColor,这个值将决定我们最终渲染的效果。在上一篇文章中,我们是通过一个使用了自定义着色器的材质来实现轮廓显示的,今天我们换一种方法,怎么做呢?我们这里通过Shader来实现,在Material中有一个Shader属性,一旦改变了该属性的值,那么所有材质都将按照新的渲染方式进行渲染。我们在上一篇文章中的脚本的基础上,扩展得到下面的脚本:
1. 2. 3. 4. 5. 6. 7. 8. 9.
public class ShowBoundry : MonoBehaviour { //使用显示轮廓的简单材质 public Material mSimpleMat; //默认材质 public Material mDefaultMat; //我们今天使用Shader来直接改变模型的渲染效果,这样可以避免使用一个材质 public Shader RimLightShader; 10. public Color RimColor = new Color(0.2F,0.8F,10.6F,1); 11. //定义私有变量以存储模型的原始信息 12. private SkinnedMeshRenderer mSkin; 13. private Color mColor; 14. private Shader mShader; 15. void Start () 16. { 17. //获取模型的SkinnedMeshRenderer 18. mSkin=GameObject.Find(\ 19. GetComponentInChildren(); 20. //获取默认颜色 21. mColor=mSkin.material.color; 22. //获取默认Shader 23. mShader=mSkin.material.shader; 24. } 25. void Update () 26. {
共分享92篇相关文档