参考:官方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)
文章评论