0%

U3D游戏横屏显示竖屏

前言

游戏是竖屏类型,但是我想在电脑上运行也保持竖屏的显示方式。竖屏下其余部分将由纯色或图片来填充。

目的是为了用UI遮盖住区域外的游戏场景的内容。

设计思路

通过shader,对背景填充的Image的图片进行修改。从中抠出符合竖屏拉升后显示的游戏内容区域,能够动态调整保持游戏显示区域。

1

实现思路

一、确保竖屏显示UI

  • Canvas Scaler 设置好长宽比;
  • 设置屏幕匹配模式 ‘Match Width Or Height’
  • 匹配拉到height位置,数值为1。

这样确保了UI都是保证高度适配屏幕,按长宽比保证显示区域。

二、UI的根节点

UI显示区域的最底层节点Root,用于保持UI显示的长宽比。

  • 在Canvas下添加一个Root的空节点
  • Root节点添加Aspect Ratio Fitter组件(锁定长宽比),选择 Height Control Width(按照高度匹配宽度),设置数值按照自己的需求,比如9/16=0.5625
  • Root节点设置RectTransformd的锚点布局为全拉伸。同时将位置、顶部、底部等设置为0,
  • Root节点添加 ‘Rect Mask 2D’ 组件。其作用是确保子节点的UI只显示在Root尺寸的区域内,区域外的不显示。类似于遮罩效果。

这样Root节点便能跟随屏幕变化始终保持最大高度的长宽比显示区域。

UI的搭建就都放在Root节点下即可。

二、背景UI

将背景UI设置的尽可能大
通过shader,以及C#脚本的配合,将Root节点的尺寸作为参照进行对背景UI进行抠图。

实现

一、组件配置

层级布局

层级布局

Canvas Scaler 设置

CanvasScaler 设置

Root节点配置

Root节点设置

二、背景UI的配置

Shader脚本

负责处理图片的渲染

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
Shader "Unlit/UIBoundMask"
{
Properties
{
[PerRendererData]
_MainTex ("Texture", 2D) = "white" {}
_RectCenter ("Rect Center (x,y)", Vector) = (0.5, 0.5, 0, 0) // 中心点坐标
_RectSize ("Rect Size (width, height)", Vector) = (0.5, 0.5, 0, 0) // 宽高
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 100

Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Cull Off

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};

struct v2f
{
float2 uv : TEXCOORD0;
float4 pos : SV_POSITION;
float4 color : COLOR;
};

sampler2D _MainTex;
float2 _RectCenter; // 中心点坐标
float2 _RectSize; // 宽高


v2f vert (appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
o.color = v.color;
return o;
}

fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv) * i.color;

// 计算像素点是否在矩形区域内
float2 uv = i.uv;
float left = _RectCenter.x - _RectSize.x * 0.5;
float right = _RectCenter.x + _RectSize.x * 0.5;
float bottom = _RectCenter.y - _RectSize.y * 0.5;
float top = _RectCenter.y + _RectSize.y * 0.5;

// 判断像素点是否在矩形区域内
float isInsideX = step(left, uv.x) * step(uv.x, right);
float isInsideY = step(bottom, uv.y) * step(uv.y, top);
float isInside = isInsideX * isInsideY; // 像素点如果都在区域内,则结果应该是1,否则是0

if (isInside > 0.5)
{
col.a = 0; // 矩形区域内透明
}

return col;
}
ENDCG
}
}
}

创建 UIBoundMask的材质
材质

C#脚本

负责根据UI尺寸调整Shader渲染的图像,抠出合适的区域。

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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// UI边框遮罩
/// </summary>
[RequireComponent(typeof(RectTransform))]
public class UIBoundMask : MonoBehaviour
{
public Material hollowMaterial; // 将你的材质拖到这个字段
public RectTransform targetRectTransform; // 指定要扣取的UI的RectTransform

private RectTransform backgroundRectTransform;

void Start()
{
backgroundRectTransform = GetComponent<RectTransform>();
UpdateShaderProperties();
}

void Update()
{
// 如果需要实时更新,可以将这行代码放在Update中
// UpdateShaderProperties();
}

void OnRectTransformDimensionsChange()
{
UpdateShaderProperties();
}

void UpdateShaderProperties()
{
if (hollowMaterial == null || targetRectTransform == null || backgroundRectTransform == null)
return;

// 获取目标UI的尺寸和位置
Rect targetRect = targetRectTransform.rect;
Vector2 targetCenter = targetRect.center;
Vector2 targetSize = targetRect.size;

// 获取背景UI的尺寸
Vector2 backgroundSize = backgroundRectTransform.rect.size;

// 将目标UI的中心点转换为背景UI的局部坐标系
Vector2 localCenter = new Vector2(
(targetCenter.x - backgroundRectTransform.rect.xMin) / backgroundSize.x,
(targetCenter.y - backgroundRectTransform.rect.yMin) / backgroundSize.y
);

// 将目标UI的尺寸转换为背景UI的UV坐标
Vector2 uvSize = new Vector2(
targetSize.x / backgroundSize.x,
targetSize.y / backgroundSize.y
);

// 设置Shader属性
hollowMaterial.SetVector("_RectCenter", new Vector4(localCenter.x, localCenter.y, 0, 0));
hollowMaterial.SetVector("_RectSize", new Vector4(uvSize.x, uvSize.y, 0, 0));
}
}

背景UI配置

将Shader赋给一个材质,将材质挂载给背景UI的Image中

添加C#脚本,添加好脚本的挂点。

BoundMask设置

结束

只要运行以下游戏,脚本会修改材质的参数,从而实现抠图。
(由于修改的是材质资源,所以运行一次即可。)

如图:
(六边形、叹号标志都是场景sprite)

效果