Unity 中的相片視訊相機
啟用相機存取的功能
必須宣告 「WebCam」功能,應用程式才能使用 相機。
- 在 Unity 編輯器中,流覽至 [編輯 > 專案設定 > 播放機] 頁面,以移至播放機設定
- 選取 [Windows 市集] 索引標籤
- 在 [發佈設定 > 功能] 區段中,檢查 WebCam 和 麥克風 功能
相機一次只能進行單一作業。 您可以在 Unity 2018 和更早版本或 UnityEngine.Windows.WebCam.Mode
Unity 2019 和更新版本中檢查相機目前使用的UnityEngine.XR.WSA.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 提供了將投影矩陣套用至其論壇上特定著色器的範例程序代碼 。
擷取相片並與原始位元組互動
若要與記憶體框架中的原始位元組互動,請遵循上述和 OnPhotoModeStarted 相同的設定步驟,如同將相片擷取到 Texture2D 一樣。 差異在於 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;
}
疑難排解
- 沒有可用的解決方案
- 確定您的專案中已指定 WebCam 功能。
下一個開發檢查點
如果您遵循我們提出的 Unity 開發檢查點旅程,您正在探索混合實境平臺功能和 API。 接下來,您可以繼續進行下一個主題:
或者,直接跳到在裝置或模擬器上部署應用程式的主題:
您可以隨時回到 Unity 開發檢查點。