由于您的着色只关心大小相同的正方形网格中的 2d 位置,这些正方形都与同一网格对齐,因此我们可以传入一个 2d 纹理,其颜色表示地面的颜色应该是什么样的。
在你的着色器中,添加一个2D
_ColorizeMap
, and a Vector
_WorldSpaceRange
。该贴图将用于传递应该对世界的哪些部分进行着色,并且范围将告诉着色器如何在世界空间和 UV(纹理)空间之间进行转换。由于游戏网格与世界 x/y 轴对齐,因此我们可以将坐标从世界空间线性缩放到 UV 空间。
然后,当法线朝上时(您可以检查法线的 y 是否足够高),获得世界位置的逆 lerp,并从_ColorizeMap
了解如何/是否应该着色。
Shader "Custom/GridHighlightShader"
{
Properties
{
[HideInInspector]_GlowInterval("_GlowInterval", float) = 1
_MainTex("Albedo (RGB)", 2D) = "white" {}
_Glossiness("Smoothness", Range(0,1)) = 0.5
_Metallic("Metallic", Range(0,1)) = 0.0
[HideInInspector]_ColorizeMap("Colorize Map", 2D) = "black" {}
_WorldSpaceRange("World Space Range", Vector) = (0,0,100,100)
}
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
struct Input
{
float2 uv_MainTex;
float3 worldNormal;
float3 worldPos;
};
sampler2D _MainTex;
half _Glossiness;
half _Metallic;
half _GlowInterval;
sampler2D _ColorizeMap;
fixed4 _WorldSpaceRange;
// 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)
{
fixed4 c = tex2D(_MainTex, IN.uv_MainTex);
// Update only the normals facing up and down
if (abs(IN.worldNormal.y) >= 0.866)) // abs(y) >= sin(60 degrees)
{
fixed4 colorizedMapUV = (IN.worldPos.xz-_WorldSpaceRange.xy)
/ (_WorldSpaceRange.zw-_WorldSpaceRange.xy);
half4 colorType = tex2D(_ColorizeMap, colorizedMapUV);
c = c + (colorType * _GlowInterval);
}
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
并删除分支:
Shader "Custom/GridHighlightShader"
{
Properties
{
[HideInInspector]_GlowInterval("_GlowInterval", float) = 1
_MainTex("Albedo (RGB)", 2D) = "white" {}
_Glossiness("Smoothness", Range(0,1)) = 0.5
_Metallic("Metallic", Range(0,1)) = 0.0
[HideInInspector]_ColorizeMap("Colorize Map", 2D) = "black" {}
_WorldSpaceRange("World Space Range", Vector) = (0,0,100,100)
}
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
struct Input
{
float2 uv_MainTex;
float3 worldNormal;
float3 worldPos;
};
sampler2D _MainTex;
half _Glossiness;
half _Metallic;
half _GlowInterval;
sampler2D _ColorizeMap;
fixed4 _WorldSpaceRange;
// 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)
{
half4 c = tex2D(_MainTex, IN.uv_MainTex);
float2 colorizedMapUV = (IN.worldPos.xz - _WorldSpaceRange.xy)
/ (_WorldSpaceRange.zw - _WorldSpaceRange.xy);
half4 colorType = tex2D(_ColorizeMap, colorizedMapUV);
// abs(y) >= sin(60 degrees) = 0.866
c = c + step(0.866, abs(IN.worldNormal.y)) * colorType * _GlowInterval;
o.Albedo = c.rgb;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Alpha = c.a;
}
ENDCG
}
FallBack "Diffuse"
}
然后在 C# 代码中创建一个不进行过滤的纹理。开始将纹理全黑,然后根据突出显示的方式向纹理添加颜色。另外,告诉着色器颜色贴图表示的世界空间范围 (minX,minZ,maxX,maxZ):
public void SetColorizationCollectionForShader()
{
Color[] selectionColors = new Color[4] { Color.clear, new Color(0.5f, 0.5f, 0.5f, 0.5f), Color.blue, Color.red };
float leftMostTileX = 0f + Battlemap.HALF_TILE_SIZE;
float backMostTileZ = 0f + Battlemap.HALF_TILE_SIZE;
float rightMostTileX = leftMostTileX + (Battlemap.Instance.GridMaxX - 1)
* Battlemap.TILE_SIZE;
float forwardMostTileZ = backMostTileZ + (Battlemap.Instance.GridMaxZ - 1)
* Battlemap.TILE_SIZE;
Texture2D colorTex = new Texture2D(Battlemap.Instance.GridMaxX, Battlemap.Instance.GridMaxZ);
colorTex.filterMode = FilterMode.Point;
Vector4 worldRange = new Vector4(
leftMostTileX - Battlemap.HALF_TILE_SIZE,
backMostTileZ - Battlemap.HALF_TILE_SIZE,
rightMostTileX + Battlemap.HALF_TILE_SIZE,
forwardMostTileZ + Battlemap.HALF_TILE_SIZE);
meshRenderer.material.SetVector("_WorldSpaceRange", worldRange);
// Loop through the tiles to be colored only and grab their world coordinates
for (int i = 0; i < Battlemap.Instance.tiles.Length; i++)
{
// determine pixel index from position
float xT = Mathf.InverseLerp(leftMostTileX, rightMostTileX,
Battlemap.Instance.tiles[i].x);
int texXPos = Mathf.RoundToInt(Mathf.Lerp(0f, Battlemap.Instance.GridMaxX - 1.0f, xT));
float yT = Mathf.InverseLerp(backMostTileZ, forwardMostTileZ,
Battlemap.Instance.tiles[i].z);
int texYPos = Mathf.RoundToInt(Mathf.Lerp(0f, Battlemap.Instance.GridMaxZ - 1.0f, yT));
colorTex.SetPixel(texXPos, texYPos, selectionColors[(int)Battlemap.Instance.tiles[i].selectionMode]);
}
colorTex.Apply();
// Feed the color map into the shader
meshRenderer.material.SetTexture("_ColorizeMap", colorTex);
}
瓷砖的边界可能存在一些不稳定,并且纹理空间/世界空间之间可能存在一些对齐问题,但这应该可以帮助您入门。