一个需求
我需要在场景中截取不同层级的截图(如只截模型或只截UI或只截外部相加看到的画面 或全都截或和Shader配合呈现人眼夜视仪热成像的画面切换)
将截图排到列表中,在场景UI中展示出来
如何做
-
相机要能够看到不同的画面
-
将当前帧画面存储下来
-
将存储的画面展示出来
知识点代码
https://developer.unity.cn/projects/64ca2cbbedbc2a00187ba6d6
下面继续
做一个练习 截屏细节 轮廓+UI 全部三张图分别展示出来
-
首先给游戏对象分好类
-
简单设计一下UI,截图功能会在此操作,截图会在此展示
三个相加分别是Main 场景的主相机,DesktopUI界面UI专门展示的相机, CamTexture专门用来截图操作的相机平时不打开,只在截图时候打开截这个相机渲染的画面
-
CamTexture想要渲染不同的画面就要对他进行不同的设置
public
class
CtrlScreenShot
:
MonoBehaviour
{
//相机渲染
[
Header
(
"可用渲染内容的相机"
)
]
public
Camera
cameraToChange
;
[
Header
(
"具体渲染的Layers"
)
]
public
LayerMask
CullingLayers0
;
public
LayerMask
CullingLayers1
;
public
LayerMask
CullingLayers2
;
// 照片存储的位置
public
Transform
PhotenRoot
;
//截图的大小模板(在场景中透明显示就行,为的就是截图时候按照这个UI的大小去截图)
public
RectTransform
UIRect
;
//
LayerMask
CullingLayers
;
Transform
photenPos
;
string
photenName
;
public
void
CtrlScreenShotBtFc
(
int
butint
)
{
switch
(
butint
)
{
case
0
:
CullingLayers
=
CullingLayers0
;
//相机渲染显示的Layers
photenPos
=
PhotenRoot
.
GetChild
(
0
)
.
transform
;
//截图显示的位置
break
;
case
1
:
CullingLayers
=
CullingLayers1
;
//相机渲染显示的Layers
photenPos
=
PhotenRoot
.
GetChild
(
1
)
.
transform
;
//截图显示的位置
break
;
case
2
:
CullingLayers
=
CullingLayers2
;
//相机渲染显示的Layers
photenPos
=
PhotenRoot
.
GetChild
(
2
)
.
transform
;
//截图显示的位置
break
;
default
:
break
;
}
StartCoroutine
(
StartScreenShot
(
)
)
;
}
///
IEnumerator
StartScreenShot
(
)
{
cameraToChange
.
cullingMask
=
0
;
//全部剔除
cameraToChange
.
cullingMask
=
CullingLayers
;
//显示选择的Layers
cameraToChange
.
gameObject
.
SetActive
(
true
)
;
photenName
=
System
.
DateTime
.
Now
.
ToString
(
"yyyyMMddHHmmss"
)
+
".png"
;
//截图的名字
string
fileName
=
Application
.
dataPath
+
"/StreamingAssets/"
+
photenName
;
//系统不识别标点符号,但支持中文
yield
return
StartCoroutine
(
CaptureByUI
(
UIRect
,
fileName
)
)
;
// 拼接图片路径
string
imagePath
=
System
.
IO
.
Path
.
Combine
(
Application
.
streamingAssetsPath
,
photenName
)
;
// 开始协程加载图片
yield
return
StartCoroutine
(
LoadImage
(
imagePath
,
photenPos
)
)
;
cameraToChange
.
gameObject
.
SetActive
(
false
)
;
}
/// <summary>
/// 保存截图,并保存成png格式文件
/// </summary>
/// <param name="UIRect"></param>屏幕截图的大小尺寸规范 是个透明的imageUI
/// <param name="mFileName"></param>将截图转换成的png文件保存的位置和命名
/// <returns></returns>
IEnumerator
CaptureByUI
(
RectTransform
UIRect
,
string
mFileName
)
{
yield
return
new
WaitForEndOfFrame
(
)
;
//等待当前帧的UI渲染完成
//计算截图的宽度和高度
int
width
=
(
int
)
(
UIRect
.
rect
.
width
)
;
int
height
=
(
int
)
(
UIRect
.
rect
.
height
)
;
//创建一个新的Texture2D对象,宽度和高度与截图的宽度和高度匹配
Texture2D
tex
=
new
Texture2D
(
width
,
height
,
TextureFormat
.
RGB24
,
false
)
;
//计算从屏幕上读取像素的起始位置
float
leftBtmX
=
UIRect
.
transform
.
position
.
x
+
UIRect
.
rect
.
xMin
;
float
leftBtmY
=
UIRect
.
transform
.
position
.
y
+
UIRect
.
rect
.
yMin
;
//使用tex.ReadPixels()函数从屏幕上读取指定区域的像素,并存储到Texture2D中。
tex
.
ReadPixels
(
new
Rect
(
leftBtmX
,
leftBtmY
,
width
,
height
)
,
0
,
0
)
;
//执行读取操作,将修改应用到Texture2D中
tex
.
Apply
(
)
;
//将Texture2D编码为PNG格式的字节数组
byte
[
]
bytes
=
tex
.
EncodeToPNG
(
)
;
//将字节数组保存为PNG图片文件
System
.
IO
.
File
.
WriteAllBytes
(
mFileName
,
bytes
)
;
}
/// <summary>
/// 将保存的png,根据名字在界面上相对位置展示出来
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
IEnumerator
LoadImage
(
string
path
,
Transform
photenPos
)
{
// 发送请求获取图片
UnityWebRequest
www
=
UnityWebRequestTexture
.
GetTexture
(
path
)
;
yield
return
www
.
SendWebRequest
(
)
;
// 检查请求是否成功
if
(
www
.
result
==
UnityWebRequest
.
Result
.
Success
)
{
// 获取加载的Texture
Texture2D
texture
=
DownloadHandlerTexture
.
GetContent
(
www
)
;
//创建一个RawImage并放在其位置
GameObject
uiObject
=
new
GameObject
(
)
;
uiObject
.
transform
.
parent
=
photenPos
.
transform
;
RectTransform
rectTransform
=
uiObject
.
AddComponent
<
RectTransform
>
(
)
;
CanvasRenderer
canvasRenderer
=
uiObject
.
AddComponent
<
CanvasRenderer
>
(
)
;
RawImage
rawImage
=
uiObject
.
AddComponent
<
RawImage
>
(
)
;
// 将加载的Texture赋值给RawImage的texture属性
rawImage
.
texture
=
texture
;
// 调整RawImage的大小以适应图片的长宽比例
rawImage
.
SetNativeSize
(
)
;
// 获取父级图像的宽度
float
parentWidth
=
rawImage
.
transform
.
parent
.
GetComponent
<
RectTransform
>
(
)
.
rect
.
width
;
// 计算图像的长宽比
float
aspectRatio
=
(
float
)
rawImage
.
texture
.
height
/
rawImage
.
texture
.
width
;
// 计算应用于图像的新高度
float
newHeight
=
parentWidth
*
aspectRatio
;
// 设置图像的宽度和高度
rawImage
.
rectTransform
.
sizeDelta
=
new
Vector2
(
parentWidth
,
newHeight
)
;
// 将图像的位置设置为零
rawImage
.
rectTransform
.
localPosition
=
Vector3
.
zero
;
// 将图像的缩放设置为1
rawImage
.
rectTransform
.
localScale
=
Vector3
.
one
;
}
else
{
Debug
.
LogError
(
"Failed to load image: "
+
www
.
error
)
;
}
}
}
用这样的方式在AR里也可以实现拍照的功能 可以切换截取的是现实的或虚拟加现实的等