Unity 中的可定位相机Locatable camera in Unity

启用相片视频相机功能Enabling the capability for Photo Video Camera

必须为应用声明 "网络摄像机" 功能,才能使用 相机The "WebCam" capability must be declared for an app to use the camera.

  1. 在 Unity 编辑器中,导航到 "编辑 > 项目设置 > Player" 页,转到 "播放机" 设置。In the Unity Editor, go to the player settings by navigating to the "Edit > Project Settings > Player" page
  2. 选择 "Windows 应用商店" 选项卡Select the "Windows Store" tab
  3. 在 "发布设置 > 功能" 部分中,检查 网络摄像机麦克风 功能In the "Publishing Settings > Capabilities" section, check the WebCam and Microphone capabilities

照相机一次只能出现一次操作。Only a single operation can occur with the camera at a time. 你可以检查相机目前处于的模式中是否包含 UnityEngine。You can check with mode the camera is currently in with UnityEngine.XR.WSA.WebCam.Mode. 可用模式有照片、视频或无。Available modes are photo, video, or none.

照片捕获Photo Capture

命名空间: UnityEngine. XRNamespace: UnityEngine.XR.WSA.WebCam
类型: PhotoCaptureType: PhotoCapture

PhotoCapture 类型允许你使用照片摄像机拍摄照片。The PhotoCapture type allows you to take still photographs with the Photo Video Camera. 使用 PhotoCapture 拍摄照片的一般模式如下所示:The general pattern for using PhotoCapture to take a photo is as follows:

  1. 创建 PhotoCapture 对象Create a PhotoCapture object
  2. 使用所需的设置创建 CameraParameters 对象Create a CameraParameters object with the settings you want
  3. 通过 StartPhotoModeAsync 启动照片模式Start Photo Mode via StartPhotoModeAsync
  4. 拍摄所需照片Take the photo you want
    • (可选) 与该图片交互(optional) Interact with that picture
  5. 停止照片模式并清理资源Stop Photo Mode and clean up resources

通用设置 PhotoCaptureCommon Set Up for PhotoCapture

对于所有这三个用途,请从上述前三个步骤开始For all three uses, start with the same first three steps above

首先创建 PhotoCapture 对象Start by creating a PhotoCapture object

PhotoCapture photoCaptureObject = null;
   void Start()
   {
       PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
   }

接下来,存储对象、设置参数和启动照片模式Next, store your object, set your parameters, and start Photo Mode

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);
   }

最后,你还将使用此处提供的相同清理代码In the end, you'll also use the same clean-up code presented here

void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
   {
       photoCaptureObject.Dispose();
       photoCaptureObject = null;
   }

完成这些步骤后,你可以选择要捕获哪种类型的照片。After these steps, you can choose which type of photo to capture.

将照片捕获到文件Capture a Photo to a File

最简单的操作是将照片直接捕获到文件中。The simplest operation is to capture a photo directly to a file. 照片可以保存为 JPG 或 PNG。The photo can be saved as a JPG or a PNG.

如果已成功启动照片模式,拍摄照片并将其存储在磁盘上If you successfully started photo mode, take a photo and store it on disk

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!");
       }
   }

将照片捕获到磁盘后,退出照片模式,然后清理对象After capturing the photo to disk, exit photo mode and then clean up your objects

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");
       }
   }

将照片捕获到 Texture2DCapture a Photo to a Texture2D

将数据捕获到 Texture2D 时,该过程类似于捕获到磁盘。When capturing data to a Texture2D, the process is similar to capturing to disk.

按照上面的设置过程进行操作。Follow the setup process above.

OnPhotoModeStarted 中,将帧捕获到内存。In OnPhotoModeStarted, capture a frame to memory.

private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
   {
       if (result.success)
       {
           photoCaptureObject.TakePhotoAsync(OnCapturedPhotoToMemory);
       }
       else
       {
           Debug.LogError("Unable to start photo mode!");
       }
   }

然后,将结果应用到纹理,并使用上面的常见清理代码。You'll then apply your result to a texture and use the common clean-up code above.

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);
   }

捕获照片并与原始字节交互Capture a Photo and Interact with the Raw bytes

若要与内存中帧的原始字节交互,请按照与在 Texture2D 中捕获 照片时相同 的设置步骤进行操作。To interact with the raw bytes of an in memory frame, follow the same setup steps as above and OnPhotoModeStarted as in capturing a photo to a Texture2D. 不同之处在于,可在 OnCapturedPhotoToMemory 中获取原始字节并与其进行交互。The difference is in OnCapturedPhotoToMemory where you can get the raw bytes and interact with them.

在此示例中,你将创建 一个 列表,通过 SetPixels 将其进一步处理或应用于纹理 ( # B1In this example, you'll create a List to be further processed or applied to a texture via 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);
   }

视频捕获Video Capture

命名空间: UnityEngine. XRNamespace: UnityEngine.XR.WSA.WebCam
类型: VideoCaptureType: VideoCapture

VideoCapture 函数类似于 PhotoCaptureVideoCapture functions similarly to PhotoCapture. 唯一的两个不同之处在于,每秒必须指定帧数 (FPS) 值,并且只能将磁盘直接保存为..。The only two differences are that you must specify a Frames Per Second (FPS) value and you can only save directly to disk as a .mp4 file. 使用 VideoCapture 的步骤如下所示:The steps to use VideoCapture are as follows:

  1. 创建 VideoCapture 对象Create a VideoCapture object
  2. 使用所需的设置创建 CameraParameters 对象Create a CameraParameters object with the settings you want
  3. 通过 StartVideoModeAsync 启动视频模式Start Video Mode via StartVideoModeAsync
  4. 开始录制视频Start recording video
  5. 停止录制视频Stop recording video
  6. 停止视频模式并清理资源Stop Video Mode and clean up resources

首先,创建 VideoCapture 对象 VideoCapture m_VideoCapture = null;Start by creating our VideoCapture object VideoCapture m_VideoCapture = null;

void Start ()
   {
       VideoCapture.CreateAsync(false, OnVideoCaptureCreated);
   }

接下来,设置要用于记录和启动的参数。Next, set up the parameters you'll want for the recording and start.

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!");
       }
   }

启动后,开始记录Once started, begin the recording

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 或行为以启用停止。After recording has started, you could update your UI or behaviors to enable stopping. 在这里,你只需记录。Here you just log.

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.
   }

稍后,你将需要使用计时器或用户输入来停止记录,例如。At a later point, you'll want to stop the recording using a timer or user input, for instance.

// The user has indicated to stop recording
   void StopRecordingVideo()
   {
       m_VideoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
   }

录制停止后,停止视频模式并清理资源。Once the recording has stopped, stop video mode and clean up your resources.

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;
   }

疑难解答Troubleshooting

  • 无可用解决方案No resolutions are available
    • 确保在项目中指定了 网络摄像机 功能。Ensure the WebCam capability is specified in your project.

下一个开发检查点Next Development Checkpoint

如果遵循我们所说的 Unity 开发检查点旅程,就是探索混合现实平台功能和 Api。If you're following the Unity development checkpoint journey we've laid out, you're in the midst of exploring the Mixed Reality platform capabilities and APIs. 从这里,你可以继续了解下一个主题:From here, you can continue to the next topic:

或直接跳到在设备或模拟器上部署应用:Or jump directly to deploying your app on a device or emulator:

你可以随时返回到 Unity 开发检查点You can always go back to the Unity development checkpoints at any time.

另请参阅See Also

  • [可定位相机Locatable camera](../platform-capab ilities-and-apis/locatable-camera.md)