参考:官方API
写过脚本编译器的同学应该都知道Monobehaivor的脚本可以重画检视面板,这有利我们开发各利插件,方便调试,Shader的面板也可以重画,区别在于,Monobehavior的脚本设置只能在运行时生效,再Shader的面板设置在编译环境下就生效,在运行时无法生效,其实这个很好理解,unity的shader最终还要是编译成各平台对应的shader语言,所以它这里用的控制更多类似于宏,即不同设置会导致最终的编译结果不同
直接上代码:
在Asset中新建文件夹Editor,创建CustomShaderGUI.cs
代码如下:
using UnityEngine; using UnityEditor; using System; public class CustomShaderGUI : ShaderGUI { public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) { // 渲染默认 GUI base.OnGUI(materialEditor, properties); Material targetMat = materialEditor.target as Material; bool has_sec = Array.IndexOf(targetMat.shaderKeywords, "SEC_ATLAS") != -1; EditorGUI.BeginChangeCheck(); has_sec = EditorGUILayout.Toggle("Sec Texture", has_sec); if (EditorGUI.EndChangeCheck()) { if (has_sec) targetMat.EnableKeyword("SEC_ATLAS"); else targetMat.DisableKeyword("SEC_ATLAS"); } } }
Shader代码如下:
Shader "Custom/CustomShader" { Properties { _Texture1("Texture1", 2D) = "white" {} _Texture2("Texture2", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } LOD 200 Pass { CGPROGRAM #include "UnityCG.cginc" #pragma vertex vert #pragma fragment frag #pragma shader_feature SEC_ATLAS sampler2D _Texture1; sampler2D _Texture2; float4 _Texture1_ST; float4 _Texture2_ST; struct appdata_t { float4 vertex : POSITION; fixed2 uv : TEXCOORD0; }; struct v2f { fixed4 vertex : POSITION; fixed2 uv : TEXCOORD0; }; v2f vert(appdata_t v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); #if SEC_ATLAS o.uv = v.uv * _Texture2_ST.xy; #else o.uv = v.uv * _Texture1_ST.xy; #endif return o; } fixed4 frag(v2f i):COLOR { #if SEC_ATLAS return tex2D(_Texture2,i.uv); #endif return tex2D(_Texture1,i.uv); } ENDCG } }CustomEditor "CustomShaderGUI"
}
代码很简单,通过Shader的检视面板的SEC_ATLAS选项来决定最终采样第一张图还是第二张图,
shader与C#的关联代码为
#pragma shader_feature SEC_ATLAS 与 CustomEditor "CustomShaderGUI
C#中的控制代码为
targetMat.EnableKeyword("SEC_ATLAS") 与 targetMat.DisableKeyword("SEC_ATLAS")
Shader编译后代码如下(SEC_ATLAS = false的情况):
// Compiled shader for PC, Mac & Linux Standalone ////////////////////////////////////////////////////////////////////////// // // NOTE: This is *not* a valid shader file, the contents are provided just // for information and for debugging purposes only. // ////////////////////////////////////////////////////////////////////////// // Skipping shader variants that would not be included into build of current scene. Shader "Custom/CustomShader" { Properties { _Texture1 ("Texture1", 2D) = "white" { } _Texture2 ("Texture2", 2D) = "white" { } } SubShader { LOD 200 Tags { "RenderType"="Opaque" } // Stats for Vertex shader: // d3d11: 9 math // Stats for Fragment shader: // d3d11: 0 math, 1 texture Pass { Tags { "RenderType"="Opaque" } ////////////////////////////////// // // // Compiled programs // // // ////////////////////////////////// ////////////////////////////////////////////////////// Global Keywords: <none> Local Keywords: <none> -- Hardware tier variant: Tier 1 -- Vertex shader for "d3d11": // Stats: 9 math, 2 temp registers Uses vertex data channel "Vertex" Uses vertex data channel "TexCoord0" Constant Buffer "$Globals" (64 bytes) on slot 0 { Vector4 _Texture1_ST at 32 } Constant Buffer "UnityPerDraw" (176 bytes) on slot 1 { Matrix4x4 unity_ObjectToWorld at 0 } Constant Buffer "UnityPerFrame" (368 bytes) on slot 2 { Matrix4x4 unity_MatrixVP at 272 } Shader Disassembly: // // Generated by Microsoft (R) D3D Shader Disassembler // // // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // POSITION 0 xyzw 0 NONE float xyz // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Position 0 xyzw 0 POS float xyzw // TEXCOORD 0 xy 1 NONE float xy // vs_4_0 dcl_constantbuffer CB0[3], immediateIndexed dcl_constantbuffer CB1[4], immediateIndexed dcl_constantbuffer CB2[21], immediateIndexed dcl_input v0.xyz dcl_input v1.xy dcl_output_siv o0.xyzw, position dcl_output o1.xy dcl_temps 2 0: mul r0.xyzw, v0.yyyy, cb1[1].xyzw 1: mad r0.xyzw, cb1[0].xyzw, v0.xxxx, r0.xyzw 2: mad r0.xyzw, cb1[2].xyzw, v0.zzzz, r0.xyzw 3: add r0.xyzw, r0.xyzw, cb1[3].xyzw 4: mul r1.xyzw, r0.yyyy, cb2[18].xyzw 5: mad r1.xyzw, cb2[17].xyzw, r0.xxxx, r1.xyzw 6: mad r1.xyzw, cb2[19].xyzw, r0.zzzz, r1.xyzw 7: mad o0.xyzw, cb2[20].xyzw, r0.wwww, r1.xyzw 8: mul o1.xy, v1.xyxx, cb0[2].xyxx 9: ret // Approximately 0 instruction slots used -- Hardware tier variant: Tier 1 -- Fragment shader for "d3d11": // Stats: 0 math, 1 textures Set 2D Texture "_Texture1" to slot 0 Shader Disassembly: // // Generated by Microsoft (R) D3D Shader Disassembler // // // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Position 0 xyzw 0 POS float // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Target 0 xyzw 0 TARGET float xyzw // ps_4_0 dcl_sampler s0, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_input_ps linear v1.xy dcl_output o0.xyzw 0: sample o0.xyzw, v1.xyxx, t0.xyzw, s0 1: ret // Approximately 0 instruction slots used } } CustomEditor "CustomShaderGUI" }
上面的代码只生成采样Textrue1的代码
当SEC_ATLAS = true的时:
// Compiled shader for PC, Mac & Linux Standalone ////////////////////////////////////////////////////////////////////////// // // NOTE: This is *not* a valid shader file, the contents are provided just // for information and for debugging purposes only. // ////////////////////////////////////////////////////////////////////////// // Skipping shader variants that would not be included into build of current scene. Shader "Custom/CustomShader" { Properties { _Texture1 ("Texture1", 2D) = "white" { } _Texture2 ("Texture2", 2D) = "white" { } } SubShader { LOD 200 Tags { "RenderType"="Opaque" } // Stats for Vertex shader: // d3d11: 9 math // Stats for Fragment shader: // d3d11: 0 math, 1 texture Pass { Tags { "RenderType"="Opaque" } ////////////////////////////////// // // // Compiled programs // // // ////////////////////////////////// ////////////////////////////////////////////////////// Global Keywords: <none> Local Keywords: <none> -- Hardware tier variant: Tier 1 -- Vertex shader for "d3d11": // Stats: 9 math, 2 temp registers Uses vertex data channel "Vertex" Uses vertex data channel "TexCoord0" Constant Buffer "$Globals" (64 bytes) on slot 0 { Vector4 _Texture1_ST at 32 } Constant Buffer "UnityPerDraw" (176 bytes) on slot 1 { Matrix4x4 unity_ObjectToWorld at 0 } Constant Buffer "UnityPerFrame" (368 bytes) on slot 2 { Matrix4x4 unity_MatrixVP at 272 } Shader Disassembly: // // Generated by Microsoft (R) D3D Shader Disassembler // // // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // POSITION 0 xyzw 0 NONE float xyz // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Position 0 xyzw 0 POS float xyzw // TEXCOORD 0 xy 1 NONE float xy // vs_4_0 dcl_constantbuffer CB0[3], immediateIndexed dcl_constantbuffer CB1[4], immediateIndexed dcl_constantbuffer CB2[21], immediateIndexed dcl_input v0.xyz dcl_input v1.xy dcl_output_siv o0.xyzw, position dcl_output o1.xy dcl_temps 2 0: mul r0.xyzw, v0.yyyy, cb1[1].xyzw 1: mad r0.xyzw, cb1[0].xyzw, v0.xxxx, r0.xyzw 2: mad r0.xyzw, cb1[2].xyzw, v0.zzzz, r0.xyzw 3: add r0.xyzw, r0.xyzw, cb1[3].xyzw 4: mul r1.xyzw, r0.yyyy, cb2[18].xyzw 5: mad r1.xyzw, cb2[17].xyzw, r0.xxxx, r1.xyzw 6: mad r1.xyzw, cb2[19].xyzw, r0.zzzz, r1.xyzw 7: mad o0.xyzw, cb2[20].xyzw, r0.wwww, r1.xyzw 8: mul o1.xy, v1.xyxx, cb0[2].xyxx 9: ret // Approximately 0 instruction slots used -- Hardware tier variant: Tier 1 -- Fragment shader for "d3d11": // Stats: 0 math, 1 textures Set 2D Texture "_Texture1" to slot 0 Shader Disassembly: // // Generated by Microsoft (R) D3D Shader Disassembler // // // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Position 0 xyzw 0 POS float // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Target 0 xyzw 0 TARGET float xyzw // ps_4_0 dcl_sampler s0, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_input_ps linear v1.xy dcl_output o0.xyzw 0: sample o0.xyzw, v1.xyxx, t0.xyzw, s0 1: ret // Approximately 0 instruction slots used ////////////////////////////////////////////////////// Global Keywords: SEC_ATLAS Local Keywords: <none> -- Hardware tier variant: Tier 1 -- Vertex shader for "d3d11": // Stats: 9 math, 2 temp registers Uses vertex data channel "Vertex" Uses vertex data channel "TexCoord0" Constant Buffer "$Globals" (64 bytes) on slot 0 { Vector4 _Texture2_ST at 48 } Constant Buffer "UnityPerDraw" (176 bytes) on slot 1 { Matrix4x4 unity_ObjectToWorld at 0 } Constant Buffer "UnityPerFrame" (368 bytes) on slot 2 { Matrix4x4 unity_MatrixVP at 272 } Shader Disassembly: // // Generated by Microsoft (R) D3D Shader Disassembler // // // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // POSITION 0 xyzw 0 NONE float xyz // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Position 0 xyzw 0 POS float xyzw // TEXCOORD 0 xy 1 NONE float xy // vs_4_0 dcl_constantbuffer CB0[4], immediateIndexed dcl_constantbuffer CB1[4], immediateIndexed dcl_constantbuffer CB2[21], immediateIndexed dcl_input v0.xyz dcl_input v1.xy dcl_output_siv o0.xyzw, position dcl_output o1.xy dcl_temps 2 0: mul r0.xyzw, v0.yyyy, cb1[1].xyzw 1: mad r0.xyzw, cb1[0].xyzw, v0.xxxx, r0.xyzw 2: mad r0.xyzw, cb1[2].xyzw, v0.zzzz, r0.xyzw 3: add r0.xyzw, r0.xyzw, cb1[3].xyzw 4: mul r1.xyzw, r0.yyyy, cb2[18].xyzw 5: mad r1.xyzw, cb2[17].xyzw, r0.xxxx, r1.xyzw 6: mad r1.xyzw, cb2[19].xyzw, r0.zzzz, r1.xyzw 7: mad o0.xyzw, cb2[20].xyzw, r0.wwww, r1.xyzw 8: mul o1.xy, v1.xyxx, cb0[3].xyxx 9: ret // Approximately 0 instruction slots used -- Hardware tier variant: Tier 1 -- Fragment shader for "d3d11": // Stats: 0 math, 1 textures Set 2D Texture "_Texture2" to slot 0 Shader Disassembly: // // Generated by Microsoft (R) D3D Shader Disassembler // // // Input signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Position 0 xyzw 0 POS float // TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // // Name Index Mask Register SysValue Format Used // -------------------- ----- ------ -------- -------- ------- ------ // SV_Target 0 xyzw 0 TARGET float xyzw // ps_4_0 dcl_sampler s0, mode_default dcl_resource_texture2d (float,float,float,float) t0 dcl_input_ps linear v1.xy dcl_output o0.xyzw 0: sample o0.xyzw, v1.xyxx, t0.xyzw, s0 1: ret // Approximately 0 instruction slots used } } CustomEditor "CustomShaderGUI" }
只生成了采样Texture2的代码,所以当Shader代码可以高度定制时,推荐使用此方法可以有效提升效率,缺点为不可在运行环境的动态修改,测试如下
using System.Collections; using System.Collections.Generic; using UnityEngine; using FloatMesh; public class Test : MonoBehaviour { public MeshRenderer mRender; void OnGUI() { if (GUI.Button(new Rect(0, 0, 150, 50),"BUTTON")) { mRender.material.EnableKeyword("SEC_ATLAS"); } } }
报错如下:
UnassignedReferenceException: The variable mRender of Test has not been assigned.
You probably need to assign the mRender variable of the Test script in the inspector.
UnityEngine.Renderer.get_material () (at <2feaf16e80004e0cadae3f2e05f2a3fa>:0)
Test.OnGUI () (at Assets/Script/Test.cs:14)
文章评论