Unity-程式碼中動態設定Material引數
阿新 • • 發佈:2018-12-26
我們知道在Unity中可以在程式碼中動態地改變Material監視面板中的引數,如改變數值大小或替換貼圖。常用的API有:SetColor , SetFloat, SetInt, SetTexture.
然而今天在設定一個StandardShader的材質貼圖的時候,發現設定了法線貼圖但是場景中的物體並沒有法線凹凸的效果,需要啟用一下材質面板才行。經過反覆檢查以及查詢資料,主要有以下兩個問題:
// 貼圖型別
string[] TEXTURE_TYPE = { "_MetallicGlossMap", "_BumpMap", "_ParallaxMap", "_OcclusionMap", "_DetailMask" , "_DetailAlbedoMap", "_DetailNormalMap"};
// Material需要設定的關鍵字
string[] TEXTURE_KEYWORD = { "_METALLICGLOSSMAP", "_NORMALMAP", "_PARALLAXMAP", "", "_DETAIL_MULX2", "_DETAIL_MULX2", "_DETAIL_MULX2" };
法線貼圖匯入進來需要設定型別為NormalMap
// 設定法線貼圖的型別 if (fileName == diffuseName + TEXTURE_TYPE[1]) { TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath
使用標準著色器(StandardShader)的Material要設定啟用相應的關鍵字
// 在Material.SetTexture之前 開啟相應的KeyWord mat.EnableKeyword(TEXTURE_KEYWORD[i]);
以下是我查文件自己理解的,不一定準確。
一個Material所使用的標準著色器在Unity中其實是多個著色器的集合。因為一個材質的著色器不可能涵蓋所有的功能,比如GI、霧效、HDR等高耗能的效果,所以Unity把標準著色器分成了帶有不同特殊功能的著色器變體(Shader Variant)。當把NormalMap分配給材質,就是激活了支援法線貼圖的著色器變體;把視差貼圖分配給材質,就是激活了支援視差貼圖的著色器變體。所以,如果要把某個特殊的貼圖賦給材質,就要開啟材質相應的關鍵字,以啟用支援相應功能的著色器變體。
需要專門開啟的關鍵字有以下幾個:
關鍵字 特性 _NORMALMAP 法線對映 _ALPHATEST_ON 用於CutOut渲染模式 _ALPHABLEND_ON 用於Fade渲染模式 _ALPHAPREMULTIPLY_ON 用於Transparent渲染模式 _EMISSION 設定自發光 _PARALLAXMAP 設定視差貼圖 _DETAIL_MULX2 用於設定第二個貼圖通道 _METALLICGLOSSMAP 在 Metallic工作流中設定金屬度貼圖 _SPECGLOSSMAP 在 Specular工作流中設定高光貼圖
下面附上設定材質屬性的部分程式碼:
/// <summary> /// 設定材質中shader的相關屬性 ///<para name = "mat"> 需要設定的Material </para> ///<para name = "meshMat"> 要傳入shader的資料集合 </para> ///<para name = "fbxName"> 模型的名字,在這裡主要是為了得到材質貼圖資料夾的位置 </para> /// </summary> void SetShader(Material mat, ShaderData data, string fbxName) { // 這裡預設貼圖資源中主貼圖的名字就是材質名,其他貼圖的名字是材質名+貼圖型別 string diffuseName = mat.name; // textureFiles用於記錄貼圖資料夾中所有的圖片檔案,記錄它們的貼圖名和路徑 Dictionary<string, string> textureFiles = new Dictionary<string, string>(); // texturePath是之前記錄好的一個fbx模型對應的貼圖資料夾的路徑 string[] filesPath = Directory.GetFiles(texturePath[fbxName]); foreach (string filePath in filesPath) { // TEXTURE_EXT是預設的圖片字尾名,用於標記圖片格式(如.jpg,.png,.tif等) if (Array.IndexOf(TEXTURE_EXT, Path.GetExtension(filePath)) != -1) { string fileName = Path.GetFileNameWithoutExtension(filePath); if (fileName.IndexOf(diffuseName) == 0) { textureFiles[fileName] = filePath; Debug.Log(fileName + " , " + filePath); // 設定法線貼圖的型別 if (fileName == diffuseName + TEXTURE_TYPE[1]) { TextureImporter importer = (TextureImporter)AssetImporter.GetAtPath(filePath); importer.textureType = TextureImporterType.NormalMap; importer.SaveAndReimport(); } } } } // 設定材質的主貼圖,也就是Albedo貼圖 if (textureFiles.ContainsKey(diffuseName)) { Debug.Log("MainTexture Exist"); mat.mainTexture = AssetDatabase.LoadAssetAtPath<Texture>(textureFiles[diffuseName]); } // 設定其他特殊型別的貼圖 for (int i = 0; i < TEXTURE_TYPE.Length; ++i) { if (textureFiles.ContainsKey(diffuseName + TEXTURE_TYPE[i])) { Debug.Log(TEXTURE_TYPE[i] + " Exist "); if (TEXTURE_KEYWORD[i] != "") mat.EnableKeyword(TEXTURE_KEYWORD[i]); mat.SetTexture(TEXTURE_TYPE[i], AssetDatabase.LoadAssetAtPath<Texture>(textureFiles[diffuseName + TEXTURE_TYPE[i]])); } } mat.color = data.color; mat.SetFloat("_Metallic", data.metallic); mat.SetFloat("_Glossiness", data.glossiness); mat.SetColor("_EmissionColor", data.emissionColor); }