- Home /
Graphics.Blit with custom shader gives black screen under iOS
I have the following
public Material shaderMaterial;
void OnRenderImage (RenderTexture source, RenderTexture destination) {
//rotoscopeMaterial.color = Color.white;
Graphics.Blit(source, destination, shaderMaterial);
}
where shaderMaterial is associated with a simple GLSL shader. This works fine in the development environment but when I build the app for iOS and run it on a device see nothing but a black screen. However, when I Blit() the image directly with no shader I do see the correct output. Any ideas?
i am having the same issue, have you found a way to fix it?
Answer by ecschiel · Oct 19, 2017 at 02:05 AM
It's probably late for an answer, but maybe it helps someone. I had this same issue using a custom shader for some post-processing effects and the reason was the custom shader was not being included in the build. You have to:
1 - reference it in some material
2 - add it under "Allways included shaders", or
3 - put shader or something that reference it on "Resources" folder
as stated in Shader.Find doc
Never too late for an answer, because this really saved my bacon! I was doing some postprocessing in OnRenderImage and while it worked fine in the editor, the build remained black. Turns out that one of the shaders I used was only used by Shader.Find and not referenced anywhere else, so it didn't get included in the build. Adding it to "Always included" seemed the cleanest solution. Thanks!
Answer by schulkinator · Mar 13, 2013 at 07:20 PM
There seems to be a bug in Unity (as of 4.0.1) under iOS where in OnRenderImage you cannot directly Blit to the destination with a Material. Doing so effectively renders nothing (whatever was previously in the backbuffer, which may be black, or garbage, or the previously rendered frames). You can however, as a workaround, render to an intermediate buffer and then Blit to the destination without a material. For example:
public Material shaderMaterial;
public RenderTexture intermediateRT;
void OnRenderImage (RenderTexture source, RenderTexture destination) {
//rotoscopeMaterial.color = Color.white;
Graphics.Blit(source, intermediateRT, shaderMaterial);
Graphics.Blit(intermediateRT, destination);
}
This of course costs the additional overhead of another RenderTexture and draw call, but it at least works. Hopefully Unity will fix this in future versions.
The way I isolated this was by using different materials of varying complexity, some that just do diffuse texturing, and some that just output a flat color, none of them worked. They work in the editor but not on a device. Also, all my RenderTexture formats were identical RGBA32s (save some resolution differences). But once I Blit without a Material to destination it renders as expected. My conclusion was that it must be the presence of a Material that is causing the issue.
i don't think this is a Unity 4.0.1+ problem. i had this issue in unity 3.5 and your solution still isn't working. i get no effect whatsoever applied. (now i have unity 4.0)
@badescuga9 I wasn't implying it was exclusively a Unity 4.0.1 problem, I was merely identifying that as the version I have known this issue to exist on (it's the version I use). As for your continuing issues, are you sure you don't have a material applied on the final Blit? Is the shader you're using working correctly and does it have all the proper inputs? Perhaps you need to set the specific pass you want by using the fourth parameter to Blit()? Also what error are you getting, if any? Could you possibly post the relevant code? Oh and to cover the obvious, I have omitted the actual creation of the intermediate rendertexture, so you would obviously need to do that to have functioning code (it would be the same format and dimensions as your screen).
i get a black screen when i try to render. All the code works in the simulator. I don't get any errors. If i apply the material on a plane, it renders properly(so it can't be the shader). i am doing a nightvision effect. I set the intermediate RT in Start() :
intermediateRT = new RenderTexture(Screen.width,Screen.height,0,RenderTextureFormat.Default);
and after that in the OnRenderImage() i use:
Graphics.Blit(source, intermediateRT, overlay$$anonymous$$aterial,0);
Graphics.Blit(intermediateRT, destination);
As for the shader:
Shader "Custom/nightvisionShader" {
Properties {
_$$anonymous$$ainTex ("Texture ", 2D) = "white" {}
_noiseTex ("noiseTex ", 2D) = "white" {}
_maskTex ("mask tex",2D) = "white" {}
_elapsedTime("elapsed time",Float) = 0 // seconds
_lu$$anonymous$$anceThreshold("lu$$anonymous$$ance threshold",Float) = .2 // 0.2
_colorAmplification("color amplification",Float) = 4 // 4.0
_effectCoverage("effect coverage",Float) = .5 // 0.5
}
SubShader {
Tags { "RenderType"="Transparent" }
//LOD 200
CGPROGRA$$anonymous$$
#pragma surface surf Lambert
sampler2D _$$anonymous$$ainTex;
sampler2D _noiseTex;
sampler2D _maskTex;
float _elapsedTime;
float _lu$$anonymous$$anceThreshold;
float _colorAmplification;
float _effectCoverage;
struct Input {
float2 uv_$$anonymous$$ainTex;
float2 uv_noiseTex;
float2 uv_maskTex;
};
void surf (Input IN, inout SurfaceOutput o)
{
half4 finalColor;
if (IN.uv_$$anonymous$$ainTex.x < _effectCoverage)
{
float2 uv;
uv.x = 0.4*sin(_elapsedTime*50.0);
uv.y = 0.4*cos(_elapsedTime*50.0);
float m = tex2D(_maskTex, IN.uv_maskTex).r;
half3 n = tex2D(_noiseTex,(IN.uv_noiseTex*3.5) + uv).rgb;
half3 c = tex2D(_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex + (n.xy*0.005)).rgb;
float lum = dot(float3(0.30, 0.59, 0.11), c);
if (lum < _lu$$anonymous$$anceThreshold)
c *= _colorAmplification;
half3 visionColor = float3(0.1, 0.95, 0.2);
finalColor.rgb = (c + (n*0.2)) * visionColor * m;
o.Albedo = finalColor.rgb;
}
else
{
o.Albedo = tex2D(_$$anonymous$$ainTex, IN.uv_$$anonymous$$ainTex).rgb;
// o.Emission = half4(.5,.5,.5,1);
}
}
ENDCG
}
FallBack "Diffuse"
}
This fixed my issues with a desktop build. I was getting a black screen when I did a standalone build, but in the editor my shader worked fine. With this intermediary RT it fixed the problem completely. Thank you!
Your answer

Follow this Question
Related Questions
Save a texture after a pass in shader 0 Answers
dynamic hole in layer / texture / camera 0 Answers
Blit isn't writing to render texture 1 Answer
Multiple Blit problem 2 Answers
Blit into Texture2DArray slice not working in WebGL 0 Answers