当前位置: 首页 > 工具软件 > frag > 使用案例 >

Unity 内置Surface着色器转换到vert/frag着色器

宰父飞白
2023-12-01

本文出发点在于,从shader可视化工具制作的shader导出的表面着色器,需要进行重写!

从编辑器中导出的着色器,很多事表面着色器,表面着色器是unity提供的一种更高层的封装,虽然降低了shader入门的难度,但是这种shader,会包含大量的变体,里面的逻辑由于封装而无法被开发者控制,所以,需要将表面着色器转换为顶点片元着色器;前提:需要在一定程度上了解表面着色器,如果不了解,推荐可以简单看一下官方文档,或《Unity Shader入门精要》- 17章;

可以选择直接重写,但有时,如果想要完整复现导出的surface着色器,可以通过先将其转换为顶点片元着色器,然后移除不必要的代码,再根据其顶点片元着色器来理解它究竟真正做了什么工作;

随便新建一个表面着色器,然后转换为顶点片元着色器,及时是一个简单的lamber模型,我们可以看到会生成上千行代码,并带来很多变体;

我们的剔除工作就是根据不必要的变体关键字来去除,首先是移除不必要的pass,可以搜索pass关键字,然后将第一个pass之后的全部移除,他们通常是不必要的;然后只关心一个pass,可以看到它根据不同的宏定义了不同的结构体和片元着色器,根据ifdef和ifndef等可以去除;最后得到一个只有一个顶点和片元着色器的pass,去尝试着理解这个pass里做了什么;当然,剔除的时候要关注材质效果是否发生了变化,如果发生了变化,那说明删除的代码是受到影响的;

最终可以得到一个简易版本,如下是一个简单的lambert模型:

