URP Shader works in Editor but not in builds (Quest 2)

Hi all,

I’ve been scratching my head on this for a few days now but couldn’t figure out what the issue is. I have a special line renderer (below). It is working perfectly fine in Editor (both Scene and Game view) but it doesn’t seem to render anything in a build (not even pink). I don’t see any errors on Logcat. Hopefully someone here would be able to point me to the right direction.

Extra context: The shader works fine in Unity 2020.1.17f1 (both build and Editor) but stopped working when I upgraded to 2021.2.8f1.

I am running Unity 2021.2.8f1 with these packages:

{
"dependencies": {
"com.unity.addressables": "1.19.15",
"com.unity.collab-proxy": "1.15.7",
"com.unity.ide.rider": "3.0.9",
"com.unity.ide.visualstudio": "2.0.12",
"com.unity.ide.vscode": "1.2.4",
"com.unity.mobile.android-logcat": "1.2.3",
"com.unity.render-pipelines.universal": "12.1.3",
"com.unity.test-framework": "1.1.29",
"com.unity.textmeshpro": "3.0.6",
"com.unity.timeline": "1.6.3",
"com.unity.ugui": "1.0.0",
"com.unity.xr.interaction.toolkit": "2.0.0-pre.7",
"com.unity.xr.management": "4.2.0",
"com.unity.xr.oculus": "1.11.0",
"com.unity.xr.openvr.standalone": "2.0.5",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.assetbundle": "1.0.0",
"com.unity.modules.audio": "1.0.0",
"com.unity.modules.cloth": "1.0.0",
"com.unity.modules.director": "1.0.0",
"com.unity.modules.imageconversion": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.physics2d": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.terrain": "1.0.0",
"com.unity.modules.terrainphysics": "1.0.0",
"com.unity.modules.tilemap": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.umbra": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.unitywebrequestassetbundle": "1.0.0",
"com.unity.modules.unitywebrequestaudio": "1.0.0",
"com.unity.modules.unitywebrequesttexture": "1.0.0",
"com.unity.modules.unitywebrequestwww": "1.0.0",
"com.unity.modules.vehicles": "1.0.0",
"com.unity.modules.video": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.wind": "1.0.0",
"com.unity.modules.xr": "1.0.0"
}
}

Shader:

{
Properties
{
_MainTex("Albedo (RGB)", 2D) = "white" {}
}

SubShader
{
Tags {"RenderPipeline" = "UniversalPipeline" "RenderType" = "Opaque" "Queue" = "Geometry"}

HLSLINCLUDE

#pragma multi_compile_instancing

#pragma prefer_hlslcc gles
#pragma exclude_renderers d3d11_9x

// In regular graphics shaders the compute buffer support requires minimum target of 4.5
#pragma target 4.5

#pragma vertex vert
#pragma fragment frag

#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"

ENDHLSL

Pass
{
Name "Forward"
Tags { "LightMode" = "UniversalForward" }

Blend One Zero, One Zero
ZWrite On
ZTest LEqual
Offset 0 , 0
ColorMask RGBA

HLSLPROGRAM

sampler2D _MainTex;
float4x4 modelXForm;
float lineWidth;

#if SHADER_TARGET >= 45
StructuredBuffer<float3> aPositionBuffer;
StructuredBuffer<float3> bPositionBuffer;
StructuredBuffer<float3> colorBuffer;
#endif

struct VertexData
{
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
float4 texcoord3 : TEXCOORD3;
half4 color : COLOR;

UNITY_VERTEX_INPUT_INSTANCE_ID
};

struct VertexOutput
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float4 color : TEXCOORD1;

UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};

VertexOutput vert(VertexData IN, uint instanceID : SV_InstanceID)
{
#if SHADER_TARGET >= 45
float3 dataA = aPositionBuffer[instanceID];
float3 dataB = bPositionBuffer[instanceID];
float3 dataColor = colorBuffer[instanceID];
#else
float3 dataA = 0;
float3 dataB = 0;
float3 dataColor = 0;
#endif

float3 xyz = IN.vertex.xyz;
float isPoint = 0.0;

// We place the instance position at point 1
float3 instancePosition = dataA;
float r = lineWidth;

// TODO comment on how this split works, what it does
// We render an instanced mesh that is two quads, one at z = 1
// The first quad we use to draw the segment between two points,
// and the second quad we use to draw the circle at the first point
if (xyz.z < 0.5)
{
// Drawing the segment
if (IN.texcoord.y > .5)
{
// The top two coordinates we place at point 2
instancePosition = dataB;
}

// Grab the vector direction between the points
float2 diff = normalize(dataB.xy - dataA.xy);

// Take the normal to that direction
float2 n = float2(-diff.y, diff.x);

// Add a scaled version of that normal in either
// direction from the instance points 1 and 2 to
// give the segment thickness
if (IN.texcoord.x > 0)
{
xyz = float3(-r * n, 0);
}
else
{
xyz = float3(r * n, 0);
}
}
else
{
// We store that this quad should be treated as a point in the fragment shader
isPoint = 1;
// We reset the z value we actually render the quad at to 0 (instead of 1)
xyz.z = 0;
// We scale the quad by the width
xyz *= r;
}

float3 worldPosition = instancePosition + xyz;
float3 worldNormal = IN.normal;

VertexOutput OUT;
// We use the passed in model world matrix to multiply against the view projection matrices
OUT.pos = mul(UNITY_MATRIX_VP, mul(modelXForm, float4(worldPosition, 1.0f)));
// We pass along our UVs (needed for circle quads)
OUT.uv = IN.texcoord.xy;
// We pass along our color with the w value specifying whether the quad is to be a circle
OUT.color = float4(dataColor, isPoint);

return OUT;
}

half4 frag(VertexOutput IN) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(IN);

// We use the .w component of color not for alpha as normally unused, but to
// store whether or not we treat this quad as a point (circle render)
if (IN.color.w > 0.0f)
{
// If this is the quad representing a point on the line,
// we use a radius check to see if we fill in the fragment.
// With uv values in the range [0,0] - [1,1] for a quad,
// if the radius^2 > 0.5^2 means we are outside the circle
float2 uv = IN.uv;
float dx = uv.x - 0.5f;
float dy = uv.y - 0.5f;
float d = dx * dx + dy * dy;

if (d > .25)
{
discard;
}
}

half4 OUT = half4(IN.color.xyz, 1.0f);
return OUT;
}

ENDHLSL
}
}
}

I have the shader in Graphics settings “Always Included Shaders” and I am using OpenGLES3.

I’m absolutely out of ideas on what else I should try; any help is welcome.

Thanks in advance.

Hi!
Please try upgrading to .12f1 - it may fix your issue.

Upgraded to 2021.2.13f1 last night but the problem persists there as well.
It works back in 2020.1.17f1 (tried last night as well). But I’m really hoping to be able to use 2021.2.8f1 for a package I’m using.

In this case I would suggest to file a bug report.
Thank you!

Will do, thanks aleksandrk.

Just an update, the shader is actually working but it is not showing up on a render texture. No idea why that is, the render texture works fine in 2020.1.17f1.