当前位置:   article > 正文

Unity的2.5D效果探究_unity2.5d研究

unity2.5d研究

2.5D可能并不是一个很精准的词,我这里所指的是DNF这种可以在3个轴向上运动的2D精灵类型的效果。

以DNF为例,精灵实际上没有Z轴坐标的,当按↑,人物向屏幕里(远离玩家)方向移动时(z轴),在渲染上,我们看到人物是在向上移动。而我们按c,人物跳起(y轴),我们仍然看到人物在向上移动。这就是DNF类游戏看起来有点3d效果的奥秘:它营造一种我们在斜向下45度(或者其它角度)观看地面的感觉,因此当人物坐标在Z轴移动时,在屏幕投影位置上我们看到人物向上或向下移动。

所以,这种效果可以通过3维坐标在渲染时的一个变换来完成。

设点A(x1,y1,z1),那么它渲染时的世界坐标会变换为:

x2 = x1,

y2 = y1*cos(a)+z1*cos(90-a)

z2 = 0

其中a代表视线与xz平面的夹角,不过一般Y轴不计算投影,因为要保持精灵的正常显示,不能让它因斜视而变矮。

因此,y2 = y1 + z1*cos(90-a)

最开始,我打算了unity中为一个物体建立两个gameobject,一个物体赋值3维坐标,因为它处于真实位置,因此可直接使用物理系统,另一个物体用上面的映射方法,计算出坐标并使用它来表示精灵的位置,SpriteRenderer附加在第二个物体上。我确实这样实现了,也运行正常。

不过后面我想到,可以用shader来更改显示位置,这样只用一个gameobject,用普通Sprite即可,比较符合直觉,也便于使用。下面先看下效果:

45度角:

yangxun983323204

这样好处在于,物体的transform和boxcollider仍然是在正常的3D空间中的,所以碰撞检测可以完全以我们熟悉的3D物理组件来完成,而不需要自己实现。

另外,对于要做小游戏的程序员来说,2D游戏对素材要求会小一些。。用此方式,表现力会比用单纯的2d精灵和2d物理好很多。

