using UnityEngine; public partial class MeshPainter { // --- Backend selection / switching --- private void SetupBackend(bool gpu, Color32[][] canonical) { // SetupGpu returns false if the shaders are missing and it fell back to CPU; honor // the real outcome so _gpuActive never claims GPU while _gpu is null (would NRE on // the next SwitchBackend / paint). if (gpu) { _gpuActive = SetupGpu(canonical); } else { SetupCpu(canonical); _gpuActive = false; } } /// Switches the backend at runtime, carrying over all painted maps. private void SwitchBackend(bool toGpu) { var canonical = new Color32[MAP_COUNT][]; for (int mi = 0; mi < MAP_COUNT; mi++) canonical[mi] = ReadCanonical(mi); if (_gpuActive) TeardownGpu(); else TeardownCpu(); SetupBackend(toGpu, canonical); _hasLastScreen = false; Debug.Log($"[MeshPainter] Backend switched -> {(toGpu ? "GPU" : "CPU")} painting.", this); } /// Reads a map from the active backend into canonical (material) layout. private Color32[] ReadCanonical(int mi) { if (_gpuActive) { var gm = _gpu[mi]; // MSO: read the packed final mask RT (R=metallic, G=occlusion, A=smoothness). // Others: the display RT. The mask map is linear data; color maps read sRGB. if (mi == MAP_MSO) return ReadRtPixels(gm.final, linear: true); return ReadRtPixels(gm.display, linear: MapIsLinear(mi)); } return (Color32[])_cpu[mi].pixels.Clone(); } private static bool MapIsLinear(int mi) => mi == MAP_MSO; private string[] MapProps(int mi) { switch (mi) { case MAP_ALBEDO: return new[] { "_BaseMap", "_MainTex" }; // One mask map drives both URP slots: _MetallicGlossMap (R/A) + _OcclusionMap (G). case MAP_MSO: return new[] { "_MetallicGlossMap", "_OcclusionMap" }; default: return new[] { "_EmissionMap" }; } } private void AssignMapTexture(int mi, Texture tex) { if (!_materialInstance) return; foreach (var p in MapProps(mi)) { int id = Shader.PropertyToID(p); if (_materialInstance.HasProperty(id)) _materialInstance.SetTexture(id, tex); } } }