Unity 中的照片/视频摄像头
启用相机访问功能
必须声明“网络摄像头”功能,应用才能使用相机。
- 在 Unity 编辑器中,导航到“编辑”>“项目设置”>“玩家”页,转到“玩家设置”
- 选择“Windows Store”选项卡
- 在“发布设置”>“功能”部分,选中“网络摄像头”和“麦克风”功能
每次只能使用相机执行一次操作。 可以使用 Unity 2018 和更低版本中的 UnityEngine.XR.WSA.WebCam.Mode
或者 Unity 2019 和更高版本中的 UnityEngine.Windows.WebCam.Mode
来检查相机当前所处的模式。 可用模式为照片、视频或无。
拍照
命名空间(在 Unity 2019 之前):UnityEngine.XR.WSA.WebCam
命名空间(Unity 2019 及更高版本):UnityEngine.Windows.WebCam
类型:PhotoCapture
PhotoCapture 类型允许使用照片视频相机拍摄静态照片。 使用 PhotoCapture 拍照的一般模式如下:
- 创建 PhotoCapture 对象
- 使用所需的设置创建 CameraParameters 对象
- 通过 StartPhotoModeAsync 启动照片模式
- 拍摄所需的照片
- (可选)与该照片交互
- 停止照片模式并清理资源
PhotoCapture 的通用设置
对于所有三种用途,请从上述前三个步骤开始
首先创建 PhotoCapture 对象
private void Start()
{
PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
}
接下来,存储该对象,设置参数,然后启动照片模式
private PhotoCapture photoCaptureObject = null;
void OnPhotoCaptureCreated(PhotoCapture captureObject)
{
photoCaptureObject = captureObject;
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
CameraParameters c = new CameraParameters();
c.hologramOpacity = 0.0f;
c.cameraResolutionWidth = cameraResolution.width;
c.cameraResolutionHeight = cameraResolution.height;
c.pixelFormat = CapturePixelFormat.BGRA32;
captureObject.StartPhotoModeAsync(c, false, OnPhotoModeStarted);
}
最后,你还将使用此处所述的相同清理代码
void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
{
photoCaptureObject.Dispose();
photoCaptureObject = null;
}
完成这些步骤后,可以选择要拍摄的照片类型。
将照片捕获到文件
最简单的操作是将照片直接捕获到文件中。 照片可以保存为 JPG 或 PNG。
如果成功启动了照片模式,请拍照并将其存储在磁盘上
private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
string filename = string.Format(@"CapturedImage{0}_n.jpg", Time.time);
string filePath = System.IO.Path.Combine(Application.persistentDataPath, filename);
photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
}
else
{
Debug.LogError("Unable to start photo mode!");
}
}
将照片捕获到磁盘后,退出照片模式,然后清理对象
void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
Debug.Log("Saved Photo to disk!");
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
else
{
Debug.Log("Failed to save Photo to disk");
}
}
使用定位将照片捕获到 Texture2D
将数据捕获到 Texture2D 的过程类似于捕获到磁盘。
请按照上面的设置过程进行操作。
在 OnPhotoModeStarted 中,将某一帧捕获到内存中。
private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
if (result.success)
{
photoCaptureObject.TakePhotoAsync(OnCapturedPhotoToMemory);
}
else
{
Debug.LogError("Unable to start photo mode!");
}
}
然后,将结果应用于纹理并使用上面的通用清理代码。
void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
if (result.success)
{
// Create our Texture2D for use and set the correct resolution
Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
Texture2D targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);
// Copy the raw image data into our target texture
photoCaptureFrame.UploadImageDataToTexture(targetTexture);
// Do as we wish with the texture such as apply it to a material, etc.
}
// Clean up
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
可定位相机
若要将此纹理放在场景中并使用可定位相机矩阵来显示它,请将以下代码添加到 result.success
检查中的 OnCapturedPhotoToMemory:
if (photoCaptureFrame.hasLocationData)
{
photoCaptureFrame.TryGetCameraToWorldMatrix(out Matrix4x4 cameraToWorldMatrix);
Vector3 position = cameraToWorldMatrix.GetColumn(3) - cameraToWorldMatrix.GetColumn(2);
Quaternion rotation = Quaternion.LookRotation(-cameraToWorldMatrix.GetColumn(2), cameraToWorldMatrix.GetColumn(1));
photoCaptureFrame.TryGetProjectionMatrix(Camera.main.nearClipPlane, Camera.main.farClipPlane, out Matrix4x4 projectionMatrix);
}
Unity 在其论坛上提供了将投影矩阵应用于特定着色器的示例代码。
拍摄照片并与原始字节交互
若要与内存中帧的原始字节交互,请按照与将照片捕获到 Texture2D 时相同的设置步骤和 OnPhotoModeStarted 进行操作。 不同之处在于 OnCapturedPhotoToMemory,可以在其中获取原始字节并与之交互。
在此示例中,你将创建一个通过 SetPixels() 进一步处理或应用于纹理的列表
void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
if (result.success)
{
List<byte> imageBufferList = new List<byte>();
// Copy the raw IMFMediaBuffer data into our empty byte list.
photoCaptureFrame.CopyRawImageDataIntoBuffer(imageBufferList);
// In this example, we captured the image using the BGRA32 format.
// So our stride will be 4 since we have a byte for each rgba channel.
// The raw image data will also be flipped so we access our pixel data
// in the reverse order.
int stride = 4;
float denominator = 1.0f / 255.0f;
List<Color> colorArray = new List<Color>();
for (int i = imageBufferList.Count - 1; i >= 0; i -= stride)
{
float a = (int)(imageBufferList[i - 0]) * denominator;
float r = (int)(imageBufferList[i - 1]) * denominator;
float g = (int)(imageBufferList[i - 2]) * denominator;
float b = (int)(imageBufferList[i - 3]) * denominator;
colorArray.Add(new Color(r, g, b, a));
}
// Now we could do something with the array such as texture.SetPixels() or run image processing on the list
}
photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}
视频视频
命名空间(在 Unity 2019 之前):UnityEngine.XR.WSA.WebCam
命名空间(Unity 2019 及更高版本):UnityEngine.Windows.WebCam
类型:VideoCapture
VideoCapture 的作用类似于 PhotoCapture。 唯一的两个差别是,必须指定每秒帧数 (FPS) 值,并且只能作为 .mp4 文件直接保存到磁盘。 VideoCapture 的使用步骤如下:
- 创建 VideoCapture 对象
- 使用所需的设置创建 CameraParameters 对象
- 通过 StartVideoModeAsync 启动视频模式
- 开始录制视频
- 停止录制视频
- 停止视频模式并清理资源
首先创建 VideoCapture 对象 VideoCapture m_VideoCapture = null;
void Start ()
{
VideoCapture.CreateAsync(false, OnVideoCaptureCreated);
}
接下来,设置所需的录制参数并启动。
void OnVideoCaptureCreated(VideoCapture videoCapture)
{
if (videoCapture != null)
{
m_VideoCapture = videoCapture;
Resolution cameraResolution = VideoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
float cameraFramerate = VideoCapture.GetSupportedFrameRatesForResolution(cameraResolution).OrderByDescending((fps) => fps).First();
CameraParameters cameraParameters = new CameraParameters();
cameraParameters.hologramOpacity = 0.0f;
cameraParameters.frameRate = cameraFramerate;
cameraParameters.cameraResolutionWidth = cameraResolution.width;
cameraParameters.cameraResolutionHeight = cameraResolution.height;
cameraParameters.pixelFormat = CapturePixelFormat.BGRA32;
m_VideoCapture.StartVideoModeAsync(cameraParameters,
VideoCapture.AudioState.None,
OnStartedVideoCaptureMode);
}
else
{
Debug.LogError("Failed to create VideoCapture Instance!");
}
}
启动后,开始录制
void OnStartedVideoCaptureMode(VideoCapture.VideoCaptureResult result)
{
if (result.success)
{
string filename = string.Format("MyVideo_{0}.mp4", Time.time);
string filepath = System.IO.Path.Combine(Application.persistentDataPath, filename);
m_VideoCapture.StartRecordingAsync(filepath, OnStartedRecordingVideo);
}
}
开始录制后,可以更新 UI 或行为以启用停止。 此处只需进行日志记录。
void OnStartedRecordingVideo(VideoCapture.VideoCaptureResult result)
{
Debug.Log("Started Recording Video!");
// We will stop the video from recording via other input such as a timer or a tap, etc.
}
稍后,需要使用计时器或用户输入等方式来停止录制。
// The user has indicated to stop recording
void StopRecordingVideo()
{
m_VideoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
}
录制停止后,停止视频模式并清理资源。
void OnStoppedRecordingVideo(VideoCapture.VideoCaptureResult result)
{
Debug.Log("Stopped Recording Video!");
m_VideoCapture.StopVideoModeAsync(OnStoppedVideoCaptureMode);
}
void OnStoppedVideoCaptureMode(VideoCapture.VideoCaptureResult result)
{
m_VideoCapture.Dispose();
m_VideoCapture = null;
}
疑难解答
- 没有可用的解决方法
- 确保在项目中指定了“网络摄像头”功能。
下一个开发检查点
如果遵循我们规划的 Unity 开发检查点旅程,则你正处于探索混合现实平台功能和 API 的过程之中。 从这里,你可以继续了解下一个主题:
或直接跳到在设备或模拟器上部署应用:
你可以随时返回到 Unity 开发检查点。