0%

Unity插件之AdvancedDissolve简略阅读指南

前情提要

由于自己项目里要做一个效果,大略也是按照坐标从A贴图溶解变为B贴图,但在溶解过程中还需加上边缘效果等,看此插件效果好,功能强大,故阅读之。然其代码由于支持丰富,代码略多,文件繁多,记录一下看的过程略作解释。(顺便把代码都贴到一个页面方便自己查看=v=)

插件地址

https://assetstore.unity.com/packages/vfx/shaders/advanced-dissolve-111598

插件效果

image

image

组织方式(以XYZ切割那个场景举例)

一开始看会摸不着头脑,故给出一个大略的看的顺序,否则不知控制器在哪儿,shader的参数又是由哪个脚本控制。

- c# part

c#脚本首先看场景上名字带Controller的

Controller_Cutout.cs

  • Controller_Cutout.cs 用cs控制shader/material的切割参数

    如果是global则给material的一系列Global参数赋值,命名为下面的+_Global
    如果不用global就给所有material赋值,大致有

    1
    2
    3
    4
    5
    6
    7
    8
    9
    materials[i].SetTexture("_DissolveMap1", texture1);
    materials[i].SetVector("_DissolveMap1_ST", new Vector4(texture1Tiling.x, texture1Tiling.y, texture1Offset.x, texture1Offset.y));
    materials[i].SetVector("_DissolveMap1_Scroll", texture1Scroll);
    materials[i].SetFloat("_DissolveMap1Intensity", texture1Intensity);
    materials[i].SetFloat("_DissolveMap1Channel", (int)texture1Channel);

    materials[i].SetFloat("_DissolveNoiseStrength", noise);
    materials[i].SetFloat("_DissolveAlphaSourceTexturesUVSet", uvSet == UVSET.UV0 ? 0 : 1);
    materials[i].SetFloat("_DissolveSourceAlphaTexturesBlend", textureBlend == TEXTURE_BLEND.Multiple ? 0 : 1);

Controller_Edge.cs

  • 用cs控制shader/material的边缘参数
    同样分为Global和非Global,主要为:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    materials[i].SetFloat("_DissolveEdgeWidth", width);
    materials[i].SetFloat("_DissolveEdgeShape", (int)shape);
    materials[i].SetColor("_DissolveEdgeColor", color);
    materials[i].SetFloat("_DissolveEdgeColorIntensity", intensity);

    materials[i].SetTexture("_DissolveEdgeTexture", texture);
    materials[i].SetFloat("_DissolveEdgeTextureReverse", reverse ? 1 : 0);
    materials[i].SetFloat("_DissolveEdgeTextureMipmap", blur);
    materials[i].SetFloat("_DissolveEdgeTextureAlphaOffset", alphaOffset);
    materials[i].SetFloat("_DissolveEdgeTexturePhaseOffset", phaseOffset);
    materials[i].SetFloat("_DissolveEdgeTextureIsDynamic", isDynamic ? 1 : 0);

    materials[i].SetFloat("_DissolveGIMultiplier", GIMultyplier > 0 ? GIMultyplier : 0);

- shader part

找场景上被切了的物体,看它用的哪个shader,比如xyz场景里用的是
Assets/VacuumShaders/Advanced Dissolve/Shaders/Physically Based/Specular.shader

Properties

  • shader part - Properties
    先来看它的Properties:
    首先是Specular常见的贴图和参数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    _Color ("Color", Color) = (1,1,1,1)
    _MainTex ("Albedo (RGBA)", 2D) = "white" {}

    _BumpMap("Normalmap", 2D) = "bump" {}
    _Glossiness ("Smoothness", Range(0,1)) = 0.5
    _Specular("Specular", Range(0,1)) = 0.0
    [Enum(Main Map Alpha,0,Specular Map Alpha,1)] _SpecularAlpha(" Source", Float) = 0
    _SpecularColor(" Specular Color", Color) = (0.2,0.2,0.2)
    _SpecularMap(" Specular Map (RGBA)", 2D) = "white" {}
    然后是溶解常用参数,以及上面c#去控制的,在mat面板被隐藏的参数,我只放一个贴图相关的参数,其实插件支持几张图
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    [Cutout]_Cutoff("   Alpha Cutoff", Range(0,1)) = 0.5

    //Mask
    [HideInInspector][KeywordEnum(None, XYZ Axis, Plane, Sphere, Box, Cylinder, Cone)] _DissolveMask("Mak", Float) = 0
    [HideInInspector][Enum(X,0,Y,1,Z,2)] _DissolveMaskAxis("Axis", Float) = 0
    [HideInInspector][Enum(World,0,Local,1)] _DissolveMaskSpace("Space", Float) = 0
    [HideInInspector] _DissolveMaskOffset("Offset", Float) = 0
    [HideInInspector] _DissolveMaskInvert("Invert", Float) = 1
    [HideInInspector][KeywordEnum(One, Two, Three, Four)] _DissolveMaskCount("Count", Float) = 0

    [HideInInspector] _DissolveMaskPosition("", Vector) = (0,0,0,0)
    [HideInInspector] _DissolveMaskNormal("", Vector) = (1,0,0,0)
    [HideInInspector] _DissolveMaskRadius("", Float) = 1

    //Alpha Source
    [HideInInspector] [KeywordEnum(Main Map Alpha, Custom Map, Two Custom Maps, Three Custom Maps)] _DissolveAlphaSource("Alpha Source", Float) = 0
    [HideInInspector] _DissolveMap1("", 2D) = "white" { }
    [HideInInspector] [UVScroll] _DissolveMap1_Scroll("", Vector) = (0,0,0,0)
    [HideInInspector] _DissolveMap1Intensity("", Range(0, 1)) = 1
    [HideInInspector] [Enum(Red, 0, Green, 1, Blue, 2, Alpha, 3)] _DissolveMap1Channel("", INT) = 3

    //Edge
    [HideInInspector] _DissolveEdgeWidth("Edge Size", Range(0,1)) = 0.25
    [HideInInspector][Enum(Cutout Source,0,Main Map,1)] _DissolveEdgeDistortionSource("Distortion Source", Float) = 0
    [HideInInspector] _DissolveEdgeDistortionStrength("Distortion Strength", Range(0, 2)) = 0

    //Color
    [HideInInspector] _DissolveEdgeColor("Edge Color", Color) = (0,1,0,1)
    [HideInInspector][PositiveFloat] _DissolveEdgeColorIntensity("Intensity", FLOAT) = 0
    [HideInInspector][Enum(Solid,0,Smooth,1, Smooth Squared,2)] _DissolveEdgeShape("Shape", INT) = 0

    [HideInInspector][KeywordEnum(None, Gradient, Main Map, Custom)] _DissolveEdgeTextureSource("", Float) = 0
    [HideInInspector][NoScaleOffset] _DissolveEdgeTexture("Edge Texture", 2D) = "white" { }
    [HideInInspector][Toggle] _DissolveEdgeTextureReverse("Reverse", FLOAT) = 0
    [HideInInspector] _DissolveEdgeTexturePhaseOffset("Offset", FLOAT) = 0
    [HideInInspector] _DissolveEdgeTextureAlphaOffset("Offset", Range(-1, 1)) = 0
    [HideInInspector] _DissolveEdgeTextureMipmap("", Range(0, 10)) = 1
    [HideInInspector][Toggle] _DissolveEdgeTextureIsDynamic("", Float) = 0

shader part 入口

  • shader part - funcs入口
    每个pass下都有

    1
    2
    #pragma vertex vert_surf
    #pragma fragment frag_surf

    文章后面会主要看一个pass的vert & frag

    1
    2
    v2f_surf vert_surf
    void frag_surf
  • shader part - cginc
    自定义引用

    1
    2
    #include "../cginc/AdvancedDissolve.cginc"
    #include "../cginc/Integration_CurvedWorld.cginc"

