private static Material CreateFallbackMaterial(Material originalMaterial, VRC.Core.APIUser user) { #if VRC_CLIENT Material fallbackMaterial; Color trustCol = user != null ? (Color)GetTrustLevelColor(user) : Color.white; string displayName = user != null ? user.displayName : "localUser"; if (originalMaterial == null || originalMaterial.shader == null) { fallbackMaterial = VRC.Core.AssetManagement.CreateMatCap(trustCol * 0.8f + new Color(0.2f, 0.2f, 0.2f)); fallbackMaterial.name = string.Format("MC_{0}_{1}", fallbackMaterial.shader.name, displayName); } else { var safeShader = VRC.Core.AssetManagement.GetSafeShader(originalMaterial.shader.name); if (safeShader == null) { fallbackMaterial = VRC.Core.AssetManagement.CreateSafeFallbackMaterial(originalMaterial, trustCol * 0.8f + new Color(0.2f, 0.2f, 0.2f)); fallbackMaterial.name = string.Format("FB_{0}_{1}_{2}", fallbackMaterial.shader.name, displayName, originalMaterial.name); } else { //Debug.Log("<color=cyan>*** using safe internal fallback for shader:"+ safeShader.name + "</color>"); fallbackMaterial = new Material(safeShader); if (safeShader.name == "Standard" || safeShader.name == "Standard (Specular setup)") { VRC.Core.AssetManagement.SetupBlendMode(fallbackMaterial); } fallbackMaterial.CopyPropertiesFromMaterial(originalMaterial); fallbackMaterial.name = string.Format("INT_{0}_{1}_{2}", fallbackMaterial.shader.name, displayName, originalMaterial.name); } } return(fallbackMaterial); #else // we are in sdk, this is not meaningful anyway return(new Material(Shader.Find("Standard"))); #endif }
static Material CreateFallbackMaterial(Material mtl, VRC.Core.APIUser user) { #if VRC_CLIENT Material newMtl; Color trustCol = (Color)GetTrustLevelColor(user); if (mtl != null) { var safeShader = VRC.Core.AssetManagement.GetSafeShader(mtl.shader.name); if (safeShader == null) { newMtl = VRC.Core.AssetManagement.CreateSafeFallbackMaterial(mtl, trustCol * 0.8f + new Color(0.2f, 0.2f, 0.2f)); newMtl.name = "FB_" + mtl.shader.name; } else { //Debug.Log("<color=cyan>*** using safe internal fallback for shader:"+ safeShader.name + "</color>"); newMtl = new Material(safeShader); if (safeShader.name == "Standard" || safeShader.name == "Standard (Specular setup)") { VRC.Core.AssetManagement.SetupBlendMode(newMtl); } newMtl.CopyPropertiesFromMaterial(mtl); newMtl.name = "INT_" + mtl.shader.name; } } else { newMtl = VRC.Core.AssetManagement.CreateMatCap(trustCol * 0.8f + new Color(0.2f, 0.2f, 0.2f)); newMtl.name = "FB?_"; } return(newMtl); #else // we are in sdk, this is not meaningful anyway return(new Material(Shader.Find("Standard"))); #endif }
static Color32 GetTrustLevelColor(VRC.Core.APIUser user) { #if VRC_CLIENT Color32 color = new Color32(255, 255, 255, 255); if (user == null) { return(color); } if (user == VRC.Core.APIUser.CurrentUser) { color = VRCInputManager.showSocialRank ? VRCPlayer.GetColorForSocialRank(user) : VRCPlayer.GetDefaultNameplateColor(user, user.hasVIPAccess); } else { color = VRCPlayer.ShouldShowSocialRank(user) ? VRCPlayer.GetColorForSocialRank(user) : VRCPlayer.GetDefaultNameplateColor(user, user.hasVIPAccess); } return(color); #else // we are in sdk, this is not meaningful anyway return((Color32)Color.grey); #endif }
public static void RestoreShaders(VRC.Core.APIUser user, HashSet <Renderer> avatarRenderers, Dictionary <Material, Material> materialSwaps) { foreach (Renderer r in avatarRenderers) { Material[] materials = new Material[r.sharedMaterials.Length]; for (int i = 0; i < r.sharedMaterials.Length; ++i) { if (r.sharedMaterials[i] == null) { // create a temporary shader while loading materials[i] = CreateFallbackMaterial(null, user); } else if (materialSwaps.ContainsKey(r.sharedMaterials[i])) { materials[i] = materialSwaps[r.sharedMaterials[i]]; } else { materials[i] = r.sharedMaterials[i]; } } r.sharedMaterials = materials; } }
public static void ReplaceShadersRealtime(VRC.Core.APIUser user, HashSet <Renderer> avatarRenderers, ref Dictionary <Material, Material> materialSwaps) { ReplaceShaders(user, avatarRenderers, ref materialSwaps, false); }
public static void ReplaceShadersRealtime(VRC.Core.APIUser user, IEnumerable <Renderer> avatarRenderers, FallbackMaterialCache fallbackMaterialCache, bool debug = false) { ReplaceShaders(user, avatarRenderers, fallbackMaterialCache, debug); }
public static void SetupShaderReplace(VRC.Core.APIUser user, GameObject currentAvatar, HashSet <Renderer> avatarRenderers) { avatarRenderers.Clear(); avatarRenderers.UnionWith(currentAvatar.GetComponentsInChildren <SkinnedMeshRenderer>(true)); avatarRenderers.UnionWith(currentAvatar.GetComponentsInChildren <MeshRenderer>(true)); }
public static void ReplaceShaders(VRC.Core.APIUser user, List <Renderer> avatarRenderers, FallbackMaterialCache fallbackMaterialCache, bool debug = true) { foreach (Renderer avatarRenderer in avatarRenderers) { if (avatarRenderer == null) { continue; } avatarRenderer.GetSharedMaterials(_replaceShadersWorkingList); bool materialNeedsReplacement = false; foreach (Material material in _replaceShadersWorkingList) { // A fallback material exists and is being used. if (fallbackMaterialCache.TryGetFallbackMaterial(material, out Material fallbackMaterial) && material == fallbackMaterial) { continue; } materialNeedsReplacement = true; break; } if (!materialNeedsReplacement) { return; } Material[] avatarRendererSharedMaterials = avatarRenderer.sharedMaterials; for (int i = 0; i < avatarRendererSharedMaterials.Length; ++i) { Material currentMaterial = avatarRendererSharedMaterials[i]; if (currentMaterial == null) { continue; } if (fallbackMaterialCache.TryGetFallbackMaterial(currentMaterial, out Material fallbackMaterial)) { if (debug) { Debug.Log($"<color=cyan>*** Using existing fallback: '{fallbackMaterial.shader.name}' </color>"); } } else { // The current material is not in our safe list so create a fallback. fallbackMaterial = CreateFallbackMaterial(currentMaterial, user); // Map the current material to the fallback and the fallback to itself. fallbackMaterialCache.AddFallbackMaterial(currentMaterial, fallbackMaterial); fallbackMaterialCache.AddFallbackMaterial(fallbackMaterial, fallbackMaterial); if (debug) { Debug.Log($"<color=cyan>*** Creating new fallback: '{fallbackMaterial.shader.name}' </color>"); } } avatarRendererSharedMaterials[i] = fallbackMaterial; } avatarRenderer.sharedMaterials = avatarRendererSharedMaterials; } }
public static void ReplaceShaders(VRC.Core.APIUser user, List <Renderer> avatarRenderers, FallbackMaterialCache fallbackMaterialCache, bool debug = false) { foreach (Renderer avatarRenderer in avatarRenderers) { if (avatarRenderer == null) { continue; } avatarRenderer.GetSharedMaterials(_replaceShadersWorkingList); bool anyReplaced = false; for (int i = 0; i < _replaceShadersWorkingList.Count; ++i) { Material currentMaterial = _replaceShadersWorkingList[i]; if (currentMaterial == null) { continue; } // Check if the material has a cached fallback material if not then create a new one. if (!fallbackMaterialCache.TryGetFallbackMaterial(currentMaterial, out Material fallbackMaterial)) { fallbackMaterial = CreateFallbackMaterial(currentMaterial, user); // Map the current material to the fallback and the fallback to itself. fallbackMaterialCache.AddFallbackMaterial(currentMaterial, fallbackMaterial); fallbackMaterialCache.AddFallbackMaterial(fallbackMaterial, fallbackMaterial); if (debug) { Debug.Log($"<color=cyan>*** Creating new fallback: '{fallbackMaterial.shader.name}' </color>"); } if (fallbackMaterial == currentMaterial) { continue; } _replaceShadersWorkingList[i] = fallbackMaterial; anyReplaced = true; continue; } // If the material is the fallback then we don't need to change it. if (currentMaterial == fallbackMaterial) { continue; } if (debug) { Debug.Log($"<color=cyan>*** Using existing fallback: '{fallbackMaterial.shader.name}' </color>"); } _replaceShadersWorkingList[i] = fallbackMaterial; anyReplaced = true; } if (anyReplaced) { avatarRenderer.sharedMaterials = _replaceShadersWorkingList.ToArray(); } } }