Quick answer: Set both QualitySettings.renderPipeline and GraphicsSettings.defaultRenderPipeline, then reload the scene if materials don’t rebind.
A graphics-options screen lets the player swap between Low and High URP assets. Setting GraphicsSettings.defaultRenderPipeline = highAsset at runtime does nothing visibly — the previous asset stays active.
Two Levels of Pipeline Assignment
Unity reads the active pipeline from two places:
- QualitySettings.renderPipeline — per-quality-level override. Checked first.
- GraphicsSettings.defaultRenderPipeline — fallback when Quality has no override.
If the current quality level has a non-null QualitySettings.renderPipeline, setting GraphicsSettings.defaultRenderPipeline doesn’t affect the runtime — the Quality value takes precedence.
The Fix
using UnityEngine.Rendering;
public class PipelineSwitcher : MonoBehaviour
{
[SerializeField] RenderPipelineAsset lowAsset;
[SerializeField] RenderPipelineAsset highAsset;
public void SetHighQuality() {
QualitySettings.renderPipeline = highAsset;
GraphicsSettings.defaultRenderPipeline = highAsset;
StartCoroutine(RefreshShaders());
}
IEnumerator RefreshShaders() {
yield return null;
Resources.UnloadUnusedAssets();
}
}
Both fields are updated. UnloadUnusedAssets after a frame nudges Unity to rebind materials against the new pipeline.
Quality-Level Driven Switching
For projects using the standard Quality system:
// Each quality level has its own RP asset configured in Project Settings
QualitySettings.SetQualityLevel(3, applyExpensiveChanges: true);
Switching quality level activates the matching pipeline asset automatically. Cleaner than manual assignment if your project follows the standard Quality ↔ Asset mapping.
When a Scene Reload Helps
Some swaps don’t fully take effect until materials rebind. Reloading the scene forces a clean rebind:
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
Costly (scene reset, asset reload) but bulletproof.
Diagnosing
Print the current pipeline:
Debug.Log($"Quality: {QualitySettings.renderPipeline?.name}");
Debug.Log($"Default: {GraphicsSettings.defaultRenderPipeline?.name}");
Debug.Log($"Current: {GraphicsSettings.currentRenderPipeline?.name}");
currentRenderPipeline is the active one. If Current matches what you intended but visuals look wrong, materials are caching the old shader variants — reload the scene.
Verifying
Swap quality at runtime. currentRenderPipeline should show the new asset name. Visual changes (different shadow quality, post-processing) should be visible.
“Quality wins over Graphics. Set both, or your runtime swap doesn’t reach the renderer.”
For per-platform settings, configure the Quality Levels in Project Settings rather than scripting — cleaner authoring, less runtime risk.