[转载]Unity Polybrush与顶点色着色器

最后更新于 2020-08-27 139 次阅读


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

[转载]Unity Polybrush与顶点色着色器插图

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

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

获取Polybrush

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

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

[转载]Unity Polybrush与顶点色着色器插图1

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

[转载]Unity Polybrush与顶点色着色器插图2

功能介绍

雕刻

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

[转载]Unity Polybrush与顶点色着色器插图3

对象散布

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

[转载]Unity Polybrush与顶点色着色器插图4

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

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

[转载]Unity Polybrush与顶点色着色器插图5

纹理混合

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

下面展示Polybrush的TriPlanar Blend功能。

[转载]Unity Polybrush与顶点色着色器插图6

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

顶点色绘制

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

读取着色器中的顶点色

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

顶点/片段着色器

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

[转载]Unity Polybrush与顶点色着色器插图7

表面着色器

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

[转载]Unity Polybrush与顶点色着色器插图8

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

```C for Graphics
Shader "Custom/SurfaceShaderVertexColor" {
Properties {

<pre><code>}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200

<pre><code>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
</code></pre>

}
FallBack "Diffuse"
</code></pre>

}

<pre><code class=""><img src="https://xian-file-1256703172.file.myqcloud.com/Unity_Polybrush%26Vertex_shader/10.webp" alt="" />

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

<h2>示例</h2>

<h3>高光</h3>

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

```C for Graphics
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版:

```C for Graphics
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
}

<pre><code> SubShader{
Tags{ "Queue" = "Transparent"}
LOD 200
Blend SrcAlpha OneMinusSrcAlpha

<pre><code>CGPROGRAM
</code></pre>

</code></pre>

pragma surface surf ToonRamp vertex:vert keepalpha

pragma shader_feature FADE // fade toggle

pragma shader_feature RIM // rim fresnel toggle

    sampler2D _Ramp;

<pre><code>// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
</code></pre>

pragma lighting ToonRamp exclude_path:prepass

inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
{

ifndef USING_DIRECTIONAL_LIGHT

    lightDir = normalize(lightDir);

endif

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

<pre><code>half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = s.Alpha;
return c;
</code></pre>

}

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

<pre><code>float rim = 1 - saturate(dot(IN.viewDir, o.Normal)); // calculate fresnel rim
</code></pre>

</code></pre>

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

<pre><code>}
ENDCG

}

<pre><code>Fallback "Diffuse"
</code></pre>

</code></pre>

}

<pre><code class=""><img src="https://xian-file-1256703172.file.myqcloud.com/Unity_Polybrush%26Vertex_shader/11.webp" alt="" />

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

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

<pre><code class="language-csharp ">float3 spec = (step(_SpecSize, rampS.r) * IN.vertexColor.r;
o.Emission =  pow(rim, _RimPower) * IN.vertexColor.r;
</code></pre>

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

<img src="https://xian-file-1256703172.file.myqcloud.com/Unity_Polybrush%26Vertex_shader/12.webp" alt="" />

高光顶点色着色器代码:

```C for Graphics
Shader "Toon/Lit Specular Vertex" {
Properties{

<pre><code> [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

</code></pre>

pragma surface surf ToonRamp vertex:vert

    sampler2D _Ramp;

<pre><code>// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
</code></pre>

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;
}

<pre><code>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"

</code></pre>

}

<pre><code class="">卡通色阶如下图所示:
[转载]Unity Polybrush与顶点色着色器插图9

高光色阶如下图所示:
[转载]Unity Polybrush与顶点色着色器插图10

摇摆动画

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

[转载]Unity Polybrush与顶点色着色器插图11

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

[转载]Unity Polybrush与顶点色着色器插图12

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

v.vertex.yz += sin(_Time.y * movementcalculation ) * v.vertexColor.r;
&lt;/code&gt;&lt;/pre&gt;

&lt;img src=&quot;https://xian-file-1256703172.file.myqcloud.com/Unity_Polybrush%26Vertex_shader/16.webp&quot; alt=&quot;&quot; /&gt;

摇摆顶点色着色器代码:

C for Graphics
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
}

<pre><code>SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Cull Off
</code></pre>

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

<pre><code>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;
</code></pre>

}

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

<pre><code>}

Fallback "Diffuse"
</code></pre>

}

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

[转载]Unity Polybrush与顶点色着色器插图13

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

float primary = step(0.6* noisetexture,IN.vertexColor.r );
&lt;/code&gt;&lt;/pre&gt;


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

&lt;pre&gt;&lt;code class=&quot;language-csharp &quot;&gt;float primaryEdge = (step(0.5* noisetexture,IN.vertexColor.r )) * (1-primary);
&lt;/code&gt;&lt;/pre&gt;

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

&lt;img src=&quot;https://xian-file-1256703172.file.myqcloud.com/Unity_Polybrush%26Vertex_shader/18.webp&quot; alt=&quot;&quot; /&gt;

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

C for Graphics
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

<pre><code> [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

</code></pre>

pragma surface surf ToonRamp

<pre><code> sampler2D _Ramp;

// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
</code></pre>

pragma lighting ToonRamp exclude_path:prepass

inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
{

ifndef USING_DIRECTIONAL_LIGHT

    lightDir = normalize(lightDir);

endif

<pre><code> 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"

</code></pre>

}


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