Search Issue Tracker
By Design
Votes
0
Found in
2019.3.3f1
2019.4
2020.1
2020.2
Issue ID
1252634
Regression
No
Terrain with a custom shader receives a black tint while the Paint Texture tool is actively used
How to reproduce:
1. Open the attached project named "Case_1252634"
2. Open the Terrain Scene located in MicroSplat/Core/Examples/Scene
3. Select the Paint Texture tool and start painting the Terrain
4. Observe the Scene or Game window
Expected result: The Tile is rendered normally with no artifacts while painting
Actual result: The Terrain Tile receives a black tint while painting
Reproducible with: 2019.4.0f1, 2020.1.0b11, 2020.2.0a13
Could not test with: 2018.4.23f1(Project crashing upon launch)
Notes:
1. Graphics APIs tested: D3D11, D3D12, Vulkan
Add comment
All about bugs
View bugs we have successfully reproduced, and vote for the bugs you want to see fixed most urgently.
Latest issues
- Articulation Body with 'Revolute' Joint Type has erratic behavior when Upper Limit is set to above 360
- WebGL Player fails to render Scene when Terrain with Detail Mesh is added and WebGPU Graphics API is used
- Inconsistent errors are logged when different types are passed into the Query "Q<>" method in UIToolkit and the ancestor VisualElement is null
- Crash on GetMaterialPropertyByIndex when opening a specific Scene
- Discrepancies in the styling are present when using a TSS file instead of a USS file in custom EditorWindow
Resolution Note (2020.2.X):
Alright, tentatively resolving this one again.
For some reason (not yet discovered) calling the Unity internal function 'WorldNormalVector' wrappped in a defined(UNITY_INSTANCING_ENABLED) doesn't yield a shader parsing that adds surfNeedsTangentSpace (which would populate the INTERNAL_DATA internalSurfaceTtoW0). The results is that 'WorldNormalVector' returns zero (which later causes a nan in:
i.viewDir = normalize(mul( t2w, (_WorldSpaceCameraPos - i.worldPos)));) since all three tangent vectors are're defined as '0' by Unity.
There is a workaround which is aligned with what MicroSplats does already: that is to explicitly use i.worldNormal _somwhere_ (which then causes the INTERNAL_DATA to be available)
For example:
l.Albedo *= saturate(normalize(i.viewDir + i.worldPos + i.worldNormal) + 9999);
One thing I found out during this investigation is that i.viewDir is calculated by Unity as:
half3 _unity_tbn_0 = IN.tSpace0.xyz;
half3 _unity_tbn_1 = IN.tSpace1.xyz;
half3 _unity_tbn_2 = IN.tSpace2.xyz;
float3 worldPos = float3 ( IN.tSpace0.w , IN.tSpace1.w , IN.tSpace2.w ) ;
float3 worldViewDir = normalize ( UnityWorldSpaceViewDir ( worldPos ) ) ;
float3 viewDir = _unity_tbn_0 * worldViewDir.x + _unity_tbn_1 * worldViewDir.y + _unity_tbn_2 * worldViewDir.z ;
surfIN.viewDir = viewDir;
Where tSpace* are populated from the VS as:
o . tSpace0 = float4 ( worldTangent . x , worldBinormal . x , worldNormal . x , worldPos . x ) ;
o . tSpace1 = float4 ( worldTangent . y , worldBinormal . y , worldNormal . y , worldPos . y ) ;
o . tSpace2 = float4 ( worldTangent . z , worldBinormal . z , worldNormal . z , worldPos . z ) ;
I noticed that the MicroSplat/Example shader's path for UNITY_INSTANCING_ENABLED sets the normal as float3(0,1,0) which is then used in pixel shader _before_ the custom surface function is called to update the normal data. One thing I tried was to populate to read and feed the normal data from the vertex shader and that seemed to give a valid i.viewDir value in MicroSplatLayer SurfImpl (so theoretically no need to recalculate it). It could be something to investigate further (I noticed some weird shadows when I tried it so would need to investigate why that is).
Hope this unblocks Jason, I will follow up with the core team to see if there would be a more elegant way to force the WorldNormalVector function to be valid without having to tickle i.worldNormal
Cheers