shader part 实现

  • shader part - 具体实现
    • vert_surf 各种给frag需要的坐标做准备
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      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);


      CURVED_WORLD_TRANSFORM_POINT_AND_NORMAL(v.vertex, v.normal, v.tangent)


      o.pos = UnityObjectToClipPos(v.vertex);
      o.pack0.xy = TRANSFORM_TEX(v.texcoord, _MainTex);
      o.pack0.zw = TRANSFORM_TEX(v.texcoord, _BumpMap);
      o.pack1.xy = TRANSFORM_TEX(v.texcoord, _SpecularMap);
      float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
      float3 worldNormal = UnityObjectToWorldNormal(v.normal);
      fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
      fixed tangentSign = v.tangent.w * unity_WorldTransformParams.w;
      fixed3 worldBinormal = cross(worldNormal, worldTangent) * tangentSign;
      o.tSpace0 = float4(worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x);
      o.tSpace1 = float4(worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y);
      o.tSpace2 = float4(worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z);
      #ifdef DYNAMICLIGHTMAP_ON
      o.lmap.zw = v.texcoord2.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
      #endif
      #ifdef LIGHTMAP_ON
      o.lmap.xy = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
      #endif

      // SH/ambient and vertex lights
      #ifndef LIGHTMAP_ON
      #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
      o.sh = 0;
      // Approximated illumination from non-important point lights
      #ifdef VERTEXLIGHT_ON
      o.sh += Shade4PointLights (
      unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0,
      unity_LightColor[0].rgb, unity_LightColor[1].rgb, unity_LightColor[2].rgb, unity_LightColor[3].rgb,
      unity_4LightAtten0, worldPos, worldNormal);
      #endif
      o.sh = ShadeSHPerVertex (worldNormal, o.sh);
      #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

      //注意这里
      //VacuumShaders
      ADVANCED_DISSOLVE_INIT_DATA(o.pos, v.texcoord.xy, v.texcoord1.xy, o)

      return o;
      }

    • ADVANCED_DISSOLVE_INIT_DATA (in AdvancedDissolve.cginc)
      1
      2
      3
      4
      5
      6
      #ifdef _DISSOLVEMAPPINGTYPE_TRIPLANAR
      #define ADVANCED_DISSOLVE_INIT_DATA(positionCS, texcoord0, texcoord1, output) output.dissolveUV = 0;
      #else
      #define ADVANCED_DISSOLVE_INIT_DATA(positionCS, texcoord0, texcoord1, output) DissolveVertex2Fragment(positionCS, texcoord0.xy, texcoord1.xy, output.dissolveUV);
      #endif

    • DissolveVertex2Fragment
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      inline void DissolveVertex2Fragment(float4 positionCS, float2 vertexUV0, float2 vertexUV1, inout float4 dissolveMapUV)
      {
      dissolveMapUV = 0;

      #if defined(_DISSOLVEMAPPINGTYPE_SCREEN_SPACE)
      dissolveMapUV = ComputeScreenPos(positionCS);
      #else

      #if defined(_DISSOLVEALPHASOURCE_CUSTOM_MAP) || defined(_DISSOLVEALPHASOURCE_TWO_CUSTOM_MAPS) || defined(_DISSOLVEALPHASOURCE_THREE_CUSTOM_MAPS)
      float2 texUV = VALUE_UVSET == 0 ? vertexUV0 : vertexUV1;

      dissolveMapUV = float4(texUV.xy, 0, 0);
      #endif
      #endif
      }

    • frag
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      fixed4 frag_surf (v2f_surf IN) : SV_Target {
      UNITY_SETUP_INSTANCE_ID(IN);


      float3 worldPos = float3(IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w);
      float3 normalWS = float3(IN.tSpace0.z, IN.tSpace1.z, IN.tSpace2.z);
      //!!! 这边就是计算切割了,沿着这个方法往下查
      float4 alpha = AdvancedDissolveGetAlpha(IN.pack0.xy, worldPos, normalWS, IN.dissolveUV);
      // alpha算出来.a 范围为-1 or 0~1
      DoDissolveClip(alpha);

      float3 dissolveAlbedo = 0;
      float3 dissolveEmission = 0;

      // 1 alpha 2 - 3- 4 : _MainTex
      float dissolveBlend = DoDissolveAlbedoEmission(alpha, dissolveAlbedo, dissolveEmission, IN.pack0.xy, 0);


      //下面几乎都是正常的pbr光照
      // prepare and unpack data
      Input surfIN;
      #ifdef FOG_COMBINED_WITH_TSPACE
      UNITY_EXTRACT_FOG_FROM_TSPACE(IN);
      #elif defined (FOG_COMBINED_WITH_WORLD_POS)
      UNITY_EXTRACT_FOG_FROM_WORLD_POS(IN);
      #else
      UNITY_EXTRACT_FOG(IN);
      #endif
      #ifdef FOG_COMBINED_WITH_TSPACE
      UNITY_RECONSTRUCT_TBN(IN);
      #else
      UNITY_EXTRACT_TBN(IN);
      #endif
      UNITY_INITIALIZE_OUTPUT(Input,surfIN);
      surfIN.uv_MainTex.x = 1.0;
      surfIN.uv_BumpMap.x = 1.0;
      surfIN.uv_SpecularMap.x = 1.0;
      surfIN.uv_MainTex = IN.pack0.xy;
      surfIN.uv_BumpMap = IN.pack0.zw;
      surfIN.uv_SpecularMap = IN.pack1.xy;
      #ifndef USING_DIRECTIONAL_LIGHT
      fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
      #else
      fixed3 lightDir = _WorldSpaceLightPos0.xyz;
      #endif
      float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPos));
      #ifdef UNITY_COMPILER_HLSL
      SurfaceOutputStandardSpecular o = (SurfaceOutputStandardSpecular)0;
      #else
      SurfaceOutputStandardSpecular o;
      #endif
      o.Albedo = 0.0;
      o.Emission = 0.0;
      o.Specular = 0.0;
      o.Alpha = 0.0;
      o.Occlusion = 1.0;
      fixed3 normalWorldVertex = fixed3(0,0,1);
      o.Normal = fixed3(0,0,1);

      // call surface function
      surf (surfIN, o);

      //这两句就是边缘着色了,另一篇讲溶解的介绍里也有: https://blog.csdn.net/w9503/article/details/105321355?utm_medium=distribute.pc_relevant.none-task-blog-title-2&spm=1001.2101.3001.4242
      o.Albedo = lerp(o.Albedo, dissolveAlbedo, dissolveBlend);
      o.Emission = lerp(o.Emission, dissolveEmission, dissolveBlend);


      // compute lighting & shadowing factor
      UNITY_LIGHT_ATTENUATION(atten, IN, worldPos)
      fixed4 c = 0;
      float3 worldN;
      worldN.x = dot(_unity_tbn_0, o.Normal);
      worldN.y = dot(_unity_tbn_1, o.Normal);
      worldN.z = dot(_unity_tbn_2, o.Normal);
      worldN = normalize(worldN);
      o.Normal = worldN;

      // Setup lighting environment
      UnityGI gi;
      UNITY_INITIALIZE_OUTPUT(UnityGI, gi);
      gi.indirect.diffuse = 0;
      gi.indirect.specular = 0;
      gi.light.color = _LightColor0.rgb;
      gi.light.dir = lightDir;
      // Call GI (lightmaps/SH/reflections) lighting function
      UnityGIInput giInput;
      UNITY_INITIALIZE_OUTPUT(UnityGIInput, giInput);
      giInput.light = gi.light;
      giInput.worldPos = worldPos;
      giInput.worldViewDir = worldViewDir;
      giInput.atten = atten;
      #if defined(LIGHTMAP_ON) || defined(DYNAMICLIGHTMAP_ON)
      giInput.lightmapUV = IN.lmap;
      #else
      giInput.lightmapUV = 0.0;
      #endif
      #if UNITY_SHOULD_SAMPLE_SH && !UNITY_SAMPLE_FULL_SH_PER_PIXEL
      giInput.ambient = IN.sh;
      #else
      giInput.ambient.rgb = 0.0;
      #endif
      giInput.probeHDR[0] = unity_SpecCube0_HDR;
      giInput.probeHDR[1] = unity_SpecCube1_HDR;
      #if defined(UNITY_SPECCUBE_BLENDING) || defined(UNITY_SPECCUBE_BOX_PROJECTION)
      giInput.boxMin[0] = unity_SpecCube0_BoxMin; // .w holds lerp value for blending
      #endif
      #ifdef UNITY_SPECCUBE_BOX_PROJECTION
      giInput.boxMax[0] = unity_SpecCube0_BoxMax;
      giInput.probePosition[0] = unity_SpecCube0_ProbePosition;
      giInput.boxMax[1] = unity_SpecCube1_BoxMax;
      giInput.boxMin[1] = unity_SpecCube1_BoxMin;
      giInput.probePosition[1] = unity_SpecCube1_ProbePosition;
      #endif
      LightingStandardSpecular_GI(o, giInput, gi);

      // realtime lighting: call lighting function
      c += LightingStandardSpecular (o, worldViewDir, gi);
      c.rgb += o.Emission;

      UNITY_APPLY_FOG(_unity_fogCoord, c); // apply fog
      //!!!
      return DoOutputForward(c, o.Alpha);
      }
    • frag 引用
      关键词:
      • AdvancedDissolveGetAlpha
      • DoDissolveClip
      • DoDissolveAlbedoEmission
      • DoOutputForward
        一个个来
      • AdvancedDissolveGetAlpha
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        // texcoord0: mainTex的texcorrd
        // positionWS: worldPos
        // normalWS: worldNormal
        // dissolveUV: vert里算完的dissolveUV
        float4 AdvancedDissolveGetAlpha(float2 texcoord0, float3 positionWS, float3 normalWS, float4 dissolveUV)
        {
        #ifdef _DISSOLVEMAPPINGTYPE_TRIPLANAR
        return ReadDissolveAlpha_Triplanar(positionWS, normalWS);
        #else
        return ReadDissolveAlpha(texcoord0, dissolveUV, positionWS);
        #endif
        }
      • ReadDissolveAlpha (简化版,源代码中有诸多#ifdef,不便于阅读,故采取当前用到的展示)
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        //注意AdvancedDissolve.cginc引用了Variables.cginc,代码中的变量在Variables里找
        inline float4 ReadDissolveAlpha(float2 mainTexUV, float4 dissolveMapUV, float3 vertexPos)
        {
        float4 alphaSource = 1;
        float2 uv1 = dissolveMapUV.xy * VALUE_MAP1_ST.xy + VALUE_MAP1_ST.zw + VALUE_MAP1_SCROLL.xy * TIME;
        alphaSource = READ_TEXTURE_2D(VALUE_MAP1, VALUE_MAP1_SAMPLER, uv1, VALUE_MAP1_INTENSITY);
        alphaSource.a = alphaSource[VALUE_MAP1_CHANNEL];
        float noise = ((alphaSource.a - 0.5) * 2) * VALUE_NOISE_STRENGTH;
        alphaSource.a = ReadMaskValue(vertexPos, noise);
        return alphaSource;
        }
      • Variables.cginc
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        #define VALUE_MAIN_MAP_TILING   _DissolveMainMapTiling
        // texture1
        #define VALUE_MAP1 _DissolveMap1
        #define VALUE_MAP1_SAMPLER sampler_DissolveMap1
        // tilling offset那个东西
        #define VALUE_MAP1_ST _DissolveMap1_ST
        //vector3, 用的xy
        #define VALUE_MAP1_SCROLL _DissolveMap1_Scroll
        //float 0~1
        #define VALUE_MAP1_INTENSITY _DissolveMap1Intensity
        //rgba
        #define VALUE_MAP1_CHANNEL _DissolveMap1Channel
      • 结合上两个翻译版:
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        inline float4 ReadDissolveAlpha(float2 mainTexUV, float4 dissolveMapUV, float3 vertexPos)
        {
        float4 alphaSource = 1;
        float2 uv1 = dissolveMapUV.xy * _DissolveMap1_ST.xy + _DissolveMap1_ST.zw + _DissolveMap1_Scroll.xy * TIME;
        alphaSource = READ_TEXTURE_2D(_DissolveMap1, sampler_DissolveMap1, uv1, _DissolveMap1Intensity);
        alphaSource.a = alphaSource[_DissolveMap1Channel];
        float noise = ((alphaSource.a - 0.5) * 2) * VALUE_NOISE_STRENGTH;
        alphaSource.a = ReadMaskValue(vertexPos, noise);
        return alphaSource;
        }


        inline float ReadMaskValue(float3 vertexPos, float noise)
        {
        float cutout = -1;

        //world 0 or local 1
        //if(VALUE_MASK_SPACE > 0.5)
        vertexPos = mul(unity_WorldToObject, float4(vertexPos, 1)).xyz;
        //VALUE_CUTOFF_AXIS: X:0 Y Z
        // VALUE_MASK_OFFSET: _DissolveMaskOffset
        // INVERT: 1 or -1 正反方向
        cutout = (vertexPos - VALUE_MASK_OFFSET)[(int)VALUE_CUTOFF_AXIS] * VALUE_AXIS_INVERT;

        cutout += noise;
        return (cutout > 0 ? cutout : -1);
        }

        #define READ_TEXTURE_2D(t,s,uv,i) saturate(tex2D(t, (uv).xy) + (1 - i).xxxx)