// Upgrade NOTE: replaced 'defined FOG_COMBINED_WITH_WORLD_POS' with 'defined (FOG_COMBINED_WITH_WORLD_POS)'

    Shader "SurfaceTest/Surf2Vert" {
        Properties {
            _MainTex ("Texture", 2D) = "white" {}
            _Color ("Main Color", Color) = (1,1,1,1)
        }
        SubShader {
        Tags { "RenderType" = "Opaque" }
        
	// ------------------------------------------------------------
	// Surface shader code generated out of a CGPROGRAM block:
	

	// ---- forward rendering base pass:
	Pass {
		Name "FORWARD"
		Tags { "LightMode" = "ForwardBase" }

CGPROGRAM
// compile directives
#pragma vertex vert_surf
#pragma fragment frag_surf
#pragma multi_compile_instancing
#pragma multi_compile_fog
#pragma multi_compile_fwdbase
#include "HLSLSupport.cginc"
#define UNITY_INSTANCED_LOD_FADE
#define UNITY_INSTANCED_SH
#define UNITY_INSTANCED_LIGHTMAPSTS
#include "UnityShaderVariables.cginc"
#include "UnityShaderUtilities.cginc"
// -------- variant for: <when no other keywords are defined>
#if !defined(INSTANCING_ON)

#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"

#define INTERNAL_DATA
#define WorldReflectionVector(data,normal) data.worldRefl
#define WorldNormalVector(data,normal) normal

  
    half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
        half NdotL = dot (s.Normal, lightDir);
        half4 c;
        c.rgb = s.Albedo * _LightColor0.rgb * max(0, NdotL);
        c.a = s.Alpha;
        return c;
    //   return fixed4(0,0,0,1);
    }

    struct Input {
        float2 uv_MainTex;
    };
    
    sampler2D _MainTex;
    fixed4 _Color;
    
    void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D(_MainTex, IN.uv_MainTex) * _Color;
        // o.Albedo = fixed4(0,1,0,1);
    }
    
// high-precision fragment shader registers:
#ifndef UNITY_HALF_PRECISION_FRAGMENT_SHADER_REGISTERS
struct v2f_surf {
  UNITY_POSITION(pos);
  float2 pack0 : TEXCOORD0; // _MainTex
  float3 worldNormal : TEXCOORD1;
  float3 worldPos : TEXCOORD2;
  fixed3 vlight : TEXCOORD3; // ambient/SH/vertexlights
  UNITY_FOG_COORDS(4)
  UNITY_SHADOW_COORDS(5)
  #if SHADER_TARGET >= 30
  float4 lmap : TEXCOORD6;
  #endif
  UNITY_VERTEX_INPUT_INSTANCE_ID
  UNITY_VERTEX_OUTPUT_STEREO
};
#endif
// with lightmaps:

float4 _MainTex_ST;

// vertex shader
v2f_surf vert_surf (appdata_full v) {
    //   UNITY_SETUP_INSTANCE_ID(v);
    v2f_surf o;
    //   UNITY_INITIALIZE_OUTPUT(v2f_surf,o);
    //   UNITY_TRANSFER_INSTANCE_ID(v,o);
    //   UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    o.pos = UnityObjectToClipPos(v.vertex);
    o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
    float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    float3 worldNormal = UnityObjectToWorldNormal(v.normal);
    o.worldPos.xyz = worldPos;
    o.worldNormal = worldNormal;

    // SH/ambient and vertex lights
    #ifndef LIGHTMAP_ON
    #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
    float3 shlight = ShadeSH9 (float4(worldNormal,1.0));
    o.vlight = shlight;
    #else
    o.vlight = 0.0;
    #endif
    #endif // !LIGHTMAP_ON

//   UNITY_TRANSFER_LIGHTING(o,v.texcoord1.xy); // pass shadow and, possibly, light cookie coordinates to pixel shader
//   #ifdef FOG_COMBINED_WITH_TSPACE
//     UNITY_TRANSFER_FOG_COMBINED_WITH_TSPACE(o,o.pos); // pass fog coordinates to pixel shader
//   #elif defined (FOG_COMBINED_WITH_WORLD_POS)
//     UNITY_TRANSFER_FOG_COMBINED_WITH_WORLD_POS(o,o.pos); // pass fog coordinates to pixel shader
//   #else
//     UNITY_TRANSFER_FOG(o,o.pos); // pass fog coordinates to pixel shader
//   #endif
  return o;
}

// fragment shader
fixed4 frag_surf (v2f_surf IN) : SV_Target {
    UNITY_SETUP_INSTANCE_ID(IN);
    // prepare and unpack data
    Input surfIN;
    UNITY_INITIALIZE_OUTPUT(Input,surfIN);
    surfIN.uv_MainTex.x = 1.0;
    surfIN.uv_MainTex = IN.pack0.xy;
    float3 worldPos = IN.worldPos.xyz;
    #ifndef USING_DIRECTIONAL_LIGHT
    fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
    #else
    fixed3 lightDir = _WorldSpaceLightPos0.xyz;
    #endif
    #ifdef UNITY_COMPILER_HLSL
    SurfaceOutput o = (SurfaceOutput)0;
    #else
    SurfaceOutput o;
    #endif
    o.Albedo = 0.0;
    o.Emission = 0.0;
    o.Specular = 0.0;
    o.Alpha = 0.0;
    o.Gloss = 0.0;
    fixed3 normalWorldVertex = fixed3(0,0,1);
    //  return fixed4(0.5* normalize(IN.worldNormal)+0.5, 1);
    o.Normal = IN.worldNormal;
    normalWorldVertex = IN.worldNormal;

    surf (surfIN, o);

    UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
    fixed4 c = 0;

    #ifndef LIGHTMAP_ON
        c.rgb += o.Albedo * IN.vlight;
    #endif

    #ifndef LIGHTMAP_ON
    c += LightingSimpleLambert (o, lightDir, atten);
    //   return c;
    #else
    c.a = o.Alpha;
    #endif

    UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
    UNITY_OPAQUE_ALPHA(c.a);
    return c;
}
#endif

ENDCG

}

}
}

 

 类似资料: