Switch deferred rendering in player settings and use DX11.
Make two sphere (left, right on the picture).
Apply the built-in “Tessellation/Bumped Specular (smooth)” shader on the left sphere.
Apply the exact same shader like the “Tessellation/Bumped Specular (smooth)” shader to the right sphere, but write in the shader this parameter: “exclude_path:prepass”.
The problem is self explanatory. (tweak the smoothness settings to make the artifacts visible)
If I use this second shader on characters the artifacts always visible, no matter how I tweak the settings.
I would be really happy if anyone could help me.
Yes, unfortunately. Lost much time trying to find a workaround, to no avail.
It’s not tessellation specific, actually.
When deferred lighting is enabled unity seems to do an additional pass (shadow receiver? early-z?) that affects even objects that have forward only lighting model.
This pass is not affected by vertex displacement and pops-out resulting in visual artifacts.
Tried also bisecting the compiled surface shader to pinpoint the issue: the pass in question is NOT present.
What also seems to me the same issue happens with transparent (including cutout) forward-only shaders with deferred enabled.
Use at the tags the following: “Queue” = “Transparent-1” LINK
Be careful it might cause rendering issues. (e.g. something rendering in front/behind your model)
Use “Offset -1,-1” in the shader. LINK
It gives quite acceptable result from distance, maybe good for somebody.
I know these are not perfect solutions but better than nothing.
Unfortunately it doesn’t solve the issue, since the offending pass is NOT part of the shader itself, but something unity does when deferred lighting is active.
You can try it yourself with this shader. As you can see there’s only one pass and it should display the object in in red and translated by 0.1 in x axis.
With deferred lighting enabled the object itself renders as expected, including the shadows if you decomment the caster/receiver block, but there’s a second object beside it showing skybox color.
Shader "Custom/Displacement" {
Properties {
_Color ("Color", color) = (1,1,1,0)
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 300
Pass {
Name "Red"
Tags { "LightMode" = "Always" }
Fog {Mode Off}
ZWrite On ZTest LEqual Cull Off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma multi_compile_particles
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
};
struct v2f {
float4 vertex : POSITION;
};
v2f vert(appdata v) {
v.vertex.x += 0.1;
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
return o;
}
fixed4 frag (v2f i) : COLOR {
return fixed4(1, 0, 0, 1);
}
ENDCG
}
/*
// Pass to render object as a shadow caster
Pass {
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
Fog {Mode Off}
ZWrite On ZTest LEqual Cull Off
Offset 1, 1
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_shadowcaster
#pragma fragmentoption ARB_precision_hint_fastest
#pragma exclude_renderers d3d11_9x
#include "UnityCG.cginc"
struct v2f {
V2F_SHADOW_CASTER;
};
v2f vert( appdata_full v ) {
v.vertex.x += 0.1;
v2f o;
TRANSFER_SHADOW_CASTER(o)
return o;
}
float4 frag( v2f i ) : COLOR {
SHADOW_CASTER_FRAGMENT(i)
}
ENDCG
}
// Pass to render object as a shadow collector
Pass {
Name "ShadowCollector"
Tags { "LightMode" = "ShadowCollector" }
Fog {Mode Off}
ZWrite On ZTest LEqual
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#pragma exclude_renderers d3d11_9x
#pragma multi_compile_shadowcollector
#define SHADOW_COLLECTOR_PASS
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
};
struct v2f {
V2F_SHADOW_COLLECTOR;
};
v2f vert (appdata_full v) {
v.vertex.x += 0.1;
v2f o;
TRANSFER_SHADOW_COLLECTOR(o)
return o;
}
fixed4 frag (v2f i) : COLOR {
SHADOW_COLLECTOR_FRAGMENT(i)
}
ENDCG
}
*/
}
FallBack Off
}
Since Unity kinda states in documentation that forward and deferred can be mixed I consider this simpy a bug.
Just found a workaround inspired by Emptiness’ response, though I’m still testing.
Just render in Geometry+1!
Tags { "RenderType"="Geometry+1" }
Edit: forget what I said above. As you can see I mistook the tag. Though it works in transparent queue or with custom RenderType value as in the code above (“Geometry+1” is not a standard render type), but it has other consequences making the workaround pretty useless.
There are multiple target platforms in Unity for DirectX 11. d3d11_9x is used for Windows RT, and d3d11 is used for the desktop version of Windows. The distinction is made because Windows RT is used for ARM processors, in stead of x86 processors.
So when you exclude the d3d11_9x platform, it can still be compiled for ‘regular’ DX11.