Difference between revisions of "Unity Products:Amplify Shader Editor/Tips Tricks and Known Issues"

From Amplify Creations Wiki
Jump to: navigation, search
(Tips and Tricks)
(Water on the PS4)
Line 53: Line 53:
Original post:
===== Accessing Depth Data on Post-Processing stack =====
===== Accessing Depth Data on Post-Processing stack =====

Revision as of 18:32, 7 November 2019

Product Page - Included Shaders - Manual - Shader Functions - Tutorials - API - Shader Templates - Scriptable Rendering Pipeline - Nodes - Community Nodes

Tips,Tricks and Known Issues

Tips and Tricks

Baked Lightmaps on Lightweight

Besides shader must having the _EMISSION flag turned on and meta pass, the material must also be set to be generating emissive light from baked light maps.

using UnityEngine;

public class SetEmissionMaterialKeywords : MonoBehaviour
	public Material EmissiveMaterial;

	private void Update()
		EmissiveMaterial.globalIlluminationFlags &= MaterialGlobalIlluminationFlags.AnyEmissive;
		EmissiveMaterial.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.BakedEmissive;
		EmissiveMaterial.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.RealtimeEmissive;
		EmissiveMaterial.EnableKeyword( "_EMISSION" );

Water on the PS4

Hi Vincent, so it happens that I do have an idea of what that is, simply because we had the same issue in our game and I spend a few days trying everything that made sense until I finally figured out the real issue.

For some reason I can't explain (I haven't found any information on this in unity docs or forums, nor at sony dev forums) the depth buffer doesn't seem to work exactly the same as in a PC build. And this is important because what you are seeing is either the "depth fade" node or a calculation with "screen depth" node failing, both of which use the depth buffer. They fail because when they run they are supposed to sample the depth buffer in order to do the depth coloring effect, however you also want your shader to write to depth so it intersects with your characters and objects, this usually done by setting your shader at a later Queue like transparent but leaving the depth writing ON, but by having these together it seems the depth buffer is not available or it can't figure out whether it's own depth contributes to the buffer on not. Usually it is the case that transparent objects do not go to the depth buffer but in PS4 they do (and btw nintendo switch has a similar issue so if you are planning on that be warned).

In our case we solved it by turning the depth writing OFF in the water shader while setting it to Opaque. Doing this will visually fix the artifacts but it will also ruin the intersection with other objects, they will simply float on top. We solved this last part by creating a second shader that only writes to the depth buffer (ColorMask 0) and does that at a later Queue, AlphaTest+49 (just before transparent). In the water object we added two materials to the material list, one for each shader with the "depthonly" shader on the second place in the list. This solution is not perfect, you'll have two draw calls for the water instead of one (not a big deal since one isn't heavy), the biggest issue is that if you have different water bodies that can be seen at different heights on top of each other it might not know the order of rendering and you may end up with something that was supposed to be rendered below being rendered above, but this never happens in our game so it was fine with us. You could probably fix this by having different water shaders in different render queues.

The real final solution would be to manually resolve the depth buffer at a specific stage, with that you could guarantee to work the same for all platforms. This seems far more complex, specially for legacy shaders, in SRP this seems to be somewhat trivial. This dirty hack did it for us.

The second shader was not create in ASE, here's the full shader, nothing special, just rendering the depth