附上shader,用精灵的默认shader改的:

  1. Shader "Sprites/YX2.5D"
  2. {
  3. Properties
  4. {
  5. [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
  6. _Color ("Tint", Color) = (1,1,1,1)
  7. [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
  8. [HideInInspector] _RendererColor ("RendererColor", Color) = (1,1,1,1)
  9. [HideInInspector] _Flip ("Flip", Vector) = (1,1,1,1)
  10. [PerRendererData] _AlphaTex ("External Alpha", 2D) = "white" {}
  11. [PerRendererData] _EnableExternalAlpha ("Enable External Alpha", Float) = 0
  12. [HideInInspector] ZFactor ("Z-Factor",float) = 0.707
  13. [HideInInspector] WOrigin ("Origin",Vector) = (0,0,0,0)
  14. }
  15. SubShader
  16. {
  17. Tags
  18. {
  19. "Queue"="Transparent"
  20. "IgnoreProjector"="True"
  21. "RenderType"="Transparent"
  22. "PreviewType"="Plane"
  23. "CanUseSpriteAtlas"="True"
  24. }
  25. Cull Off
  26. Lighting Off
  27. ZWrite Off
  28. Blend One OneMinusSrcAlpha
  29. Pass
  30. {
  31. CGPROGRAM
  32. #pragma vertex SpriteVert
  33. #pragma fragment SpriteFrag
  34. #pragma target 2.0
  35. #pragma multi_compile_instancing
  36. #pragma multi_compile _ PIXELSNAP_ON
  37. #pragma multi_compile _ ETC1_EXTERNAL_ALPHA
  38. #include "UnityCG.cginc"
  39. #ifdef UNITY_INSTANCING_ENABLED
  40. UNITY_INSTANCING_CBUFFER_START(PerDrawSprite)
  41. // SpriteRenderer.Color while Non-Batched/Instanced.
  42. fixed4 unity_SpriteRendererColorArray[UNITY_INSTANCED_ARRAY_SIZE];
  43. // this could be smaller but that's how bit each entry is regardless of type
  44. float4 unity_SpriteFlipArray[UNITY_INSTANCED_ARRAY_SIZE];
  45. UNITY_INSTANCING_CBUFFER_END
  46. #define _RendererColor unity_SpriteRendererColorArray[unity_InstanceID]
  47. #define _Flip unity_SpriteFlipArray[unity_InstanceID]
  48. #endif // instancing
  49. CBUFFER_START(UnityPerDrawSprite)
  50. #ifndef UNITY_INSTANCING_ENABLED
  51. fixed4 _RendererColor;
  52. float4 _Flip;
  53. #endif
  54. float _EnableExternalAlpha;
  55. CBUFFER_END
  56. // Material Color.
  57. fixed4 _Color;
  58. float4 WOrigin;
  59. float ZFactor;
  60. float YFactor;
  61. struct appdata_t
  62. {
  63. float4 vertex : POSITION;
  64. float4 color : COLOR;
  65. float2 texcoord : TEXCOORD0;
  66. UNITY_VERTEX_INPUT_INSTANCE_ID
  67. };
  68. struct v2f
  69. {
  70. float4 vertex : SV_POSITION;
  71. fixed4 color : COLOR;
  72. float2 texcoord : TEXCOORD0;
  73. UNITY_VERTEX_OUTPUT_STEREO
  74. };
  75. v2f SpriteVert(appdata_t IN)
  76. {
  77. v2f OUT;
  78. UNITY_SETUP_INSTANCE_ID (IN);
  79. UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
  80. #ifdef UNITY_INSTANCING_ENABLED
  81. IN.vertex.xy *= _Flip.xy;
  82. #endif
  83. float4 wpos = mul(unity_ObjectToWorld, IN.vertex)-WOrigin;
  84. float4 wposMap = float4(wpos.x,wpos.y + wpos.z*ZFactor,0,wpos.w);
  85. OUT.vertex = mul(UNITY_MATRIX_VP,wposMap);
  86. OUT.texcoord = IN.texcoord;
  87. OUT.color = IN.color * _Color * _RendererColor;
  88. #ifdef PIXELSNAP_ON
  89. OUT.vertex = UnityPixelSnap (OUT.vertex);
  90. #endif
  91. return OUT;
  92. }
  93. sampler2D _MainTex;
  94. sampler2D _AlphaTex;
  95. fixed4 SampleSpriteTexture (float2 uv)
  96. {
  97. fixed4 color = tex2D (_MainTex, uv);
  98. #if ETC1_EXTERNAL_ALPHA
  99. fixed4 alpha = tex2D (_AlphaTex, uv);
  100. color.a = lerp (color.a, alpha.r, _EnableExternalAlpha);
  101. #endif
  102. return color;
  103. }
  104. fixed4 SpriteFrag(v2f IN) : SV_Target
  105. {
  106. fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
  107. c.rgb *= c.a;
  108. return c;
  109. }
  110. ENDCG
  111. }
  112. }
  113. }

使用方法为,创建一个材质,使用上面提供的shader,默认就是45度角的效果。然后SpriteRender使用该材质。

为了方便起见,还写了一个c#脚本,方便视角、原点等参数设置,但它不是必须的:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class Sprite25D : MonoBehaviour {
  5. public Vector3 Origin;
  6. public float Angle = 45;
  7. private new SpriteRenderer renderer;
  8. private void OnEnable()
  9. {
  10. Apply();
  11. }
  12. public void Apply()
  13. {
  14. if (renderer == null)
  15. {
  16. renderer = GetComponent<SpriteRenderer>();
  17. }
  18. Material mat;
  19. if (Application.isPlaying)
  20. mat = renderer.material;
  21. else
  22. mat = renderer.sharedMaterial;
  23. mat.SetVector("WOrigin", Origin);
  24. mat.SetFloat("ZFactor", Mathf.Sin(Angle * Mathf.Deg2Rad));
  25. }
  26. }
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using UnityEditor;
  5. [CustomEditor(typeof(Sprite25D))]
  6. public class Sprite25DInspector : Editor
  7. {
  8. public override void OnInspectorGUI()
  9. {
  10. base.OnInspectorGUI();
  11. GUILayout.Label("以下操作会修改sharedMaterial");
  12. if (GUILayout.Button("设置当前位置为映射原点"))
  13. {
  14. var inst = (target as Sprite25D);
  15. var pos = inst.transform.position;
  16. inst.Origin = new Vector3(pos.x, pos.y, pos.z);
  17. inst.Apply();
  18. }
  19. if (GUILayout.Button("重置原点为zero"))
  20. {
  21. var inst = (target as Sprite25D);
  22. inst.Origin = Vector3.zero;
  23. inst.Apply();
  24. }
  25. }
  26. }

就是这样了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/90769
推荐阅读
相关标签
  

闽ICP备14008679号