xian's

Unity Polybrush与顶点色着色器
暂时无可提供的摘要
扫描右侧二维码阅读全文
14
2018/10

Unity Polybrush与顶点色着色器

Head Pic:「壹 零 計 劃」/「@CLare」


Unity Polybrush与顶点色着色器

今年年初,我们宣布了ProBuilder和Polybrush将正式成为Unity的一部分。我们已经详细介绍过使用ProBuilder快速关卡建模,而Polybrush可以帮助我们完成粗略的雕刻、纹理混合、对象散布和顶点色绘制等功能。

通常为了处理顶点色,必须进行3D程序代码编写并估计最终结果。但有了Polybrush后,我们可以直接在编辑器中进行绘制,然后看到处理后的效果。

本文将展示一些使用顶点色的着色器示例,介绍如何将Polybrush和它们一起使用。

获取Polybrush

你可以访问Asset Store资源商店下载Polybrush :
https://www.assetstore.unity3d.com/cn/?stay#!/content/111427

下载完毕后导入资源包,点击菜单栏,选择Tools > Polybrush > Polybrush Window。

打开Polybrush 窗口中,如下图所示,我们可以看见四个功能选项:
1、雕刻(Sculpting)
2、顶点色绘制(Vertex Color Painting)
3、对象散布(Object Scattering)
4、纹理混合(Texture Blending)

功能介绍

雕刻

该功能拥有二个标签页,第一个标签页用于升降顶点位置,第二个标签页用于平滑处理顶点位置。

对象散布

在使用该部分功能前,首先需要给Palette添加一些预制件,预制件位于目录Procore > PolybrushPrefab Palettes > Default下。

将想要绘制的预制件拖入到此处。如果想要删除预制件,选取后按下退格键。

现在就可以点击放置对象,笔刷的强度(Strength)属性控制对象密度。

纹理混合

纹理混合功能需要具体的着色器设置,它使用三个UV集。资源包内含有一些示例,我们可以通过示例了解如何进行设置。

下面展示Polybrush的TriPlanar Blend功能。

给材质添加想要的纹理,然后在Texture Paint Settings中选择纹理即可。Flood选项会将整个网格绘制为所选颜色,Fill选项只会绘制预览图中的顶点,Brush选项会以光标为圆心绘制特定半径的圆形区域。

顶点色绘制

现在让我们详细介绍顶点色绘制。

读取着色器中的顶点色

为了访问着色器中的顶点色,你只需在Input Struct(表面着色器使用的结构)或Appdata Struct(顶点/片段着色器使用的结构)添加一行代码即可。

顶点/片段着色器

下图代码会在Appdata struct中读取颜色,在v2F struct中声明颜色,然后将颜色在二个结构间传递。你可以在片段着色器中使用"i.color"读取颜色。

表面着色器

你可以使用"IN.vertexColor"读取顶点色。

这是最基本的顶点着色器:

