HDRP is erroneously rendering shadows for transparent particles

I have a bunch of particle system-based VFX in a game, often several particle systems nested within each VFX prefab. According to the tooltip for ParticleSystemRenderer.shadowCastingMode, particles with transparent materials aren’t supposed to cast shadows regardless of what ParticleSystemRenderer.shadowCastingMode is set to. But they seem to - we’ve got fog in a lot of our scenes and the big blocky shadows look really bad. Setting shadowCastingMode to Off fixes it. But I’m guessing the shadows started showing up after upgrading to HDRP because shadowCastingMode isn’t consistently set to off.

So, first thing, I guess this is a bug report: HDRP renders shadows for transparent materials.

Second thing, we have a lot of these VFX, enough to where manually setting that value everywhere would take a while. I’ve written an editor script to process prefabs and scene gameobjects to set shadowCastingMode to Off. It’s able to open up the prefab for editing, determine the current value of shadowCastingMode, and set it, but the changes aren’t being saved back to the prefab. Any ideas?

Here’s the editor script code. I’ve tried using both SerializedObject syntax for editing the ParticleSystemRender component (shown below), and also just setting the property directly. Neither works for prefab assets, but setting it directly works for gameobjects in a scene.

Thanks in advance!

	private void OnGUI()
	{
		if (GUILayout.Button("Grab Selection"))
		{
			SetSelection(Selection.objects);
		}
		int prefabAssetCount = 0;
		int sceneGOCount = 0;
		foreach (GameObject go in selectedGOs)
		{
			if (go != null)
			{
				if (IsSceneGO(go))
				{
					sceneGOCount++;
				}
				else if (IsPrefabAsset(go))
				{
					prefabAssetCount++;
				}
			}
		}
		GUILayout.Label("GameObjects Selected: " + selectedGOs.Count);
		GUILayout.Label("Prefab Assets Selected: " + prefabAssetCount);
		GUILayout.Label("Scene GameObjects Selected: " + sceneGOCount);
		if (GUILayout.Button("Turn Off Shadows"))
		{
			BatchProcessSelection(selectedGOs, TurnOffShadows);
		}
	}

	private void BatchProcessSelection(List<GameObject> prefabBatch, ProcessorDelegate process)
	{
		foreach (GameObject go in prefabBatch)
		{
			if (go != null)
			{
				if (IsPrefabAsset(go))
				{
					Debug.Log("Editing prefab: " + go.name);
					string assetPath = AssetDatabase.GetAssetPath(go);
					using (var editScope = new PrefabUtility.EditPrefabContentsScope(assetPath))
					{
						ProcessGameObject(go, process);
					}
					return;
				}
				else if (IsSceneGO(go))
				{
					Debug.Log("Editing Scene GameObject: " + go.name);
					ProcessGameObject(go, process);
					return;
				}
			}
		}
	}

	private void ProcessGameObject(GameObject go, ProcessorDelegate process)
	{
		process(go);
		foreach (Transform t in go.transform)
		{
			if (!PrefabUtility.IsOutermostPrefabInstanceRoot(go))	// skip nested prefabs
			{
				ProcessGameObject(t.gameObject, process);
			}
		}
	}

	private void TurnOffShadows(GameObject go)
	{
		ParticleSystem ps = go.GetComponent<ParticleSystem>();
		if (ps != null)
		{
			Debug.Log("Particle System found on: " + go.name);
			ParticleSystemRenderer renderer = ps.GetComponent<ParticleSystemRenderer>();
			if (renderer != null)
			{
				Debug.Log("Initial shadow status: " + renderer.shadowCastingMode.ToString());
				if (renderer.shadowCastingMode != UnityEngine.Rendering.ShadowCastingMode.Off)
				{
					renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
/*					SerializedObject rObj = new SerializedObject(renderer);
					SerializedProperty scmProp = rObj.FindProperty("shadowCastingMode");
					if (scmProp != null)
					{
						Debug.Log("shadowCastingMode property found.");
						scmProp.intValue = (int)UnityEngine.Rendering.ShadowCastingMode.Off;
						rObj.ApplyModifiedProperties();
					} */
				}
			}
		}
	}

	bool IsPrefabAsset(GameObject go) { return AssetDatabase.IsMainAsset(go) && PrefabUtility.IsPartOfAnyPrefab(go); }
	bool IsSceneGO(GameObject go) { return !AssetDatabase.IsMainAsset(go) && !PrefabUtility.IsPartOfAnyPrefab(go); }