Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
3
Question by TheProfessor · Jun 06, 2016 at 07:10 AM · androidshaderpost-process-effect

Shader works in Editor/Windows but not on Android

This shader adds a post processor effect, on Windows/Editor it works, but on Android it does not appear. Just nothing, everything works, but the effect does not appear.

 Shader "Custom/Highlight" {
 Properties {
     _Color ("Color", Color) = (1,1,1,1)
     _MainTex ("Main Texture", 2D) = "black" {}
     _OccludeMap ("Occlusion Map", 2D) = "black" {}
 }
 
 SubShader {

     ZTest Always Cull Off ZWrite Off Fog { Mode Off }
     
     
     // OVERLAY GLOW
     
     Pass {
         CGPROGRAM
             #pragma vertex vert_img
             #pragma fragment frag
             #pragma fragmentoption ARB_precision_hint_fastest
             #include "UnityCG.cginc"
         
             sampler2D _MainTex;
             sampler2D _OccludeMap;
             
             fixed4 _Color;
         
             fixed4 frag(v2f_img IN) : COLOR 
             {
                 fixed3 overCol = tex2D(_OccludeMap, IN.uv).r * _Color.rgb * _Color.a;
                 return tex2D (_MainTex, IN.uv) + fixed4(overCol, 1.0);
             }
         ENDCG
     }
     
     // OVERLAY SOLID
     
     Pass {
         CGPROGRAM
             #pragma vertex vert_img
             #pragma fragment frag
             #pragma fragmentoption ARB_precision_hint_fastest
             #include "UnityCG.cginc"
         
             sampler2D _MainTex;
             sampler2D _OccludeMap;
             
             fixed4 _Color;
         
             fixed4 frag(v2f_img IN) : COLOR 
             {
                 fixed4 mCol = tex2D (_MainTex, IN.uv);
                 fixed oCol = tex2D (_OccludeMap, IN.uv).r;
                 
                 fixed solid = step (1.0 - _Color.a, oCol);
                 return mCol + solid * fixed4(_Color.rgb, 1.0);
             }
         ENDCG
     }
 
     
     // OCCLUSION
     
     Pass {
             CGPROGRAM
             #pragma vertex vert_img
             #pragma fragment frag
             #pragma fragmentoption ARB_precision_hint_fastest
             #include "UnityCG.cginc"
         
             sampler2D _MainTex;
             sampler2D _OccludeMap;
         
             fixed frag(v2f_img IN) : COLOR 
             {
                 return tex2D (_MainTex, IN.uv).r - tex2D(_OccludeMap, IN.uv).r;
             }
         ENDCG
     }
     
     Pass {
     
            Tags {"RenderType"="Opaque"}
         ZWrite On
         ZTest LEqual
         Fog { Mode Off }
     
         CGPROGRAM

         #pragma vertex vert
         #pragma fragment frag

         float4 vert(float4 v:POSITION) : POSITION {
             return mul (UNITY_MATRIX_MVP, v);
         }

         fixed frag() : COLOR {
             return 1.0;
         }

         ENDCG
     }    
     
     Pass {            
            Tags {"Queue"="Transparent"}
         Cull Back
         Lighting Off
         ZWrite Off
         ZTest LEqual
         ColorMask RGBA
         Blend OneMinusDstColor One

     
         CGPROGRAM
         #pragma vertex vert
         #pragma fragment frag
         #include "UnityCG.cginc"
         
         sampler2D _CameraDepthTexture;
         
         struct v2f {
             float4 vertex : POSITION;
             float4 projPos : TEXCOORD1;
         };
  
         v2f vert( float4 v : POSITION ) {        
             v2f o;
             o.vertex = mul( UNITY_MATRIX_MVP, v );
             o.projPos = ComputeScreenPos(o.vertex);             
             return o;
         }

         fixed frag( v2f i ) : COLOR {          
             float depthVal = LinearEyeDepth (tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)).r);
             float zPos = i.projPos.z;
             
             return step( zPos, depthVal );         
         }
         ENDCG
     }
 } 
 }

This works perfectly for a Windows build/Editor, but NOT in on an Android device/Emulator; it works via Unity Remote 4.

C# Script that uses it:

 using UnityEngine;
 using System.Collections.Generic;

 using UnityStandardAssets.ImageEffects;
 using UnityEngine.Rendering;

 [RequireComponent(typeof(Camera))]
 public class HighlightsPostEffect : MonoBehaviour 
 {
 #region enums
 public enum HighlightType
 {
     Glow = 0,
     Solid = 1
 }
 public enum SortingType
 {
     Overlay = 3,
     DepthFilter = 4
 }
 public enum FillType
 {
     Fill,
     Outline
 }
 public enum RTResolution
 {
     Quarter = 4,
     Half = 2,
     Full = 1
 }
 #endregion

 #region public vars

 public HighlightType m_selectionType = HighlightType.Glow;
 public SortingType m_sortingType = SortingType.DepthFilter;    
 public FillType m_fillType = FillType.Outline;
 public RTResolution m_resolution = RTResolution.Full;

 public string m_occludeesTag = "Occludee";
 public string m_occludersTag = "Occluder";
 public Color m_highlightColor = new Color(1f, 0f, 0f, 0.65f);

 public Shader m_highlightShader;

 #endregion

 #region private field

 private BlurOptimized m_blur;

 private Renderer[] highlightObjects;
 private Renderer[] m_occluders = null;
 
 private Material m_highlightMaterial;

 private CommandBuffer m_renderBuffer;

 private int m_RTWidth = 512;
 private int m_RTHeight = 512;

 #endregion

 private void Awake()
 {
     CreateBuffers();
     CreateMaterials();
     SetOccluderObjects();

     //m_blur = gameObject.AddComponent<BlurOptimized>();
     m_blur = gameObject.GetComponent<BlurOptimized>();
     m_blur.enabled = false;

     GameObject[] occludees = GameObject.FindGameObjectsWithTag(m_occludeesTag);
     highlightObjects = new Renderer[occludees.Length];


     for( int i = 0; i < occludees.Length; i++ )
         highlightObjects[i] = occludees[i].GetComponent<Renderer>();

     m_RTWidth = (int) (Screen.width / (float) m_resolution);
     m_RTHeight = (int) (Screen.height / (float) m_resolution);
 }

 private void CreateBuffers()
 {
     m_renderBuffer = new CommandBuffer();
 }

 private void ClearCommandBuffers()
 {
     m_renderBuffer.Clear();
 }
 
 private void CreateMaterials()
 {
     m_highlightMaterial = new Material( m_highlightShader );
 }

 private void SetOccluderObjects()
 {
     if( string.IsNullOrEmpty(m_occludersTag) )
         return;
     
     GameObject[] occluderGOs = GameObject.FindGameObjectsWithTag(m_occludersTag);
     
     List<Renderer> occluders = new List<Renderer>();
     foreach( GameObject go in occluderGOs )
     {
         Renderer renderer = go.GetComponent<Renderer>();
         if( renderer != null )
             occluders.Add( renderer );
     }
     
     m_occluders = occluders.ToArray();
 }
 
 private void RenderHighlights( RenderTexture rt)
 {
     if( highlightObjects == null )
         return;

     RenderTargetIdentifier rtid = new RenderTargetIdentifier(rt);
     m_renderBuffer.SetRenderTarget( rtid );


     for(int i = 0; i < highlightObjects.Length; i++)
     {
         if( highlightObjects[i] == null )
             continue;
     
         m_renderBuffer.DrawRenderer( highlightObjects[i], m_highlightMaterial, 0, (int) m_sortingType );
     }

     RenderTexture.active = rt;
     Graphics.ExecuteCommandBuffer(m_renderBuffer);
     RenderTexture.active = null;
 }
 
 private void RenderOccluders( RenderTexture rt)
 {
     if( m_occluders == null )
         return;

     RenderTargetIdentifier rtid = new RenderTargetIdentifier(rt);
     m_renderBuffer.SetRenderTarget( rtid );

     m_renderBuffer.Clear();
     
     foreach(Renderer renderer in m_occluders)
     {    
         m_renderBuffer.DrawRenderer( renderer, m_highlightMaterial, 0, (int) m_sortingType );
     }

     RenderTexture.active = rt;
     Graphics.ExecuteCommandBuffer(m_renderBuffer);
     RenderTexture.active = null;
 }


 /// Final image composing.
 /// 1. Renders all the highlight objects either with Overlay shader or DepthFilter
 /// 2. Downsamples and blurs the result image using standard BlurOptimized image effect
 /// 3. Renders occluders to the same render texture
 /// 4. Substracts the occlusion map from the blurred image, leaving the highlight area
 /// 5. Renders the result image over the main camera's G-Buffer
     private void OnRenderImage( RenderTexture source, RenderTexture destination )
     {
         RenderTexture highlightRT;

         RenderTexture.active = highlightRT = RenderTexture.GetTemporary(m_RTWidth, m_RTHeight, 0, RenderTextureFormat.R8 );
         GL.Clear(true, true, Color.clear);
         RenderTexture.active = null;

         ClearCommandBuffers();

         RenderHighlights(highlightRT);

         RenderTexture blurred = RenderTexture.GetTemporary( m_RTWidth, m_RTHeight, 0, RenderTextureFormat.R8 );


         m_blur.OnRenderImage( highlightRT, blurred );

 
         RenderOccluders(highlightRT);

         if( m_fillType == FillType.Outline )
         {
             RenderTexture occluded = RenderTexture.GetTemporary( m_RTWidth, m_RTHeight, 0, RenderTextureFormat.R8);

         // Excluding the original image from the     blurred image, leaving out the areal alone
             m_highlightMaterial.SetTexture("_OccludeMap", highlightRT);
             Graphics.Blit( blurred, occluded, m_highlightMaterial, 2 );

             m_highlightMaterial.SetTexture("_OccludeMap", occluded);

             RenderTexture.ReleaseTemporary(occluded);

         }
         else
         {
             m_highlightMaterial.SetTexture("_OccludeMap", blurred);
         }

         m_highlightMaterial.SetColor("_Color", m_highlightColor);
         Graphics.Blit (source, destination, m_highlightMaterial, (int) m_selectionType);


         RenderTexture.ReleaseTemporary(blurred);
         RenderTexture.ReleaseTemporary(highlightRT);
     }

     public void RefreshHighlight()
     {
     //CreateBuffers();
     //CreateMaterials();
         SetOccluderObjects();

     //m_blur =     gameObject.AddComponent<BlurOptimized>();
     //m_blur.enabled = false;

         GameObject[] occludees = GameObject.FindGameObjectsWithTag(m_occludeesTag);
         highlightObjects = new Renderer[occludees.Length];


         for (int i = 0; i < occludees.Length; i++)
             highlightObjects[i] = occludees[i].GetComponent<Renderer>();

         m_RTWidth = (int)(Screen.width / (float)m_resolution);
         m_RTHeight = (int)(Screen.height / (float)m_resolution);
     }
 }
Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image tanoshimi · Jun 07, 2016 at 06:16 AM 0
Share