Shader "Custom/SurfaceShaderVertexColor" {
    Properties {

    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float4 vertexColor: COLOR; // vertex color
        };

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            o.Albedo = IN.vertexColor.rgb; // vertex color
            // Metallic and smoothness come from slider variables

            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

现在我们就可以绘制顶点色了,让我们了解一些有趣的示例。

示例

高光

这是一个卡通高光着色器(Toon Specular):

Shader "Toon/Lit Specular" {
    Properties{
        _Color("Main Color", Color) = (1,1,1,1)
        _SColor("Specular Color", Color) = (1,1,1,1)
        _MainTex("Base (RGB)", 2D) = "white" {}
    _Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
    _RampS("Specular Ramp (RGB)", 2D) = "gray" {} // specular ramp, cutoff point
    _SpecSize("Specular Size", Range(0.65,0.999)) = 0.9 // specular size
        _SpecOffset("Specular Offset", Range(0.5,1)) = 0.5 // specular offset of the spec Ramp
        _TColor("Gradient Overlay Top Color", Color) = (1,1,1,1)
        _BottomColor("Gradient Overlay Bottom Color", Color) = (0.23,0,0.95,1)
        _Offset("Gradient Offset", Range(-4,4)) = 3.2
        [Toggle(RIM)] _RIM("Fresnel Rim?", Float) = 0
        _RimColor("Fresnel Rim Color", Color) = (0.49,0.94,0.64,1)
        [Toggle(FADE)] _FADE("Fade specular to bottom?", Float) = 0
        _TopBottomOffset("Specular Fade Offset", Range(-4,4)) = 3.2
    }

        SubShader{
        Tags{ "RenderType" = "Opaque" }
        LOD 200

        CGPROGRAM
#pragma surface surf ToonRamp vertex:vert
#pragma shader_feature FADE // fade toggle
#pragma shader_feature RIM // rim fresnel toggle
        sampler2D _Ramp;

    // custom lighting function that uses a texture ramp based
    // on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
    inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
    {
#ifndef USING_DIRECTIONAL_LIGHT
        lightDir = normalize(lightDir);
#endif

        half d = dot(s.Normal, lightDir)*0.5 + 0.5;
        half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;

        half4 c;
        c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
        c.a = 0;
        return c;
    }

    sampler2D _MainTex;
    float4 _Color;
    float4 _SColor; // specular color
    sampler2D _RampS; // specular ramp
    float _SpecSize; // specular size
    float _SpecOffset; // offset specular ramp
    float4 _TColor; // top gradient color
    float4 _BottomColor;// bottom gradient color
    float _TopBottomOffset; // gradient bottom offset
    float _Offset; // specular fade offset
    float4 _RimColor; // fresnel rim color

    struct Input {
        float2 uv_MainTex : TEXCOORD0;
        float3 lightDir;
        float3 worldPos; // world position
        float3 viewDir; // view direction from camera
    };

    void vert(inout appdata_full v, out Input o)
    {
        UNITY_INITIALIZE_OUTPUT(Input, o);
        o.lightDir = WorldSpaceLightDir(v.vertex); // get the worldspace lighting direction
    }

    void surf(Input IN, inout SurfaceOutput o) {
        float3 localPos = (IN.worldPos - mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz);// local position of the object, with an offset
        half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
        half d = dot(o.Normal, IN.lightDir)*0.5 + _SpecOffset; // basing on normal and light direction
        half3 rampS = tex2D(_RampS, float2(d, d)).rgb; // specular ramp

        float rim = 1 - saturate(dot(IN.viewDir, o.Normal)); // calculate fresnel rim
#if RIM
        o.Emission = _RimColor.rgb * pow(rim, 1.5); // fresnel rim
#endif
        o.Albedo = (step(_SpecSize, rampS.r)) * rampS * d* _SColor; // specular
#if FADE
        o.Albedo = (step(_SpecSize, rampS.r)) * rampS * d* saturate(localPos.y + _TopBottomOffset) * _SColor; // fade specular to bottom
#endif
        o.Albedo += c.rgb*lerp(_BottomColor, _TColor, saturate(localPos.y + _Offset)) * 1.1; // multiply color by gradient lerp
        o.Alpha = c.a;
    }
    ENDCG

    }

        Fallback "Diffuse"
}

这个是Alpha版:

Shader "Toon/Lit Specular Alpha" {
    Properties{
        _Color("Main Color", Color) = (1,1,1,1)
        _SColor("Specular Color", Color) = (1,1,1,1)
        _MainTex("Base (RGB)", 2D) = "white" {}
    _Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
    _RampS("Specular Ramp (RGB)", 2D) = "gray" {} // specular ramp, cutoff point
    _SpecSize("Specular Size", Range(0.65,0.999)) = 0.9 // specular size
        _SpecOffset("Specular Offset", Range(0.5,1)) = 0.5 // specular offset of the spec Ramp
        _TColor("Gradient Overlay Top Color", Color) = (1,1,1,1)
        _BottomColor("Gradient Overlay Bottom Color", Color) = (0.23,0,0.95,1)
        _Offset("Gradient Offset", Range(-4,4)) = 3.2
        [Toggle(RIM)] _RIM("Fresnel Rim?", Float) = 0
        _RimColor("Fresnel Rim Color", Color) = (0.49,0.94,0.64,1)
        [Toggle(FADE)] _FADE("Fade specular to bottom?", Float) = 0
        _TopBottomOffset("Specular Fade Offset", Range(-4,4)) = 3.2
    }

        SubShader{
        Tags{ "Queue" = "Transparent"}
        LOD 200
        Blend SrcAlpha OneMinusSrcAlpha

        CGPROGRAM
#pragma surface surf ToonRamp vertex:vert keepalpha
#pragma shader_feature FADE // fade toggle
#pragma shader_feature RIM // rim fresnel toggle
        sampler2D _Ramp;

    // custom lighting function that uses a texture ramp based
    // on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
    inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
    {
#ifndef USING_DIRECTIONAL_LIGHT
        lightDir = normalize(lightDir);
#endif

        half d = dot(s.Normal, lightDir)*0.5 + 0.5;
        half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;

        half4 c;
        c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
        c.a = s.Alpha;
        return c;
    }

    sampler2D _MainTex;
    float4 _Color;
    float4 _SColor; // specular color
    sampler2D _RampS; // specular ramp
    float _SpecSize; // specular size
    float _SpecOffset; // offset specular ramp
    float4 _TColor; // top gradient color
    float4 _BottomColor;// bottom gradient color
    float _TopBottomOffset; // gradient bottom offset
    float _Offset; // specular fade offset
    float4 _RimColor; // fresnel rim color

    struct Input {
        float2 uv_MainTex : TEXCOORD0;
        float3 lightDir;
        float3 worldPos; // world position
        float3 viewDir; // view direction from camera
    };

    void vert(inout appdata_full v, out Input o)
    {
        UNITY_INITIALIZE_OUTPUT(Input, o);
        o.lightDir = WorldSpaceLightDir(v.vertex); // get the worldspace lighting direction
    }

    void surf(Input IN, inout SurfaceOutput o) {
        float3 localPos = (IN.worldPos - mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz);// local position of the object, with an offset
        half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
        half d = dot(o.Normal, IN.lightDir)*0.5 + _SpecOffset; // basing on normal and light direction
        half3 rampS = tex2D(_RampS, float2(d, d)).rgb; // specular ramp

        float rim = 1 - saturate(dot(IN.viewDir, o.Normal)); // calculate fresnel rim
#if RIM
        o.Emission = _RimColor.rgb * pow(rim, 1.5); // fresnel rim
#endif
        float specular= (step(_SpecSize, rampS.r)) * rampS * d* _SColor;
        o.Albedo = specular; // specular
        o.Alpha = c.a + specular;
#if FADE
        float specular2 = (step(_SpecSize, rampS.r)) * rampS * d* saturate(localPos.y + _TopBottomOffset) * _SColor;
        o.Albedo = specular2; // fade specular to bottom
        o.Alpha = c.a + specular2;
#endif
        o.Albedo += c.rgb*lerp(_BottomColor, _TColor, saturate(localPos.y + _Offset)) * 1.1; // multiply color by gradient lerp

    }
    ENDCG

    }

        Fallback "Diffuse"
}

如果不设置静态遮罩,该着色器效果会更棒,我们可以使用该着色器在任意位置进行绘制,从而使对象看起来潮湿或看起来像玻璃。

为了实现这部分,我们将伪高光数值乘以IN.vertexColor.r,o.Emission通道的边缘光也乘以IN.vertexColor.r,所以绘制区域也有发光效果。

float3 spec = (step(_SpecSize, rampS.r) * IN.vertexColor.r;
o.Emission =  pow(rim, _RimPower) * IN.vertexColor.r;

这意味着绘制红色的位置都会发光,如果不想让发光效果太明显,可以使用较深的红色。

高光顶点色着色器代码:

Shader "Toon/Lit Specular Vertex" {
    Properties{

        [Header(Main)]
        _Color("Main Color", Color) = (1,1,1,1)
        _MainTex("Base (RGB)", 2D) = "white" {}
        _Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
        [Space]
        [Header(Specular)]
        _SColor("Specular Color", Color) = (1,1,1,1)
        _RampS("Specular Ramp (RGB)", 2D) = "gray" {} // specular ramp, cutoff point
        _SpecSize("Specular Size", Range(0.65,0.999)) = 0.9 // specular size
        _SpecOffset("Specular Offset", Range(0,1)) = 0.5 // specular offset of the spec Ramp
        [Space]
         [Header(Rim Light)]
        _RimColor("Fresnel Rim Color", Color) = (0.49,0.94,0.64,1)
        _RimPower("Rim Power", Range(0,20)) = 3.2
    }

        SubShader{
        Tags{ "RenderType" = "Opaque" }
        LOD 200

        CGPROGRAM
#pragma surface surf ToonRamp vertex:vert
        sampler2D _Ramp;

    // custom lighting function that uses a texture ramp based
    // on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
    inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
    {
#ifndef USING_DIRECTIONAL_LIGHT
        lightDir = normalize(lightDir);
#endif
        half d = dot(s.Normal, lightDir)*0.5 + 0.5;
        half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;
        half4 c;
        c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
        c.a = 0;
        return c;
    }

    sampler2D _MainTex;
    float4 _Color, _SColor, _RimColor;
    sampler2D _RampS; // specular ramp
    float _SpecSize; // specular size
    float _SpecOffset; // offset specular ramp
    float _RimPower; // gradient bottom offset

    struct Input {
        float2 uv_MainTex : TEXCOORD0;
        float3 lightDir;
        float3 viewDir;
        float4 vertexColor: COLOR; // vertex color
    };

    void vert(inout appdata_full v, out Input o)
    {
        UNITY_INITIALIZE_OUTPUT(Input, o);
        o.lightDir = WorldSpaceLightDir(v.vertex); // get the worldspace lighting direction
    }

    void surf(Input IN, inout SurfaceOutput o) {

        half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color; // main texture
        half d = dot(o.Normal, IN.lightDir + IN.viewDir) + _SpecOffset; // basing on normal and light direction
        half3 rampS = tex2D(_RampS, float2(d, d)).rgb; // specular ramp
        float rim = 1 - saturate(dot(IN.viewDir, o.Normal)); // calculate fresnel rim
        o.Emission = _RimColor.rgb * pow(rim, _RimPower) * IN.vertexColor.r; // fresnel rim
        float3 spec = ((step(_SpecSize, rampS.r)) * rampS * d* _SColor) * IN.vertexColor.r; // specular
        o.Albedo = c.rgb + spec; // multiply color by gradient lerp
        o.Alpha = c.a;
    }
    ENDCG

    }

        Fallback "Diffuse"
}

卡通色阶如下图所示:

高光色阶如下图所示:

摇摆动画

该动画类似动态草丛,如果我们不想在旗帜、树叶和链子等一些静态物体使用Cloth/Physics模拟效果,我们可以使用一个处理顶点动画的着色器。

多数全局解决方案会带来剪裁问题。使用顶点色版解决方案的好处是可以设置允许的移动量。在下图的示例中,我们想要使旗帜的顶端不会移动,但只让旗杆的中间位置稍微移动一点。

我们可以乘以红色顶点色通道,控制效果的位置。

v.vertex.yz += sin(_Time.y * movementcalculation ) * v.vertexColor.r;

摇摆顶点色着色器代码:

Shader "Toon/Lit Vertex Sway" {
    Properties {
        [Header(Main)]
        _Color ("Main Color", Color) = (0.5,0.5,0.5,1)
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _Ramp ("Toon Ramp (RGB)", 2D) = "gray" {}
        [Space]
        [Header(Movement)]
        _Speed ("Speed", Range(0,2)) = 1
        _Amount ("Wave Amount", Range(0,2)) = 1
        _MaxWidth ("Max Width", Range(0,2)) = 1
        [MaterialToggle] XZAxis ("XZ Axis? (Otherwise YZ)", Float) = 0
    }

    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Cull Off

CGPROGRAM
#pragma surface surf ToonRamp vertex:vert addshadow
#pragma multi_compile _ XZAXIS_ON
sampler2D _Ramp;

// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
inline half4 LightingToonRamp (SurfaceOutput s, half3 lightDir, half atten)
{
    #ifndef USING_DIRECTIONAL_LIGHT
    lightDir = normalize(lightDir);
    #endif

    half d = dot (s.Normal, lightDir)*0.5 + 0.5;
    half3 ramp = tex2D (_Ramp, float2(d,d)).rgb;

    half4 c;
    c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
    c.a = 0;
    return c;
}

sampler2D _MainTex;
float4 _Color;
float _Speed;
float _Amount;
float _MaxWidth;

struct appdata{
    float4 color: COLOR; // vertex colors
};

struct Input {
    float2 uv_MainTex : TEXCOORD0;
};

void vert( inout appdata_full v )
{
float4 worldSpaceVertex = mul( unity_ObjectToWorld, v.vertex );
#if XZAXIS_ON
v.vertex.xz += sin( _Time.y * _Speed + worldSpaceVertex.y  * _Amount ) * _MaxWidth * v.color.r;
#else
v.vertex.yz += sin( _Time.y * _Speed + worldSpaceVertex.y + worldSpaceVertex.x * _Amount ) * _MaxWidth * v.color.r;
#endif
}

void surf (Input IN, inout SurfaceOutput o) {
    half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    o.Albedo = c.rgb;
    o.Alpha = c.a;
}
ENDCG

    }

    Fallback "Diffuse"
}

三平面多纹理

本文前面部分展示的纹理混合工具提供了非常平滑或模糊效果。对于一些艺术风格而言,该效果还不错,但我们可以尝试让边缘更清晰并带有噪音效果。

该着色器使用了和三平面一样的基色,但没有在世界法线使用“Grass”,它使用红色和蓝色顶点通道来添加新纹理。

float primary = step(0.6* noisetexture,IN.vertexColor.r );

将它与红色通道上显示的纹理相乘,然后对于纹理周围的边缘,将比原始部分稍大的区域乘以反转的原始部分,从而只留下一小部分。

float primaryEdge = (step(0.5* noisetexture,IN.vertexColor.r )) * (1-primary);

顶点色非常模糊,但是由于Step函数和噪音纹理的缘故,获得的结果非常干净。我们也可以重制纹理混合着色器来实现类似效果,因为多个UV集会得到更多纹理。

三平面顶点色着色器代码:

Shader "Toon/Lit TriPlanar Vertex" {
    Properties{
        [Header(Main)]
        _Color("Main Color", Color) = (0.5,0.5,0.5,1)
        _Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
        _Normal("Noise", 2D) = "gray" {}
        _NoiseScale("Noise Scale", Range(-2,2)) = 1

        [Space]
        [Header(Extra Textures)]
        _MainTexBase("Base Texture", 2D) = "white" {}
        _MainTex("Primary Texture", 2D) = "white" {}
        _MainTex2("Secondary Texture", 2D) = "white" {}        
        _Scale("Base Scale", Range(-2,2)) = 1
        _PrimaryScale("Primary Scale", Range(-2,2)) = 1
        _SecondaryScale("Secondary Scale", Range(-2,2)) = 1
        _EdgeColor("Primary Edge Color", Color) = (0.5,0.5,0.5,1)
        _EdgeColor2("Secondary Edge Color", Color) = (0.5,0.5,0.5,1)
        _Edgewidth("Edge Width", Range(0,0.2)) = 0.1

        [Space]
        [Header(Rim)]
        _RimPower("Rim Power", Range(-2,20)) = 1
        _RimColor("Rim Color Top", Color) = (0.5,0.5,0.5,1)    
        _RimColor2("Rim Color Side/Bottom", Color) = (0.5,0.5,0.5,1)
    }

        SubShader{
        Tags{ "RenderType" = "Opaque" }
        LOD 200

        CGPROGRAM
#pragma surface surf ToonRamp

        sampler2D _Ramp;

    // custom lighting function that uses a texture ramp based
    // on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
    inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
    {
#ifndef USING_DIRECTIONAL_LIGHT
        lightDir = normalize(lightDir);
#endif

        half d = dot(s.Normal, lightDir)*0.5 + 0.5;
        half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;

        half4 c;
        c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
        c.a = 0;
        return c;
    }

    sampler2D _MainTex, _MainTexBase, _Normal, _MainTex2;
    float4 _Color, _RimColor, _RimColor2;
    float _RimPower;
    float _Scale, _PrimaryScale, _SecondaryScale, _NoiseScale;
    float4 _EdgeColor, _EdgeColor2;
    float _Edgewidth;

    struct Input {
        float2 uv_MainTex : TEXCOORD0;
        float3 worldPos; // world position built-in value
        float3 worldNormal; // world normal built-in value
        float3 viewDir;// view direction built-in value we're using for rimlight
        float4 vertexColor : COLOR;
    };

    void surf(Input IN, inout SurfaceOutput o) {

        // clamp (saturate) and increase(pow) the worldnormal value to use as a blend between the projected textures
        float3 blendNormal = saturate(pow(IN.worldNormal * 1.4,4));

        // normal noise triplanar for x, y, z sides
        float3 xn = tex2D(_Normal, IN.worldPos.zy * _NoiseScale);
        float3 yn = tex2D(_Normal, IN.worldPos.zx * _NoiseScale);
        float3 zn = tex2D(_Normal, IN.worldPos.xy * _NoiseScale);

        // lerped together all sides for noise texture
        float3 noisetexture = zn;
        noisetexture = lerp(noisetexture, xn, blendNormal.x);
        noisetexture = lerp(noisetexture, yn, blendNormal.y);

        // triplanar for primary texture for x, y, z sides
        float3 xm = tex2D(_MainTex, IN.worldPos.zy * _PrimaryScale);
        float3 zm = tex2D(_MainTex, IN.worldPos.xy * _PrimaryScale);
        float3 ym = tex2D(_MainTex, IN.worldPos.zx * _PrimaryScale);

        // lerped together all sides for primary texture
        float3 toptexture = zm;
        toptexture = lerp(toptexture, xm, blendNormal.x);
        toptexture = lerp(toptexture, ym, blendNormal.y);

         // triplanar for secondary texture for x, y, z sides
        float3 xm2 = tex2D(_MainTex2, IN.worldPos.zy * _SecondaryScale);
        float3 zm2 = tex2D(_MainTex2, IN.worldPos.xy * _SecondaryScale);
        float3 ym2 = tex2D(_MainTex2, IN.worldPos.zx * _SecondaryScale);

        // lerped together all sides for secondary texture
        float3 toptexture2 = zm2;
        toptexture2 = lerp(toptexture2, xm2, blendNormal.x);
        toptexture2 = lerp(toptexture2, ym2, blendNormal.y);

        // triplanar for base texture, x,y,z sides
        float3 x = tex2D(_MainTexBase, IN.worldPos.zy * _Scale);
        float3 y = tex2D(_MainTexBase, IN.worldPos.zx * _Scale);
        float3 z = tex2D(_MainTexBase, IN.worldPos.xy * _Scale);

        // lerped together all sides for base texture
        float3 baseTexture = z;
        baseTexture = lerp(baseTexture, x, blendNormal.x);
        baseTexture = lerp(baseTexture, y, blendNormal.y);

        // rim light for fuzzy top texture
        half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal * noisetexture));

        // rim light for side/bottom texture
        half rim2 = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal* noisetexture));

        // primary texture only on red vertex color with the noise texture
        float vertexColoredPrimary = step(0.6* noisetexture,IN.vertexColor.r );
        float3 primaryTextureResult = vertexColoredPrimary * toptexture;
        // secondary texture only on blue vertex color with the noise texture
        float vertexColoredSecondary = step(0.6* noisetexture + saturate(IN.vertexColor.r),IN.vertexColor.b );
        float3 secondaryTextureResult = vertexColoredSecondary * toptexture2;
        // edge for primary texture
        float vertexColorEdge = (step((0.6 - _Edgewidth)* noisetexture,IN.vertexColor.r )) * (1- vertexColoredPrimary);
        // edge for secondary texture
        float vertexColorEdge2 = (step((0.6 - _Edgewidth)* noisetexture+ saturate(IN.vertexColor.r),IN.vertexColor.b )) * (1-vertexColoredSecondary);

        // basetexture only where there is no red or blue vertex paint
        float3 sideTextureResult =  baseTexture * (1-(vertexColoredPrimary + vertexColorEdge + vertexColoredSecondary+ vertexColorEdge2));

        // final albedo color by adding everything together
        o.Albedo =   sideTextureResult + primaryTextureResult + (vertexColorEdge * _EdgeColor) + secondaryTextureResult + (vertexColorEdge2 * _EdgeColor2) ; //+ topTextureEdgeResult;
        o.Albedo *= _Color;

        // adding the fuzzy rimlight(rim) on the top texture, and the harder rimlight (rim2) on the side/bottom texture
        o.Emission = (vertexColoredSecondary  * pow(rim2, _RimPower)* _RimColor2) + (vertexColoredPrimary * _RimColor * pow(rim, _RimPower));

    }
    ENDCG

    }

        Fallback "Diffuse"
}

版权所有:unity中文官方社区
原文地址:Unity Polybrush与顶点色着色器

Last modification:November 10th, 2018 at 03:59 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment