Unity 使用UV坐标和Shader做小地图
个不用遮罩,不用把整个小地图图片放到UI上。只用通过计算偏移,然后改变UV,在通过Shader根据UV坐标渲染一部分就可以
一、效果图
二、实现原理
RawImage组件可以调整图片的UV坐标的四个值,Shader可以根据UV坐标去把图片进行截取,并融合成一个新的纹理。这样我们就可以通过C#脚本,动态的去改变RawImage的UV Rect的Vector4数值,然后设置给Shader,实时获取到截取的小地图。
三、脚本
1、UnityShader脚本
顶点函数部分:
v2f vert (a2v v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = (v.uv * _UVScaleOffset.xy) + _UVScaleOffset.zw;//添加Uv偏移和大小
return o;
}
片元函数部分:
fixed4 frag (v2f i) : SV_Target
{
//使用修改后的UV坐标从主纹理采样颜色
fixed4 color = tex2D(_MainTex, i.uv);//获取原图颜色
color.rgb = color.rgb
return color;
}
全部Shader代码:
Shader "Leh1ng01/MapShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_UVScaleOffset ("UV Scale Offset", Vector) = (1, 1, 0, 0)
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct a2v
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
};
sampler2D _MainTex;
fixed4 _UVScaleOffset;
v2f vert (a2v v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = (v.uv * _UVScaleOffset.xy) + _UVScaleOffset.zw;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 color = tex2D(_MainTex, i.uv);
color.rgb = color.rgb;
return color;
}
ENDCG
}
}
FallBack "Diffuse"
}
这样我们的Shader脚本就完成了,主要的逻辑都在顶点和片元函数中。
2、C#脚本
using UnityEngine;
public class MapShaderController : MonoBehaviour
{
public Material myMaterial;
public Vector4 uvScaleOffset = new Vector4(1, 1, 0, 0);
void Start()
{
if (myMaterial != null)
{
// 修改UV缩放和偏移
myMaterial.SetVector("_UVScaleOffset", uvScaleOffset);
}
}
}
在C#脚本中,我们只需要把uv的四个值,在获取到挂载上边的Shader的材质球后,直接对Shader中的属性进行赋值。然后把图片也进行一个设置即可。
场景中实现步骤:
上边的代码完成后,挂载到空物体上,挂载RawImage和C#脚本,再把上边Shader的材质球挂载到RawImage上,其实就已经可以通过手动改变这里的X、Y值,看到小地图的移动了。
当然,我们肯定是想要他动态的刷新地图的。所以我用简单的代码进行了一个实例:
void Update()
{
if (Input.GetAxis("Horizontal") != 0 || Input.GetAxis("Vertical") != 0)
{
Player.transform.Translate(Vector3.forward * Time.deltaTime * Input.GetAxis("Vertical") * 5);
Player.transform.Rotate(Vector3.up * Time.deltaTime * Input.GetAxis("Horizontal") * 150);
playerPoint.transform.localEulerAngles = new Vector3(0, 0, -Player.transform.eulerAngles.y);
SetUpValue();
}
}
private void SetUpValue()
{
float x = Player.transform.position.x / texture.width * 20;
float y = Player.transform.position.z / texture.height * 20;
myImage.uvRect = new Rect(x + 0.5f, y + 0.5f,1, 1);
myMaterial.SetVector("_UVScaleOffset", uvScaleOffset);
}
上边部分就是通过玩家在场景中的位置,计算了一下偏移,然后让UVRect的值发生改变并赋值给Shader。
四、场景搭建
UI的map是空对象,上边说过怎么挂载。他的子对象就是一个图片,用来显示玩家的。最后挂完是这样:
下边的map也是一个空对象,就是为了直接把小地图放到3D场景里:
五、完成
这样我们就完成了通过UV坐标,改变小地图显示的demo。应该还有优化的地方,在知道了大概逻辑后,就会有很多的可玩性,可以加上很多自己的逻辑。
这个不用遮罩,不用把整个小地图图片放到UI上。只用通过计算偏移,然后改变UV,在通过Shader根据UV坐标渲染一部分就可以,个人认为很不错。
更多推荐
所有评论(0)