(sidenote) I never knew CommandBuffers worked on mobile- I'd always associated them with deferred rendering and DX11/desktop only. So thanks for showing me that's not the case!

1 Reply

· Add your reply
  • Sort: 
avatar image
1

Answer by Eudaimonium · Jun 07, 2016 at 12:54 AM

Well, you're trying to do post processing on mobile hardware, what did you expect? :D

Seriously though, technical question: Are you using deferred rendering on your main camera?

If so, no wonder. Deferred rendering requires MRT (multiple render targets) tech, basically it means that a pixel shader can write to several render targets at once, instead of just one. This feature is not supported on mobile hardware yet, to the best of my knowledge. Therefore you lose your depth buffer and whatever else is required for your effects to work.

Putting that aside, any kind of post process on mobile will be horrible for performance because mobile devices have insane resolutions, but very low pixel fillrates - usually not enough to render out to the entire screen several times. Even reducing the resolution doesn't help much since simply switching texture targets required for post process will be insanely expensive.

If I may be so bold as to ask, what is the nature of your application? Any particular reason why you can't just stick with desktop platform?

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image TheProfessor · Jun 07, 2016 at 01:00 AM 0
Share

The problem turns out to be a simple fix: RenderTextureFormat.R8 needed to be RenderTextureFormat.RGBA32 and it works perfectly. I'm not sure why though.

I was developing on Windows because it's a mobile multiplayer game but its faster to iterate on the PC build then it is to use an emulator.

avatar image Eudaimonium TheProfessor · Jun 07, 2016 at 09:21 AM 0
Share

Aahh yes then there's that, I believe I saw a platform-format table, so you can crossreference what supports what.

Hmm I can't seem to find it, but there's this link, try running this on your mobile system and check against R8 format:
http://docs.unity3d.com/ScriptReference/SystemInfo.SupportsRenderTextureFormat.html

Perhaps that's why.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

Strange bug(?) using Graphics.Blit 0 Answers

Specular bug on iOS/Android using Standard shader 2 Answers

ARtoolkit problem on android 2 Answers

Set default number/emails in a new text message/email sent via unity 0 Answers

Shader works in editor but not on Android 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges