Search code examples
unity-game-enginerenderingshader

Rendering 3d objects behind 2d Objects unity


I am making a an isometric game with a combination of 2d and 3d elements. I wish to know how to make my player and enemy sprites (all made up of 2d elemnts) not render behind or inside my 3d elements.

enter image description here

So I have tried messing about with renderQueue and setting the renderqueue of the materials these rocks and such have to a high value to have them drawn behind the 2d elements.

However through my searching I have found out that I actually need to be setting the ztest of the objects to correct this. This confused me a bit and I am unsure how to do it as I have not really used shaders that much. I could not find any decent references that explain exactly how to go about this just stuff written that assumes prior knowledge like this. I tried downloading the unity shaders and and opened the default sprite one but I was unsure where to change the ztest or tagging to solve this.

here is the standard sprite shader from unity:

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

#ifndef UNITY_SPRITES_INCLUDED
#define UNITY_SPRITES_INCLUDED

#include "UnityCG.cginc"

#ifdef UNITY_INSTANCING_ENABLED

UNITY_INSTANCING_BUFFER_START(PerDrawSprite)
    // SpriteRenderer.Color while Non-Batched/Instanced.
    UNITY_DEFINE_INSTANCED_PROP(fixed4, unity_SpriteRendererColorArray)
    // this could be smaller but that's how bit each entry is regardless of type
    UNITY_DEFINE_INSTANCED_PROP(fixed2, unity_SpriteFlipArray)
UNITY_INSTANCING_BUFFER_END(PerDrawSprite)

#define _RendererColor  UNITY_ACCESS_INSTANCED_PROP(PerDrawSprite, unity_SpriteRendererColorArray)
#define _Flip           UNITY_ACCESS_INSTANCED_PROP(PerDrawSprite,    unity_SpriteFlipArray)

#endif // instancing

CBUFFER_START(UnityPerDrawSprite)
#ifndef UNITY_INSTANCING_ENABLED
fixed4 _RendererColor;
fixed2 _Flip;
#endif
float _EnableExternalAlpha;
CBUFFER_END

// Material Color.
fixed4 _Color;

struct appdata_t
{
float4 vertex   : POSITION;
float4 color    : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct v2f
{
float4 vertex   : SV_POSITION;
fixed4 color    : COLOR;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_OUTPUT_STEREO
};

inline float4 UnityFlipSprite(in float3 pos, in fixed2 flip)
{
return float4(pos.xy * flip, pos.z, 1.0);
}

v2f SpriteVert(appdata_t IN)
{
v2f OUT;

UNITY_SETUP_INSTANCE_ID (IN);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);

OUT.vertex = UnityFlipSprite(IN.vertex, _Flip);
OUT.vertex = UnityObjectToClipPos(OUT.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color * _Color * _RendererColor;

#ifdef PIXELSNAP_ON
OUT.vertex = UnityPixelSnap (OUT.vertex);
#endif

return OUT;
}

sampler2D _MainTex;
sampler2D _AlphaTex;

fixed4 SampleSpriteTexture (float2 uv)
{
fixed4 color = tex2D (_MainTex, uv);

#if ETC1_EXTERNAL_ALPHA
fixed4 alpha = tex2D (_AlphaTex, uv);
color.a = lerp (color.a, alpha.r, _EnableExternalAlpha);
#endif

  return color;
}

fixed4 SpriteFrag(v2f IN) : SV_Target
{
   fixed4 c = SampleSpriteTexture (IN.texcoord) * IN.color;
   c.rgb *= c.a;
   return c;
 }

#endif // UNITY_SPRITES_INCLUDED

Update 1

enter image description here


Solution

  • If I understand your problem correctly, I think you can try using an extra camera.

    Correctly set the two cameras's culling mask and depth and clear flags.

    The depth of the extra camera should be higher and the clearflag should be set to depth only and culling mask only set the layer you want render in front.

    And your original camera culling mask should delete the layer render in extra camera.

    You can make objects of a particular layer render in front.

    Yesterday Svp tell me that he want fine-grained control drawing-order of 2d and 3d objects.My old answer can not does this well.So after research, there are three solutions.

    UPDATE:

    1. Treat 2d object as 3d. Use z-pos to sort all objects. Keep few 3d object z-pos always less than or greater than player z-pos (The offset of z-pos of 3d object and player need greater than fixed value that make the entire 3d object behind the player.).The fixed value could select 3d object bounds max.

    2. Treat 3d object as 2d. 3d object mesh render use 2d sprite-default shader. Use 2d sorting layer and order in layer control 3d object render.But we need custom mesh render inspector use follow code copy from here by uvivagabond.

      using System;
      using UnityEngine;
      using UnityEditor;
      using UnityEditorInternal;
      using System.Reflection;
      using UnityEngine.Rendering;
      [CanEditMultipleObjects ()]
      [CustomEditor (typeof(MeshRenderer))]
      public class MeshRendererSortingLayersEditor : Editor
      {
      
