- 목차
개요
구 버전 (Arcore SDK) 과의 차이점
- Sample 예제 코드가 줄어듦
- ReadMe를 보면 아직 Foundation에서 사용할 수 없다고 함.
- RawDepth 관련 코드가 달라짐
- Frame을 가져오는 코드들이 달라짐
- SDK에서는 Extern API에서 가져오지만, Foundation에서는 AR관련 오브젝트에서 가져옴.
EventArgs와 XRCpuImage 비교
| Param | Type | Texture Format |
Graphic Format |
Pixel Stride |
Desc |
|---|---|---|---|---|---|
| EventArgs | Frame | RGBA32 | R8G8B8A8 _SRGB |
? | 1920 X 1080 고정 (?) |
| EventArgs | Env Depth |
RHalf | R16_SFloat | ? | 16-bit signed floating-point format that has a single 16-bit R component |
| EventArgs | Conf Depth |
R8 | R8_UNorm | ? | 8-bit unsigned normalized format that has a single 8-bit R component |
| XRCpu Image |
Frame | Android Yuv420_888 |
? | ? | RGBA32 또는 RGB24로 변환해서 사용 |
| XRCpu Image |
Env Depth |
Depth Uint16 |
? | 2 | 16-bit unsigned integer, describing the depth (distance to an object) in millimeters |
| XRCpu Image |
Conf Depth |
One Component8 |
? | 1 | A single channel image format with 8 bits per pixel |
- EventArgs : 기본적인 정보 활용 및 참고용. 텍스쳐 읽기는 가능하나 자체 수정은 되지 않음. 읽기가 가능하기 때문에 텍스쳐를 복사해서 활용하는 방법 이용한다.
- AROcclusionFrameEventArgs : 유효 데이터로는 Texture와 Material 키워드.
- ARCameraFrameEventArgs : AROcclusionFrameEventArgs와는 다르게 ARCamera의 기본 정보도 포함됨.
- XRCpuImage : 이미지 데이터를 Raw (Low Level) 단위로 접근해야할 때. 참고 자료 (Doc)
- XRCpuImage.ConversionParams의 3번째 Parameter에 TextureFormat 입력
- 아래는 CpuImageFormat.cs 파일 내부 AsTextureFormat 함수에서 제공하는 포맷 예시. 보통 Depth 이미지에서만 사용하고, AR이미지는 TextureFormat을 직접 지정한다. 그리고 안드로이드에서는 텍스처 포맷 중 R16 포맷을 지원하지 않는다.)
- 왼쪽이 XRCpuImage.Format → 오른쪽이 TextureFormat (둘이 같은 포맷이 아님)
- OneComponent8 → TextureFormat.R8
- DepthFloat32 → TextureFormat.RFloat
- DepthUint16 → TextureFormat.RFloat
- 미확인 포맷 → 0
AR Foundation
ARCameraManager
XR 카메라 관련. (Intrinsics, DisplayMatrix)
AROcclusionManager
Depth 이미지 관련.
ARCameraBackground.cs
XR 카메라 배경 출력 관련 (Material). 기본 Shader는 Unlit/ARCoreBackground.shader를 사용한다. (하단 코드 참조) (ARCoreCameraSubsystem.cs에서 언급됨). ARCore SDK버전의 카메라 이미지만 다루었다면 AR Foundation에서는 Depth도 같이 취급한다. (ARCore SDK에 있는 큐브 아이콘 관련된 부분도 없어졌다)
대부분의 함수가 접근이 불가능하기 때문에 직접 상속하는 것 보다는 차라리 코드 전체를 복사해서 별도의 클래스를 만들어서 사용하는 것이 편하다.
-
void OnCameraFrameReceived(ARCameraFrameEventArgs eventArgs)
ARCameraManager 콜백 함수. (AR Foundatoin Sample 부분에서 설명한) CameraConfiguration에서 지정한 설정대로로 텍스쳐를 받을 수 있음. 아래 목록을 로그를 출력했을때 나온 결과의 예시 이며, 이 값은 단말기마다 다를 수 있다.- Shader property name : _MainTex
- Texture format : RGBA32
- Graphic format : R8G8B8A8_SRGB
- Texture size : 1920x1080 (CameraConfiguration가 적용되지 않음. 확인 필요)
- eventArgs.enabledMaterialKeywords, disabledMaterialKeywords : 따로 나오는 것은 없음.
-
(추가 사항) ARCameraManager.TryAcquireLatestCpuImage(out XRCpuImage xrCpuImage)
- Texture size (CameraConfiguration 설정에 영향)
- 640x480
- 1280x720
- 1920x1080
- Texture format : AndroidYuv420_888 → 참조 : 관련 문서 링크 (5.0 버전으로 대체)
- Texture size (CameraConfiguration 설정에 영향)
-
void OnOcclusionFrameReceived(AROcclusionFrameEventArgs eventArgs)
- 공통 사항
- Texture size (CameraConfiguration 설정에 영향을 받음)
- 160x90 : 기본값
- 640x360 : Depth sensor 지원 기종에 한하여 추가적으로 제공
- Texture size (CameraConfiguration 설정에 영향을 받음)
- (0)번 텍스쳐 : ARCORE_ENVIRONMENT_DEPTH_ENABLED
- Shader Property name : _EnvironmentDepth
- Texture format : RHalf (Scalar ® texture format, 16bit floating point. 즉, R값만 16bit에 걸쳐서 표시)
- Graphic format : R16_SFloat (A one-component, 16-bit signed floating-point format that has a single 16-bit R component.)
- (1)번 텍스쳐
- eventArgs.enabledMaterialKeywords : ARCORE_ENVIRONMENT_DEPTH_ENABLED (ARCoreBackground.shader에 있는 프로퍼티)
- eventArgs.disalbedMaterialKeywords : 따로 검출 안됨.
- 공통 사항
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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | // 이 Shader 코드는 "com.unity.xr.arcore@패키지버전\Assets\Shaders"에 위치해있는데, // 패키지 내부에 있기 때문에 실제로는 "프로젝트 경로\Library\PackageCache\위에 적은 경로"에 존재한다. Shader "Unlit/ARCoreBackground" { Properties { _MainTex("Texture", 2D) = "white" {} _EnvironmentDepth("Texture", 2D) = "black" {} } SubShader { Tags { "Queue" = "Background" "RenderType" = "Background" "ForceNoShadowCasting" = "True" } Pass { Cull Off ZTest Always ZWrite On Lighting Off LOD 100 Tags { "LightMode" = "Always" } GLSLPROGRAM #pragma multi_compile_local __ ARCORE_ENVIRONMENT_DEPTH_ENABLED #pragma only_renderers gles3 #include "UnityCG.glslinc" #ifdef SHADER_API_GLES3 #extension GL_OES_EGL_image_external_essl3 : require #endif // SHADER_API_GLES3 // Device display transform is provided by the AR Foundation camera background renderer. uniform mat4 _UnityDisplayTransform; #ifdef VERTEX varying vec2 textureCoord; void main() { #ifdef SHADER_API_GLES3 // Transform the position from object space to clip space. gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; // Remap the texture coordinates based on the device rotation. textureCoord = (_UnityDisplayTransform * vec4(gl_MultiTexCoord0.x, 1.0f - gl_MultiTexCoord0.y, 1.0f, 0.0f)).xy; #endif // SHADER_API_GLES3 } #endif // VERTEX #ifdef FRAGMENT varying vec2 textureCoord; uniform samplerExternalOES _MainTex; uniform float _UnityCameraForwardScale; #ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED uniform sampler2D _EnvironmentDepth; #endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED #if defined(SHADER_API_GLES3) && !defined(UNITY_COLORSPACE_GAMMA) float GammaToLinearSpaceExact (float value) { if (value <= 0.04045F) return value / 12.92F; else if (value < 1.0F) return pow((value + 0.055F)/1.055F, 2.4F); else return pow(value, 2.2F); } vec3 GammaToLinearSpace (vec3 sRGB) { // Approximate version from http://chilliant.blogspot.com.au/2012/08/srgb-approximations-for-hlsl.html?m=1 return sRGB * (sRGB * (sRGB * 0.305306011F + 0.682171111F) + 0.012522878F); // Precise version, useful for debugging, but the pow() function is too slow. // return vec3(GammaToLinearSpaceExact(sRGB.r), GammaToLinearSpaceExact(sRGB.g), GammaToLinearSpaceExact(sRGB.b)); } #endif // SHADER_API_GLES3 && !UNITY_COLORSPACE_GAMMA float ConvertDistanceToDepth(float d) { d = _UnityCameraForwardScale > 0.0 ? _UnityCameraForwardScale * d : d; float zBufferParamsW = 1.0 / _ProjectionParams.y; float zBufferParamsY = _ProjectionParams.z * zBufferParamsW; float zBufferParamsX = 1.0 - zBufferParamsY; float zBufferParamsZ = zBufferParamsX * _ProjectionParams.w; // Clip any distances smaller than the near clip plane, and compute the depth value from the distance. return (d < _ProjectionParams.y) ? 1.0f : ((1.0 / zBufferParamsZ) * ((1.0 / d) - zBufferParamsW)); } void main() { #ifdef SHADER_API_GLES3 vec3 result = texture(_MainTex, textureCoord).xyz; float depth = 1.0; #ifdef ARCORE_ENVIRONMENT_DEPTH_ENABLED float distance = texture(_EnvironmentDepth, textureCoord).x; depth = ConvertDistanceToDepth(distance); #endif // ARCORE_ENVIRONMENT_DEPTH_ENABLED #ifndef UNITY_COLORSPACE_GAMMA result = GammaToLinearSpace(result); #endif // !UNITY_COLORSPACE_GAMMA gl_FragColor = vec4(result, 1.0); gl_FragDepth = depth; #endif // SHADER_API_GLES3 } #endif // FRAGMENT ENDGLSL } } FallBack Off } | cs |
Project structure
Common
class MotionStereoDepthDataSource (Script)
- private void InitializeCameraIntrinsics()
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 | //AR Foundation 버전의 InitializeCameraIntrinsics /// <summary> /// Queries and correctly scales camera intrinsics for depth to vertex reprojection. /// </summary> private void InitializeCameraIntrinsics() { if (ARSession.state != ARSessionState.SessionTracking) { Debug.LogWarningFormat("ARSession is not ready yet: {0}", ARSession.state); return; } _cameraManager ??= Object.FindObjectOfType<ARCameraManager>(); Debug.Assert(_cameraManager); _cameraManager.frameReceived += OnCameraFrameReceived; _occlusionManager ??= Object.FindObjectOfType<AROcclusionManager>(); Debug.Assert(_occlusionManager); // Enable smooth depth by default. _occlusionManager.environmentDepthTemporalSmoothingRequested = !_useRawDepth; _cameraBackground ??= Object.FindObjectOfType<ARCameraBackground>(); Debug.Assert(_cameraBackground); // Gets the camera parameters to create the required number of vertices. if (!_cameraManager.TryGetIntrinsics(out XRCameraIntrinsics cameraIntrinsics)) { Debug.LogError("MotionStereoDepthDataSource: Failed to obtain camera intrinsics."); return; } // Scales camera intrinsics to the depth map size. Vector2 intrinsicsScale; intrinsicsScale.x = _depthWidth / (float)cameraIntrinsics.resolution.x; intrinsicsScale.y = _depthHeight / (float)cameraIntrinsics.resolution.y; var focalLength = Utilities.MultiplyVector2(cameraIntrinsics.focalLength, intrinsicsScale); var principalPoint = Utilities.MultiplyVector2(cameraIntrinsics.principalPoint, intrinsicsScale); var resolution = new Vector2Int(_depthWidth, _depthHeight); _depthCameraIntrinsics = new XRCameraIntrinsics(focalLength, principalPoint, resolution); //요 부분은 디버깅을 위해 임의로 출력한 부분 Debug.Log(nameof(MotionStereoDepthDataSource) + " print value =======" +"\n==> Depth width, height : (" + _depthWidth + "//" + _depthHeight + ")" +"\n==> Camera intrinsics (focalLength) : ("+ cameraIntrinsics.focalLength + ")" +"\n==> Camera intrinsics (resolution) : ("+ cameraIntrinsics.resolution + ")" +"\n==> Camera intrinsics (principalPoint) : ("+ cameraIntrinsics.principalPoint + ")" +"\n==> Depth intrinsics (focalLength) : ("+ focalLength + ")" +"\n==> Depth intrinsics (resolution) : ("+ resolution + ")" +"\n==> Depth intrinsics (principalPoint) : ("+ principalPoint + ")" ); //Depth 요소들이 0이 아니어야 초기화가 완료된 것이다. //따라서 아래의 UpdateEnvironmentDepthImage 함수가 호출되고 나서 초기화가 완료된다. if (_depthCameraIntrinsics.resolution != Vector2.zero) { _initialized = true; Debug.Log("MotionStereoDepthDataSource intrinsics initialized."); } } | cs |
XRCameraIntrinsics 값은 앱을 시작할 때 (조금씩) 바뀌지만, 앱 시작 중에는 (별다른 조작이 없는한) 변화하지 않는다.
클래스 Initialized 단에서 호출 (Init가 완료 될 때까지 Update 함수 단에서 게속 호출된다).
디버깅을 위해 작성한 Log 구문의 처음 작동시에는 DepthIntrinscis 관련 값이 0으로 나온다 (초기에는 DepthWidth, DepthHeight가 0으로 초기화 되어 있기 때문).
하단에 서술하고 있는 UpdateEnvironmentDepthImage 함수를 거치고나서 (DepthWidth, DepthHeight가 정의되서) DepthIntrinscis가 정의된다.
| 구글 ARCore 에서 명시된 Depth API 차이 |
|---|
- void UpdateEnvironmentDepthImage()
Depth 이미지를 가져오는 메서드. Depth 이미지가 스펙트럼 색상(무지개 같은 색상)으로 구성 되어있다.
XRCpuImage 에서 반환되는 값은 다음과 같다. (useRawDepth = true)
- Width x Height : 160 x 90 (기본값), 640 X 360 (Depth Sensor 지원) (CameraConfiguration 설정에 영향)
- pixelStride = 2
- Format : 16bit unsigned integer (enum 타입이며 저장된 값은 DepthUint16 → 참조 : 관련 문서 링크 (5.0 버전으로 대체))
- 코드에 대한 뇌피셜(?)
- Unity Document에 표시된 DepthUint16 : 16-bit unsigned integer, describing the depth (distance to an object) in millimeters
- 2byte (16bit)를 이용하여 알파값 없는 RGB565를 표시 (R:5bit, G:6bit, B:5bit)
※ Depth 관련 데이터는 AROcclusionMananger에서 가져온다.
...
// 전역변수
private byte[] _depthBuffer = new byte[0];
...
void UpdateEnvironmentDepthImage()
{
// CameraConfiguration 변경 후, 조금 시간이 지난 후 값을 가져와야 값이 반영되는 것으로 보임 (이미지 사이즈)
if (_occlusionManager &&
_occlusionManager.TryAcquireEnvironmentDepthCpuImage(out XRCpuImage image))
{
using (image)
{
_depthWidth = image.width; //160
_depthHeight = image.height; //90
// Depth data를 저장하는 방법 (1) : 16bit 데이터를 1byte 배열에 저장 (한 pixel을 2byte에 표시함)
int numPixels = image.width * image.height;
int numBytes = numPixels * image.GetPlane(0).pixelStride; //pixelStride = 2
if (_depthBuffer.Length != numBytes)
{
_depthBuffer = new byte[numBytes];
}
//_depthBuffer를 같은 Length의 short 배열에 Buffer.BlockCopy를 해도된다.
image.GetPlane(0).data.CopyTo(_depthBuffer);
// ///////////////////////////////////////////////
// Depth data를 저장하는 방법 (2) : Texture2D (RFloat) 형식으로 저장 (흑백으로 저장됨)
var depthTextureFormat = image.format.AsTextureFormat(); //RFloat
Texture2D _depthRFloatTexture = new Texture2D(_depthWidth, _depthHeight, depthTextureFormat, false);
var dTextureRawTextureData = _depthRFloatTexture.GetRawTextureData<byte>();
XRCpuImage.Transformation transformation = XRCpuImage.Transformation.None
var conversionParams = new XRCpuImage.ConversionParams(image, depthTextureFormat, transformation);
image.Convert(conversionParams, dTextureRawTextureData);
image.Dispose();
_depthRFloatTexture.Apply();
}
}
}
-
void UpdateEnvironmentDepthConfidenceImage()
위에 있는 UpdateEnvironmentDepthImage 메서드에서 출력되는 이미지를 grayscale 처리했다고 생각하면된다. 여기서 UpdateRawImage 함수를 사용하는 이유는 XRCpuImage 클래스를 Texture2D로 형변환하기 위해서라고 생각하면된다.
XRCpuImage 에서 반환되는 값은 다음과 같다. (useRawDepth = true) -
Width x Height : 160 x 90 (기본값), 640 X 360 (Depth Sensor 지원) (CameraConfiguration 설정에 영향)
-
pixelStride = 1
-
Format : Single channel 8bit (enum 타입이며 저장된 값은 OneComponenet8 → 참조 : 관련 문서 링크 (5.0 버전으로 대체))
※ 문서상에서 confidence depth는 raw depth 기능을 활성화 되었을 때, 사용할 수 있는 기능이라고 명시되어 있다.
관련 문서 링크
void UpdateEnvironmentDepthConfidenceImage()
{
if (_occlusionManager &&
_occlusionManager.TryAcquireEnvironmentDepthConfidenceCpuImage(out XRCpuImage image))
{
using (image)
{
UpdateRawImage(ref _confidenceTexture, image, TextureFormat.R8, TextureFormat.R8);
}
}
}
static void UpdateRawImage(ref Texture2D texture, XRCpuImage cpuImage,
TextureFormat conversionFormat, TextureFormat textureFormat)
{
if (texture == null || texture.width != cpuImage.width || texture.height != cpuImage.height)
{
texture = new Texture2D(cpuImage.width, cpuImage.height, textureFormat, false);
}
var conversionParams = new XRCpuImage.ConversionParams(cpuImage, conversionFormat);
var rawTextureData = texture.GetRawTextureData<byte>();
cpuImage.Convert(conversionParams, rawTextureData);
texture.Apply();
}
class ARBackgroundMaterialReplacer.cs (Script)
ARCameraBackground를 이용해 사용자 정의 재질(또는 쉐이더)을 지정하면, 임의의 XR 카메라 배경을 출력하도록 할 수 있다.
DisplayMatrix
CameraManager에서 가져온 이미지(1920 X 1080)를 단말기 (S20 Ultra : 2326 X 1080, S21 : 2320 X 1080)에 렌더링시 적용한 행렬을 뜻함. 당연히 단말마다 다르다. 아래 코드는 XRCameraFrameExtensions::GetImageDisplayMatrix에 관한 내용이다.
//-----------------------------------------------------------------------
// <copyright file="XRCameraFrameExtensions.cs" company="Google LLC">
//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// </copyright>
//-----------------------------------------------------------------------
namespace Google.XR.ARCoreExtensions
{
using System;
using Google.XR.ARCoreExtensions.Internal;
using UnityEngine;
using UnityEngine.XR.ARSubsystems;
/// <summary>
/// Extensions to AR Subsystem's XRCameraFrame struct.
/// </summary>
public static class XRCameraFrameExtensions
{
/// <summary>
/// Get the 4x4 image display matrix for the camera frame. This is used by the texture
/// populated based on CPU images
/// to calculate the display coordinates.
/// </summary>
/// <param name="frame">The XRCameraFrame instance.</param>
/// <returns>The 4x4 image display matrix.</returns>
public static Matrix4x4 GetImageDisplayMatrix(this XRCameraFrame frame)
{
// Unity Screen Coordinate: Android Screen Coordinate (flipped Y-Axis):
// (0, 1) (1, 1) (0, 0) (1, 0)
// |----------------| |----------------|
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// | | | |
// |----------------| |----------------|
// (0, 0) (1, 0) (0, 1) (1, 1)
IntPtr sessionHandle = ARCoreExtensions._instance.currentARCoreSessionHandle;
if (sessionHandle == IntPtr.Zero)
{
return Matrix4x4.identity;
}
// X-Axis (1, 0) in Unity view maps to (1, 1) on Android screen.
Vector2 affineBasisX = new Vector2(1.0f, 1.0f);
// Y-Axis (0, 1) in Unity view maps to (0, 0) on Android screen.
Vector2 affineBasisY = new Vector2(0.0f, 0.0f);
// Origin (0, 0) in Unity view maps to (0, 1) on Android screen.
Vector2 affineOrigin = new Vector2(0.0f, 1.0f);
Vector2 transformedX = FrameApi.TransformCoordinates2d(
sessionHandle, frame.FrameHandle(), ApiCoordinates2dType.ViewNormalized,
ApiCoordinates2dType.ImageNormalized, ref affineBasisX);
Vector2 transformedY = FrameApi.TransformCoordinates2d(
sessionHandle, frame.FrameHandle(), ApiCoordinates2dType.ViewNormalized,
ApiCoordinates2dType.ImageNormalized, ref affineBasisY);
Vector2 transformedOrigin = FrameApi.TransformCoordinates2d(
sessionHandle, frame.FrameHandle(), ApiCoordinates2dType.ViewNormalized,
ApiCoordinates2dType.ImageNormalized, ref affineOrigin);
Matrix4x4 imageMatrix = Matrix4x4.identity;
imageMatrix[0, 0] = transformedX.x - transformedOrigin.x;
imageMatrix[0, 1] = transformedX.y - transformedOrigin.y;
imageMatrix[1, 0] = transformedY.x - transformedOrigin.x;
imageMatrix[1, 1] = transformedY.y - transformedOrigin.y;
imageMatrix[2, 0] = transformedOrigin.x;
imageMatrix[2, 1] = transformedOrigin.y;
return imageMatrix;
}
}
}
-
XR에서 설정한 Configuration : (1920, 1080)
-
DisplayMatrix
1.0000 0.0000 0.0000 0.0000
0.0000 0.8255 0.0873 0.0000
0.0000 0.0000 0.0000 0.0000
0.0000 0.0000 0.0000 0.0000 -
UV 계산 : 결과 값을 살펴보면 XR 이미지의 위아래로 Crop된 영역을 단말기에 Display한다는 것을 알수 있음
- (UV) LeftTop 유도 : Vector2 leftTop = displayMatrix * new Vector4(0f, 1f, 1f, 0f) = (0.0000, 약 0.9127) //operator 정의로 Vector4에서 z, w 요소가 제거되어 x, y만 Vector2로 저장됨.
- ≒ 0.8255 + 0.0873 ≒ 0.9127
- (UV) RightBottom 유도 : Vector2 rightBottom = displayMatrix * new Vector4(1f, 0f, 1f, 0f) = (1.0000, 약 0.0873) //operator 정의로 Vector4에서 z, w 요소가 제거되어 x, y만 Vector2로 저장됨.
- ≒ 0.0873
- 위아래 비율값 차이 = 높이 비율값 : 0.9127 - 0.0873 = 0.8254
- 단말기에서 Display되는 XR 이미지의 높이값 : 1080 (단말기의 높이) * 0.8254 = 약 891.432 ← XR 이미지에서 해당 사이즈 부분에서 어떤 상수를 곱하여 1080으로 확대한 후, 단말기에 실제로 Display됨
- (UV) LeftTop 유도 : Vector2 leftTop = displayMatrix * new Vector4(0f, 1f, 1f, 0f) = (0.0000, 약 0.9127) //operator 정의로 Vector4에서 z, w 요소가 제거되어 x, y만 Vector2로 저장됨.
-
S20 Ultra에서 ScreenShot Size = 실제 단말에서 보이는 크기 (Screen Size) : (2326, 1080)
- (세로 값) 891.432가 1080이 되기 위해서는 어떤 상수를 곱해야하는가 (Scale 값 계산) : 1080 / 891.432 = 약 1.211533802 (이거 계산할 필요가 있었나???)
- (가로 값) 1920에 구한 Scale 값을 곱하면 : 1920 * 1.211533802 = 약 2326.1449

댓글
댓글 쓰기