1
\$\begingroup\$

I'm trying to make text have a fixed position in world space and be overlayed in screen space at the same time.

enter image description here

I have text in canvas with "Screen Space - Overlay" which covers my text located in canvas (world space).

What should I do? Is this a dead end? Please comment if you didn't understand (I know it's hard to get)

\$\endgroup\$
  • \$\begingroup\$ you want a world space canvas that is always on top of everything I presume ? \$\endgroup\$ – Uri Popov May 3 '16 at 9:28
  • \$\begingroup\$ @UriPopov Exactly. \$\endgroup\$ – Programmer May 3 '16 at 9:29
  • \$\begingroup\$ I edited my answer to explain how to do exactly what you want. Please check it out. \$\endgroup\$ – Uri Popov May 4 '16 at 8:03
1
\$\begingroup\$

A world-space canvas is rendered as a 3d plane-mesh in the game-world, which means it is overlapped by other 3d objects. But to solve this problem you don't need a custom shader. You can do it with multiple cameras with different culling masks.

When you have multiple cameras in your scene, each camera will be rendered separately. The culling mask decides what will be rendered by the camera. Then the output of all the cameras get drawn on top of each other in order of their "Depth" value.

  • Click on "Layers -> Edit Layers" and create a new user layer "Over".
  • Assign that layer to the world-space canvas.
  • Make sure everything else has the "Default" layer assigned to it.
  • Create a second camera which is identical to the first. Make sure it also maintains the same position, rotation and other settings so both cameras always show the exact same view frustum.
  • On the first camera (the "default"-camera) set:
    • Clear Flags: "Skybox" / "Solid color" (whatever you want to be the background)
    • Culling mask: "Default"
    • Depth: 0
  • On the second camera (the "over" camera) set:
    • Clear Flags: "Depth Only"
    • Culling mask: "Over"
    • Depth: 1
\$\endgroup\$
  • \$\begingroup\$ I have a question. Isn't this doing the exact same thing as the shader in my answer, but just internally ? \$\endgroup\$ – Uri Popov May 3 '16 at 9:55
  • \$\begingroup\$ I have tried this, and it only makes world space canvas elements be in front of default non-canvas gameobjects. Canvas overlay is still in front of world space canvas. where did i go wrong? \$\endgroup\$ – Programmer May 3 '16 at 10:18
  • \$\begingroup\$ @Gog65 I don't understand. Isn't that what you wanted? \$\endgroup\$ – Philipp May 3 '16 at 10:53
  • \$\begingroup\$ @UriPopov Shader programming is not my area of expertise. \$\endgroup\$ – Philipp May 3 '16 at 10:54
  • \$\begingroup\$ @Philipp i want my world space canvas to be on top everything, even my Screen Space - Overlay canvas. \$\endgroup\$ – Programmer May 3 '16 at 10:57
0
\$\begingroup\$

You're going to need a custom shader for your World Space UI objects that has it's Render Order to Overlay and has ZTest turned off. Also your World Space ui does not have to be a child of a screen overlay canvas( that's not how it works)

This is a copy of the Default UI shader with the necessary changes. Should do the trick. Just make a material with this shader, and apply it to everything you want drawn over the top of geometry in your WorldSpace UI.

Shader "UI/Default_OverlayNoZTest"
 {
     Properties
     {
         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
         _Color ("Tint", Color) = (1,1,1,1)

         _StencilComp ("Stencil Comparison", Float) = 8
         _Stencil ("Stencil ID", Float) = 0
         _StencilOp ("Stencil Operation", Float) = 0
         _StencilWriteMask ("Stencil Write Mask", Float) = 255
         _StencilReadMask ("Stencil Read Mask", Float) = 255

         _ColorMask ("Color Mask", Float) = 15
     }

     SubShader
     {
         Tags
         { 
             "Queue"="Overlay" 
             "IgnoreProjector"="True" 
             "RenderType"="Transparent" 
             "PreviewType"="Plane"
             "CanUseSpriteAtlas"="True"
         }

         Stencil
         {
             Ref [_Stencil]
             Comp [_StencilComp]
             Pass [_StencilOp] 
             ReadMask [_StencilReadMask]
             WriteMask [_StencilWriteMask]
         }

         Cull Off
         Lighting Off
         ZWrite Off
         ZTest Off
         Blend SrcAlpha OneMinusSrcAlpha
         ColorMask [_ColorMask]

         Pass
         {
         CGPROGRAM
             #pragma vertex vert
             #pragma fragment frag
             #include "UnityCG.cginc"

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

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

             fixed4 _Color;

             v2f vert(appdata_t IN)
             {
                 v2f OUT;
                 OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
                 OUT.texcoord = IN.texcoord;
 #ifdef UNITY_HALF_TEXEL_OFFSET
                 OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
 #endif
                 OUT.color = IN.color * _Color;
                 return OUT;
             }

             sampler2D _MainTex;

             fixed4 frag(v2f IN) : SV_Target
             {
                 half4 color = tex2D(_MainTex, IN.texcoord) * IN.color;
                 clip (color.a - 0.01);
                 return color;
             }
         ENDCG
         }
     }
 }

credit goes to http://answers.unity3d.com/questions/878667/world-space-canvas-on-top-of-everything.html

Edit: Ok so I managed to replicate what the OP wants using my shader and a screen-space camera canvas. Here is a screenshot: enter image description here

The red square is a world canvas image that has a material with the shader. The button is a screenspace camera button with the same material. Both canvases are set to the UI layer. The world space canvas has its sorting order set to 1 and the camera canvas order in layer is 0. Now both the world space canvas and the camera one are over all other geometry and the world canvas is on top of everything.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.