Unity URP渲染管线动态修改材质球状态
最近工作过程中,有遇到需要动态修改模型材质球的情况,然后发现这点内置管线和URP还是有一些区别的,所以整理总结一下。
自定义结构体
我这里用到方法是创建一个自定义的结构体,结构体内写入对应的字段来存储材质球的各种属性,这里是我创建的一个结构体:
[System.Serializable]
//初始材质状态
public struct MaterialState
{// URP渲染模式public int surfaceType; // 表面类型(0-不透明 1-透明)public int blendMode; // 混合模式(1=Alpha混合,2=Premultiply等)public int renderFace; //渲染面 (0-双面 1-背面 2-正面)// 基础属性public Color albedoColor; // 基础颜色public Texture albedoMap; // 纹理贴图public string renderTypeTag; // 渲染类型标签public int renderQueue; // 渲染队列public CompareFunction zTest; // 深度测试模式public int zWrite; // 深度写入public MaterialGlobalIlluminationFlags globalIlluminationFlags;// URP PBR属性public float metallic; // 金属度 [0-1]public float smoothness; // 光滑度 [0-1]public Texture metallicSmoothnessMap;// 金属光滑度贴图//增强属性public Texture normalMap; //法线贴图public float normalStrength; //法线强度// 自发光属性(URP增强版)public bool isEmission; // 是否启用自发光public Color emissionColor; // 自发光颜色public float emissionIntensity; // 自发光强度public Texture emissionMap; // 自发光贴图public bool emissionUseGlobalIllumination; // 自发光是否影响全局光照// URP关键字状态public List<string> enabledKeywords; // 已启用的Shader关键字
}
保存材质球状态
Unity里动态保存或者修改材质球属性,都是通过调用Material类的API,通过关键字查找到材质球对应的属性,进行保存或修改。
初始化保存材质球方法:
public static MaterialState SaveMaterialState(Material mat){// 初始化材质状态结构体MaterialState state = new MaterialState();if (mat == null){Debug.LogError("尝试保存空材质的状态");return state;}if (mat.HasProperty("_Surface")){state.surfaceType = mat.GetInt("_Surface");}if (mat.HasProperty("_Blend")){state.blendMode = mat.GetInt("_Blend");}if (mat.HasProperty("_Cull")){Debug.Log("当前渲染面:" + mat.GetInt("_Cull"));state.renderFace = mat.GetInt("_Cull");}// 基础属性state.renderTypeTag = mat.GetTag("RenderType", false, "");state.renderQueue = mat.renderQueue;// 基础颜色和纹理(URP标准属性)state.albedoColor = mat.HasProperty("_BaseColor") ? mat.GetColor("_BaseColor") :(mat.HasProperty("_Color") ? mat.GetColor("_Color") : Color.white);state.albedoMap = mat.HasProperty("_BaseMap") ? mat.GetTexture("_BaseMap") :(mat.HasProperty("_MainTex") ? mat.GetTexture("_MainTex") : null);// 深度测试if (mat.HasProperty("_ZTest")){state.zTest = (CompareFunction)mat.GetInt("_ZTest");}if (mat.HasProperty("_ZWrite")){state.zWrite = mat.GetInt("_ZWrite");}// URP PBR属性state.metallic = mat.HasProperty("_Metallic") ? mat.GetFloat("_Metallic") : 0f;//金属度state.smoothness = mat.HasProperty("_Smoothness") ? mat.GetFloat("_Smoothness") :(mat.HasProperty("_Glossiness") ? mat.GetFloat("_Glossiness") : 0.5f);//光滑度state.metallicSmoothnessMap = mat.HasProperty("_MetallicGlossMap") ?mat.GetTexture("_MetallicGlossMap") : null;//增强属性state.normalMap = mat.HasProperty("_BumpMap") ? mat.GetTexture("_BumpMap") : null;state.normalStrength = mat.HasProperty("_BumpScale") ? mat.GetFloat("_BumpScale"):0;//自发光属性state.isEmission = mat.IsKeywordEnabled("_EMISSION");if (mat.HasProperty("_EmissionColor")){state.emissionColor = mat.GetColor("_EmissionColor");}if (mat.HasProperty("_EmissionIntensity")){state.emissionIntensity = mat.GetFloat("_EmissionIntensity");}else{// fallback: 使用颜色分量最大值state.emissionIntensity = state.emissionColor.maxColorComponent;}state.emissionMap = mat.HasProperty("_EmissionMap") ? mat.GetTexture("_EmissionMap") : null;state.emissionUseGlobalIllumination = (mat.globalIlluminationFlags &MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0;// 保存材质关键字状态(URP关键特性)state.enabledKeywords = new List<string>(mat.shaderKeywords);// 全局光照设置state.globalIlluminationFlags = mat.globalIlluminationFlags;return state;}
恢复材质球初始状态(动态修改材质球)
public static void RestoreMaterialState(Material mat, MaterialState state){if (mat == null){Debug.LogError("无法恢复空材质的状态");return;}// 1. 恢复URP核心渲染模式(替代传统_Mode)if (mat.HasProperty("_Surface")){mat.SetInt("_Surface", state.surfaceType); // 表面类型(0=不透明,1=透明等)}if (mat.HasProperty("_Blend")){mat.SetInt("_Blend", state.blendMode); // 混合模式}if (mat.HasProperty("_Cull")){mat.SetInt("_Cull", state.renderFace);}// 2. 恢复渲染类型标签和队列mat.SetOverrideTag("RenderType", state.renderTypeTag);mat.renderQueue = state.renderQueue;// 3. 恢复深度测试和写入设置(URP关键属性)if (mat.HasProperty("_ZTest")){mat.SetInt("_ZTest", (int)state.zTest); // 深度测试模式}if (mat.HasProperty("_ZWrite")){mat.SetInt("_ZWrite", state.zWrite); // 深度写入}// 4. 恢复基础颜色和纹理 URP一般是_BaseColorif (mat.HasProperty("_BaseColor")){mat.SetColor("_BaseColor", state.albedoColor); // 基础颜色}else if (mat.HasProperty("_Color")){mat.SetColor("_Color", state.albedoColor); // 兼容传统属性}if (mat.HasProperty("_BaseMap") && state.albedoMap != null){mat.SetTexture("_BaseMap", state.albedoMap); // URP基础纹理}else if (mat.HasProperty("_MainTex") && state.albedoMap != null){mat.SetTexture("_MainTex", state.albedoMap); // 兼容传统纹理}// 5. 恢复PBR属性(金属度/光滑度)if (mat.HasProperty("_Metallic")){mat.SetFloat("_Metallic", state.metallic);}if (mat.HasProperty("_Smoothness")){mat.SetFloat("_Smoothness", state.smoothness);}else if (mat.HasProperty("_Glossiness")){mat.SetFloat("_Glossiness", state.smoothness); // 兼容光泽度}if (mat.HasProperty("_MetallicGlossMap") && state.metallicSmoothnessMap != null){mat.SetTexture("_MetallicGlossMap", state.metallicSmoothnessMap); // URP金属光滑度贴图}// 6.恢复增强属性if (mat.HasProperty("_BumpMap") && state.normalMap != null){mat.SetTexture("_BumpMap", state.normalMap);}if (mat.HasProperty("_BumpScale")){mat.SetFloat("_BumpScale", state.normalStrength);}// 7. 恢复自发光属性if (mat.HasProperty("_EmissionColor")){mat.SetColor("_EmissionColor", state.emissionColor);}if (mat.HasProperty("_EmissionIntensity")){mat.SetFloat("_EmissionIntensity", state.emissionIntensity); // URP单独强度控制}if (mat.HasProperty("_EmissionMap") && state.emissionMap != null){mat.SetTexture("_EmissionMap", state.emissionMap);}// 恢复自发光关键字和全局光照影响SetKeyword(mat, "_EMISSION", state.isEmission);if (state.isEmission){// 控制自发光是否影响全局光照mat.globalIlluminationFlags = state.emissionUseGlobalIllumination? state.globalIlluminationFlags & ~MaterialGlobalIlluminationFlags.EmissiveIsBlack: state.globalIlluminationFlags | MaterialGlobalIlluminationFlags.EmissiveIsBlack;}// 8. 恢复全局光照设置mat.globalIlluminationFlags = state.globalIlluminationFlags;}private static void SetKeyword(Material material, string keyword, bool state){if (state){material.EnableKeyword(keyword);}else{material.DisableKeyword(keyword);}}
我这里基本上只是选择了材质球里比较常用的属性举例,如果有别的需要修改的属性,可以修改一下结构体,找到那个属性对应的关键字,再根据需求添加就可以。