          public override void OnInspectorGUI ()
          {
      
              #region Get Serialized Property
              SerializedProperty sortingLayerID = serializedObject.FindProperty (propertyPath: "m_SortingLayerID");
              SerializedProperty sortingOrder = serializedObject.FindProperty ("m_SortingOrder");
      
              SerializedProperty castShadows = serializedObject.FindProperty ("m_CastShadows");
              SerializedProperty receiveShadows = serializedObject.FindProperty ("m_ReceiveShadows");
              SerializedProperty motionVectors = serializedObject.FindProperty ("m_MotionVectors");
              SerializedProperty materials = serializedObject.FindProperty ("m_Materials");
              SerializedProperty lightProbes = serializedObject.FindProperty ("m_LightProbeUsage");
              SerializedProperty reflectionProbes = serializedObject.FindProperty ("m_ReflectionProbeUsage");
              SerializedProperty anchorProbes = serializedObject.FindProperty ("m_ProbeAnchor");
              #endregion
      
              #region Draw Properties
              AddPropertyField (castShadows);
              AddPropertyField (receiveShadows);
              AddPropertyField (motionVectors);
              AddPropertyField (materials);
              AddPopup (ref lightProbes, "Light Probes", typeof(LightProbeUsage));
              AddPopup (ref reflectionProbes, "Reflection Probes", typeof(ReflectionProbeUsage));
              AddPropertyField (anchorProbes, "Anchor Override");
              #endregion
      
      
              GUIStyle style = new GUIStyle (GUI.skin.label);
              style.richText = true;
              EditorGUILayout.Space ();
              EditorGUILayout.LabelField ("<b><color=#EE4035FF>SortingLayers Options:</color></b>", style);
              #region SortingLayer
              Rect firstHoriz = EditorGUILayout.BeginHorizontal ();
              EditorGUI.BeginChangeCheck ();
              //    EditorGUI.PropertyField (mat, new GUIContent ("Materials"));
              EditorGUI.BeginProperty (firstHoriz, GUIContent.none, sortingLayerID);
              string[] layerNames = GetSortingLayerNames ();
              int[] layerID = GetSortingLayerUniqueIDs ();
              int selected = -1;
              int sID = sortingLayerID.intValue;
              for (int i = 0; i < layerID.Length; i++)
                  if (sID == layerID [i])
                      selected = i;
              if (selected == -1)
                  for (int i = 0; i < layerID.Length; i++)
                      if (layerID [i] == 0)
                          selected = i;
              selected = EditorGUILayout.Popup ("Sorting Layer", selected, layerNames);
      
              sortingLayerID.intValue = layerID [selected];
              EditorGUI.EndProperty ();
              EditorGUILayout.EndHorizontal ();
              #endregion
      
              #region OrderInLayer
              EditorGUILayout.BeginHorizontal ();
              EditorGUI.BeginChangeCheck ();
              EditorGUILayout.PropertyField (sortingOrder, new GUIContent ("Order in Layer"));
              EditorGUILayout.EndHorizontal ();
              serializedObject.ApplyModifiedProperties ();
              #endregion
      
      
          }
      
          void AddPropertyField (SerializedProperty ourSerializedProperty)
          {
              Rect ourRect = EditorGUILayout.BeginHorizontal ();
              EditorGUI.BeginProperty (ourRect, GUIContent.none, ourSerializedProperty);
              EditorGUI.BeginChangeCheck ();
      
              EditorGUILayout.PropertyField (property: ourSerializedProperty, includeChildren: true); //I set includeChildren:true to display material children
      
              EditorGUI.EndProperty ();
              EditorGUILayout.EndHorizontal ();
          }
      
          void AddPropertyField (SerializedProperty ourSerializedProperty, string name)
          {
              Rect ourRect = EditorGUILayout.BeginHorizontal ();
              EditorGUI.BeginProperty (ourRect, GUIContent.none, ourSerializedProperty);
              EditorGUI.BeginChangeCheck ();
      
              EditorGUILayout.PropertyField (ourSerializedProperty, new GUIContent (name), true);
      
              EditorGUI.EndProperty ();
              EditorGUILayout.EndHorizontal ();
          }
      
          void AddPopup (ref SerializedProperty ourSerializedProperty, string nameOfLabel, Type typeOfEnum)
          {
              Rect ourRect = EditorGUILayout.BeginHorizontal ();
              EditorGUI.BeginProperty (ourRect, GUIContent.none, ourSerializedProperty);
              EditorGUI.BeginChangeCheck ();
      
              int actualSelected = 1;  
              int selectionFromInspector = ourSerializedProperty.intValue;
              string[] enumNamesList = System.Enum.GetNames (typeOfEnum);
              actualSelected = EditorGUILayout.Popup (nameOfLabel, selectionFromInspector, enumNamesList);
              ourSerializedProperty.intValue = actualSelected;
      
              EditorGUI.EndProperty ();
              EditorGUILayout.EndHorizontal ();
          }
      
      
          public string[] GetSortingLayerNames ()
          {
              Type internalEditorUtilityType = typeof(InternalEditorUtility);
              PropertyInfo sortingLayersProperty = internalEditorUtilityType.GetProperty ("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
              return (string[])sortingLayersProperty.GetValue (null, new object[0]);
          }
      
          public int[] GetSortingLayerUniqueIDs ()
          {
              Type internalEditorUtilityType = typeof(InternalEditorUtility);
              PropertyInfo sortingLayerUniqueIDsProperty = internalEditorUtilityType.GetProperty ("sortingLayerUniqueIDs", BindingFlags.Static | BindingFlags.NonPublic);
              return (int[])sortingLayerUniqueIDsProperty.GetValue (null, new object[0]);
          }
      }
      

    After this your render mesh inspector view as this: Mesh Render Inspector

    1. Combine 2d render system and 3d render system. Handle Z-buffer Z-write and many many other ... I believe this great challenge.Unity should do this work not us.

    I hope this can help you.