Shader "WaterDepthOnly"
        Tags{ "RenderType" = "Opaque"  "Queue" = "AlphaTest+49" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True" "DisableBatching" = "True" }
        Cull Back
            ColorMask 0
            ZWrite On

Original post: https://forum.unity.com/threads/best-tool-asset-store-award-amplify-shader-editor-node-based-shader-creation-tool.430959/page-99#post-4905377

Accessing Depth Data on Post-Processing stack

Depth is only sampled correctly if the PostProcessEvent is set to BeforeTransparent, in the post processing script and for both _MainTex and _CameraDepthTexture, the Screen Position is connected to the UV port.


Accessing depth data on unlit scene

If a user needs to access values from the depth buffer on an unlit scene ( without any lights ), the DepthTextureMode.Depth must be manually set over the camera (Camera.main.depthTextureMode). This is needed since no shadow caster passes are called because without lighting there are no shadows.

Supplying correct derivatives on transformed UVS

When modifying uvs and then using it on texture fetches, incorrect uv derivatives are calculated fetching some values from incorrect mips. This results into artifacts that resembles seams. In order to fix, just apply DDX and DDY over the original UVS and use them on the texture fetch.

Shadow on Transparent Objects (Surface)

Our surface shader adds a custom shadow caster when on transparent blend mode which uses the alpha value on the shadow itself.
In order for transparency not affect shadows, simply place a Static Switch using the UNITY_PASS_SHADOWCASTER keyword over the Opacity port and set its True port to 1.
This way it forces always Alpha to 1 on the shadow caster pass.

Render Mode on Point Lights
  • Auto: Unity decides for each light if its calculated by vertex or by pixel
  • Important: Light is always rendered per pixel
  • Not Important: Light is always rendered per pixel

Special Considerations for Not Important Lights

Keyword POINT and _WorldSpaceLightPos0.w are not defined, so they can't be used when using Per Vertex point lights. Unity only does per vertex lighting over point lights, directional lighting is always done per pixel. So the VERTEXLIGHT_ON can be used to detect if a certain vertex is being affected by a per vertex point light. It is really important to take into account that VERTEXLIGHT_ON keyword is only defined over the vertex function so, if you need to use that information over the fragment, you'll need to pass that information from the vertex to the fragment via an interpolator.

GBuffer Contents

All deferred GBuffer contents can be accessed via the global textures below.

  • half4 gbuffer0 = tex2D (_CameraGBufferTexture0, uv); // Diffuse RGB, Occlusion A
  • half4 gbuffer1 = tex2D (_CameraGBufferTexture1, uv); // Specular RGB, Smoothness A
  • half4 gbuffer2 = tex2D (_CameraGBufferTexture2, uv); // Normal RGB

Uvs must be screen space position.

Global Array
  • Arrays in shaders cannot be indexed by a property but only constants. If a user connects p.e. a Float node as a property into the Index port of a Global Array node, it won't work.
  • SourceThe first time that you set either a local or global array, Unity fixes the size of the array itself. For instance, if you initialize an array defined in the shader as uniform float _Array[10]; with a C# array defined as float[] array = new float[5];, you will not be able to set more than 5 elements to your array. Because of this and to avoid bugs, always initialize arrays with the maximum size allowed.
Code Comments
  • Add comments to specific parts of your shader using a Custom Expression in Call Mode.

Known Issues

Static Switch Enum

Static Switch enum mode is set to a max of 9 options due to a Unity limitation. Advert user that using this amount will increase the amount of keywords (which are limited ) and shader variants (which greatly increase compile time ) so it should be used with caution.

Huge Shader Compilation Times

Shader Features and Multi-Compile must be used with caution with Surface Shaders. Each surface shader goes through an intermediate process on which it transforms its code into several vertex/ frag programs.
For each new Shader Feature and Multi-Compile option added the amount of shader variants will exponentially increase into a point where the conversion process from surface to vertex frag will fail resulting in errors like:
Assertion failed: Shader Compiler Socket Exception: Terminating shader compiler process, 0 retries left
As mentioned this only happens with surface shaders so using Shader Features and Multi-Compile directly on a vertex/frag shader won't result on this mentioned issue.

Light Cookies
World Normal

Jira Ticket Using World Normal node on the vertex function generates issues when working with Light cookies. It internally calls the Unity native UnityObjectToWorldNormal(...) which seems to be incompatible with how light cookies are calculated and applied over the shadow caster. One possible workaround is to do the object to world transform by hand.


Jira Ticket There's a issue with how Unity generates the code which copies the cookies information from the vertex to the fragment program. Somehow cookie information is being incorrectly sent/written and is being taken into account as an alpha value. This behavior can be prevented by setting the Blend Mode to Transparent. This mode internally forces the Alpha:Fade surface option to be written into the shader which then correctly passes/writes the light cookie.

GPU Instancing
  • GPU Instancing does not work correctly with Deferred rendering path on Metal as instanced values seems to overlap each other
    • Reported issues refer to this be happening on Intel HD cards
    • There is a similar issue reported by us Instanced properties don't have correct value on surface shader on macOS which can be tracked here.

Both these cylinders have the same material applied to them, thus incorrectly showing different results

  • Can't animate material properties.
Unity Internal Time/Timer
  • Unity internal time values starts to have precision errors after a hour or so of running the application
    • Although Time node is affected by this issue, some other time nodes like Sin Time aren't
Depth Buffer and Consoles

Depth buffer is written in different stages when working with either consoles or PC.
On PC this buffer is written after all opaques are drawn as this doesn't happen on consoles( not sure what which stage though).
What this means is that nodes like Depth Fade won't work under a normal context as when the fragment is being rendered it is also written on the depth buffer (even when on the Transparent Queue).
The solution comes by separating the shader into two, and adding both materials into the mesh renderer material queue.
The first one must have ZWrite Off and its Render Queue must be under the Geometry range of values.
This shader will be the main one where you do your grab pass, apply refraction, etc.
The second one only needs to write on the ZBuffer ( ZWrite On ) thus its color mask should by set to all channels so no color is written (ColorMask 0). Place its render queue at the very end of the Alpha Cutout (AlphaTest+49) range so it catches all the objects it needs to catch.

Shader "DepthOnly"
		Tags{ "RenderType" = "Opaque"  "Queue" = "AlphaTest+49" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True" "DisableBatching" = "True" }
		Cull Back
			ColorMask 0
			ZWrite On