Xamarin.ios에서 ARKit를 사용 하 여 UrhoSharp 사용Using ARKit with UrhoSharp in Xamarin.iOS

Arkit가 도입 되면서 Apple은 개발자가 확장 된 현실 응용 프로그램을 간편 하 게 만들 수 있게 되었습니다.With the introduction of ARKit, Apple has made it simple for developers to create augmented reality applications. ARKit는 장치의 정확한 위치를 추적 하 고 전 세계 다양 한 화면을 검색할 수 있으며, 개발자는 ARKit에서 제공 되는 데이터를 코드에 혼합할 수 있습니다.ARKit can track the exact position of your device and detect various surfaces on the world, and it is then up to the developer to blend the data coming out of ARKit into your code.

Urhosharp 는 3d 응용 프로그램을 만드는 데 사용할 수 있는 포괄적이 고 사용 하기 쉬운 3d API를 제공 합니다.UrhoSharp provides a comprehensive and easy to use 3D API that you can use to create 3D applications. 둘 다 함께 혼합할 수 있습니다. ARKit는 전 세계에 대 한 물리적 정보를 제공 하 고, 결과를 렌더링 하는 Urho를 제공 합니다.Both of these can be blended together, ARKit to provide the physical information about the world, and Urho to render the results.

이 페이지에서는 이러한 두 가지를 함께 연결 하 여 뛰어난 확대 현실 응용 프로그램을 만드는 방법을 설명 합니다.This page explains how to connect these two worlds together to create great augmented reality applications.

기본 사항The Basics

IPhone/iPad에서 볼 수 있듯이 전 세계에 3D 콘텐츠가 제공 됩니다.What we want to do is present 3D content on top of the world as seen by the iPhone/iPad. 여기서는 장치 카메라에서 제공 되는 콘텐츠를 3D 콘텐츠와 혼합 하 고, 장치 사용자가 공간을 중심으로 이동 하 여 3D 개체가 해당 대화방의 일부인 것 처럼 동작 하도록 하는 것이 좋습니다 .이 작업은 개체를이 세계에 고정 하 여 수행 됩니다.The idea is to blend the contents coming from the device’s camera with the 3D content, and as the user of the device moves around the room to ensure that the 3D object behave as is they part of that room - this is done by anchoring the objects into this world.

ARKit의 애니메이션 그림

여기서는 Urho 라이브러리를 사용 하 여 3D 자산을 로드 하 고 전 세계에 배치 하며, ARKit를 사용 하 여 카메라에서 들어오는 비디오 스트림과 전 세계의 휴대폰 위치를 가져옵니다.We will be using the Urho library to load our 3D assets and place them on the world, and we will be using ARKit to get the video stream coming from the camera as well as the location of the phone in the world. 사용자가 휴대폰으로 이동 하면 위치에서 변경 사항을 사용 하 여 Urho 엔진이 표시 하는 좌표계를 업데이트 합니다.As the user moves with his phone, we will use the changes in the location to update the coordinate system that the Urho engine is displaying.

이러한 방식으로 3D 공간에 개체를 배치 하 고 사용자가 이동할 때 3D 개체의 위치는 위치와 위치가 배치 된 위치를 반영 합니다.This way, when you place an object in the 3D space and the user moves, the location of the 3D object reflects the place and location where it was placed.

응용 프로그램 설정Setting up your application

iOS 응용 프로그램 시작iOS Application Launch

IOS 응용 프로그램에서 3d 콘텐츠를 만들고 시작 해야 합니다 Urho.Application .이 작업을 수행 하려면의 서브 클래스를 구현 하 고 메서드를 Start 재정의 하 여 설치 코드를 제공 합니다.Your iOS application needs to create and launch your 3D content, you do this by creating an implementing a subclass of the Urho.Application and provide your setup code by overriding the Start method. 여기서는 장면을 데이터로 채우고 이벤트 처리기를 설정 하는 등의 방법을 사용 합니다.This is where your scene gets populated with data, event handlers are setup and so on.

서브 Urho.ArkitApp Start 클래스와 해당 메서드의 메서드가 많은 리프트를 수행 하는 클래스를 도입 했습니다. Urho.ApplicationWe have introduced an Urho.ArkitApp class that subclasses Urho.Application and on its Start method does the heavy lifting. 기존 urho 응용 프로그램에 대 한 모든 작업을 수행 하려면 기본 클래스를 형식 Urho.ArkitApp 으로 변경 하 고 전 세계에서 urho 장면을 실행 하는 응용 프로그램을 만들어야 합니다.All you need to do to your existing Urho application is change the base class to be of type Urho.ArkitApp and you have an application that will run your urho Scene in the world.

ArkitApp 클래스The ArkitApp Class

이 클래스는 운영 체제에서 제공 하는 ARKit 이벤트의 처리 뿐만 아니라 몇 가지 주요 개체를 포함 하는 장면의 편리한 기본값 집합을 제공 합니다.This class provides a set of convenient defaults, both a scene with some key objects as well as the processing of ARKit events as they are delivered by the operating system.

설치 프로그램이 Start 가상 메서드에서 수행 됩니다.The setup takes place in the Start virtual method. 서브 클래스에서이 메서드를 재정의 하는 경우 고유한 구현에서를 사용 base.Start() 하 여 부모에 연결 해야 합니다.When you override this method on your subclass, you need to make sure to chain to your parent by using base.Start() on your own implementation.

메서드 Start 는 장면, 뷰포트, 카메라 및 방향성 광원을 설정 하 고 공용 속성으로 표시 합니다.The Start method sets up the scene, viewport, camera and a directional light, and surfaces those as public properties:

  • 개체를 보유할입니다. Scenea Scene to hold your objects,
  • 그림자가 Light 있는 방향성 이며, 속성을 LightNode 통해 해당 위치를 사용할 수 있습니다.a directional Light with shadows, and whose location is available via the LightNode property
  • arkit에서 응용 프로그램에 대 한 업데이트를 전달할 때 구성 요소가 업데이트 되는 Camera 입니다.a Camera whose components are updated when ARKit delivers an update to the application and
  • 결과 ViewPort 를 표시 하는입니다.a ViewPort displaying the results.

코드Your code

그런 다음 클래스의 ArkitApp 서브 클래스를 만들고 메서드를 Start 재정의 해야 합니다.You then need to subclass the ArkitApp class and override the Start method. 메서드가 수행 해야 하는 첫 번째 작업은를 호출 ArkitApp.Start base.Start()하 여에 연결 하는 것입니다.The first thing that your method should do is chain up to the ArkitApp.Start by calling base.Start(). 그런 다음 ArkitApp를 사용 하 여 개체를 장면에 추가 하 고 처리할 광원, 그림자 또는 이벤트를 사용자 지정할 수 있습니다.After that, you can use any of the properties setup by ArkitApp to add your objects to the scene, customize the lights, shadows or events that you want to handle.

ARKit/UrhoSharp 샘플은 질감이 있는 애니메이션 문자를 로드 하 고 다음 구현을 사용 하 여 애니메이션을 재생 합니다.The ARKit/UrhoSharp sample loads an animated character with textures and plays the animation, with the following implementation:

public class MutantDemo : ArkitApp
{
    [Preserve]
    public MutantDemo(ApplicationOptions opts) : base(opts) { }

    Node mutantNode;

    protected override void Start()
    {
        base.Start ();

        // Mutant
        mutantNode = Scene.CreateChild();
        mutantNode.Rotation = new Quaternion(x: 0, y:15, z:0);
        mutantNode.Position = new Vector3(0, -1f, 2f); /*two meters away*/
        mutantNode.SetScale(0.5f);

        var mutant = mutantNode.CreateComponent<AnimatedModel>();
        mutant.Model = ResourceCache.GetModel("Models/Mutant.mdl");
        mutant.Material = ResourceCache.GetMaterial("Materials/mutant_M.xml");

        var animation = mutantNode.CreateComponent<AnimationController>();
        animation.Play("Animations/Mutant_HipHop1.ani", 0, true, 0.2f);
    }
}

그리고이 시점에서 3D 콘텐츠를 확대 된 현실에 표시 하기 위해 수행 해야 하는 것은 사실입니다.And that is really all that you have to do at this point to have your 3D content displayed in augmented reality.

Urho는 3D 모델 및 애니메이션에 사용자 지정 형식을 사용 하므로 자산을이 형식으로 내보내야 합니다.Urho uses custom formats for 3D models and animations, so you need to export your assets into this format. Urho3D Blender 추가 기능UrhoAssetImporter 와 같은 도구를 사용 하 여 이러한 자산을 .DBX, DAE, OBJ, Blend, 3d-Max와 같은 인기 있는 형식에서 urho에 필요한 형식으로 변환할 수 있습니다.You can use tools like the Urho3D Blender Add-in and UrhoAssetImporter that can convert these assets from popular formats like DBX, DAE, OBJ, Blend, 3D-Max into the format required by Urho.

Urho를 사용 하 여 3D 응용 프로그램을 만드는 방법에 대해 자세히 알아보려면 UrhoSharp 소개 가이드를 참조 하세요.To learn more about creating 3D applications using Urho, visit the Introduction to UrhoSharp guide.

ArkitAppArkitApp in Depth

참고

이 섹션은 UrhoSharp 및 ARKit의 기본 환경을 사용자 지정 하려는 개발자를 위한 것입니다. 또는 통합이 작동 하는 방식을 심층적으로 파악 하고자 합니다.This section is intended for developers that want to customize the default experience of UrhoSharp and ARKit or want to get a deeper insight on how the integration works. 이 섹션을 읽을 필요는 없습니다.It is not necessary to read this section.

ARKit API는 매우 간단 하며, ARSession 개체를 만들고 구성한 다음 ARFrame 개체를 전달 하기 시작 합니다.The ARKit API is pretty simple, you create and configure an ARSession object which then start delivering ARFrame objects. 여기에는 카메라에 의해 캡처된 이미지와 장치의 예상 실제 위치가 모두 포함 됩니다.These contain both the image captured by the camera as well as the estimated real-world position of the device.

카메라에서 3D 콘텐츠를 사용 하 여 전달 되는 이미지를 작성 하 고, 장치 위치 및 위치에 대 한 기회와 일치 하도록 UrhoSharp의 카메라를 조정 합니다.We will be composing the images being delivered by the camera to us with our 3D content, and adjust the camera in UrhoSharp to match the chances in the device location and position.

다음 다이어그램에서는 ArkitApp 클래스에서 수행 되는 작업을 보여 줍니다.The following diagram shows what is taking place in the ArkitApp class:

ArkitApp의 클래스 및 화면 다이어그램Diagram of classes and screens in the ArkitApp

프레임 렌더링Rendering the Frames

아이디어는 간단 하며 카메라에서 제공 되는 비디오를 3D 그래픽으로 결합 하 여 결합 된 이미지를 생성 합니다.The idea is simple, combine the video coming out of the camera with our 3D graphics to produce the combined image. 이러한 캡처된 이미지를 순서 대로 가져오는 것 이며,이 입력을 Urho 장면으로 혼합 합니다.We will be getting a series of these captured images in sequence, and we will mix this input with the Urho scene.

이 작업을 수행 하는 가장 간단한 방법은를 RenderPathCommand main RenderPath에 삽입 하는 것입니다.The simplest way to do it is to insert a RenderPathCommand into the main RenderPath. 단일 프레임을 그리기 위해 수행 하는 일련의 명령입니다.This is a set of commands that are performed to draw a single frame. 이 명령은 뷰포트를 전달 하는 모든 질감으로 채웁니다.This command will fill the viewport with any texture we pass to it. 이는 처리 되는 첫 번째 프레임에서 설정 하 고 실제 정의는이 시점에서 로드 되는 th Arrenderpath .xml 파일에서 수행 됩니다.We set this up on the first frame that is process, and the actual definition is done in th ARRenderPath.xml file that is loaded at this point.

그러나 두 가지 문제를 함께 결합 하는 두 가지 문제에 직면 하 고 있습니다.However, we are faced with two problems to blend these two worlds together:

  1. IOS에서 GPU 질감의 해상도는 2의 거듭제곱 이어야 하지만 카메라에서 가져올 프레임의 해상도는 2의 거듭제곱 이어야 합니다. 예를 들면 다음과 같습니다. 1280x720.On iOS, GPU Textures must have a resolution that is a power of two, but the frames that we will get from the camera do not have resolution that are a power of two, for example: 1280x720.
  2. 프레임은 YUV 형식으로 인코딩되고, 두 이미지 (루마 및 크로마)로 표시 됩니다.The frames are encoded in YUV format, represented by two images - luma and chroma.

YUV 프레임은 서로 다른 두 가지 해상도로 제공 됩니다.The YUV frames come in two different resolutions. 광도 구성 요소에 대 한 광도 (기본적으로 회색 눈금 이미지)와 훨씬 더 작은 640x360을 나타내는 1280x720 이미지는 다음과 같습니다.a 1280x720 image representing luminance (basically a gray scale image) and much smaller 640x360 for the chrominance component:

Y 및 UV 구성 요소 결합을 보여 주는 이미지

OpenGL ES를 사용 하 여 색이 지정 된 전체 이미지를 그리려면 질감 슬롯에서 광도 (Y 구성 요소) 및 색차 (UV 평면)를 사용 하는 작은 셰이더를 작성 해야 합니다.To draw a full colored image using OpenGL ES we have to write a small shader that takes luminance (Y component) and chrominance (UV planes) from the texture slots. UrhoSharp에는 이름 ("sDiffMap" 및 "Sdiffmap")이 있으며이를 RGB 형식으로 변환 합니다.In UrhoSharp they have names - “sDiffMap” and “sNormalMap” and convert them into RGB format:

mat4 ycbcrToRGBTransform = mat4(
    vec4(+1.0000, +1.0000, +1.0000, +0.0000),
    vec4(+0.0000, -0.3441, +1.7720, +0.0000),
    vec4(+1.4020, -0.7141, +0.0000, +0.0000),
    vec4(-0.7010, +0.5291, -0.8860, +1.0000));

vec4 ycbcr = vec4(texture2D(sDiffMap, vTexCoord).r,
                    texture2D(sNormalMap, vTexCoord).ra, 1.0);
gl_FragColor = ycbcrToRGBTransform * ycbcr;

두 해상도의 거듭제곱이 없는 질감을 렌더링 하려면 다음 매개 변수를 사용 하 여 Texture2D를 정의 해야 합니다.To render the texture that does not have a power of two resolution we have to define Texture2D with the following parameters:

// texture for UV-plane;
cameraUVtexture = new Texture2D();
cameraUVtexture.SetNumLevels(1);
cameraUVtexture.SetSize(640, 360, Graphics.LuminanceAlphaFormat, TextureUsage.Dynamic);
cameraUVtexture.FilterMode = TextureFilterMode.Bilinear;
cameraUVtexture.SetAddressMode(TextureCoordinate.U, TextureAddressMode.Clamp);
cameraUVtexture.SetAddressMode(TextureCoordinate.V, TextureAddressMode.Clamp);

따라서 캡처된 이미지를 배경으로 렌더링 하 고이를 통해 해당 하는 모든 장면을 mutant 수 있습니다.Thus we are able to render captured images as a background and render any scene above it like that scary mutant.

카메라 조정Adjusting the Camera

또한 ARFrame 개체에는 예상 장치 위치도 포함 됩니다.The ARFrame objects also contain the estimated device position. 이제 게임 카메라 ARFrame을 이동 해야 합니다. Arframe는 장치 방향 (roll, 피치 및 요)을 추적 하 고 비디오 위에 고정 된 홀로그램을 렌더링 하는 것은 아닙니다. 하지만 장치를 이동 하는 경우에는 비트 holograms가 드리프트 됩니다.We now we need to move game camera ARFrame - before ARKit it was not a big deal to track device orientation (roll, pitch and yaw) and render a pinned hologram on top of the video - but if you move your device a bit - holograms will drift.

이는 자이로스코프가 같은 기본 제공 센서가 이동을 추적할 수 없고 가속만 가능 하기 때문에 발생 합니다.That happens because built-in sensors such as gyroscope are not able to track movements, they can only acceleration. ARKit는 각 프레임을 분석 하 여 추적할 기능 요소를 추출 하므로 이동 및 회전 데이터를 포함 하는 정확한 변환 매트릭스를 제공할 수 있습니다.ARKit analyses each frame and extracts feature points to track and thus is able to give us an accurate Transform matrix containing movement and rotation data.

예를 들어 현재 위치를 가져오는 방법은 다음과 같습니다.For example, this is how we can obtain current position:

var row = arCamera.Transform.Row3;
CameraNode.Position = new Vector3(row.X, row.Y, -row.Z);

Arkit -row.Z 에서 오른손 좌표계를 사용 하기 때문에를 사용 합니다.We use -row.Z because ARKit uses a right-handed coordinate system.

평면 검색Plane detection

ARKit는 가로 평면을 검색할 수 있으며이 기능을 사용 하면 실제 테이블 또는 층에 mutant를 추가할 수 있습니다.ARKit is able to detect horizontal planes and this ability allows you to interact with the real world, for example, we can place the mutant on a real table or a floor. 이 작업을 수행 하는 가장 간단한 방법은 System.windows.media.visualtreehelper.hittest 메서드 (raycasting)를 사용 하는 것입니다.The simplest way to do that is to use HitTest method (raycasting). 화면 좌표 (0.5; 0.5는 가운데)를 실제 좌표 (0; 0; 0)로 변환 합니다. 는 첫 번째 프레임의 위치)입니다.It converts screen coordinates (0.5;0.5 is the center) into the real world coordinates (0;0;0 is the first frame's location).

protected Vector3? HitTest(float screenX = 0.5f, float screenY = 0.5f)
{
    var result = ARSession.CurrentFrame.HitTest(new CGPoint(screenX, screenY),
        ARHitTestResultType.ExistingPlaneUsingExtent)?.FirstOrDefault();
    if (result != null)
    {
        var row = result.WorldTransform.Row3;
        return new Vector3(row.X, row.Y, -row.Z);
    }
    return null;
}

이제 장치 화면에서 탭 하는 위치에 따라 가로 화면에 mutant를 넣을 수 있습니다.now we can place the mutant on a horizontal surface depending on where on the device screen we tap:

void OnTouchEnd(TouchEndEventArgs e)
{
    float x = e.X / (float)Graphics.Width;
    float y = e.Y / (float)Graphics.Height;
    var pos = HitTest(x, y);
    if (pos != null)
    mutantNode.Position = pos.Value;
}

평면을 보기 이동으로 변경 하는 애니메이션 그림

현실적인 조명Realistic lighting

실제 조명 조건에 따라 가상 장면을 주변 환경에 맞게 더 밝게 하거나 더 밝게 해야 합니다.Depending on the real world lighting conditions, the virtual scene should be lighter or darker to better match its surroundings. ARFrame에는 Urho 앰비언트 조명을 조정 하는 데 사용할 수 있는 LightEstimate 속성이 포함 되어 있습니다 .이 속성은 다음과 같이 수행 됩니다.ARFrame contains a LightEstimate property that we can use to adjust the Urho ambient light, this is done like this:

var ambientIntensity = (float) frame.LightEstimate.AmbientIntensity / 1000f;
var zone = Scene.GetComponent<Zone>();
zone.AmbientColor = Color.White * ambientIntensity;

IOS 이상-HoloLensBeyond iOS - HoloLens

UrhoSharp는 모든 주요 운영 체제에서 실행되므로 기존 코드를 다른 곳에서 재사용할 수 있습니다.UrhoSharp runs on all major operating systems, so you can reuse your existing code elsewhere.

HoloLens는 실행 중인 가장 흥미로운 플랫폼 중 하나입니다.HoloLens is one of the most exciting platforms it runs on. 즉, iOS와 HoloLens 간을 쉽게 전환 하 여 UrhoSharp를 사용 하는 뛰어난 확대 현실 응용 프로그램을 빌드할 수 있습니다.This means that you can easily switch between iOS and HoloLens to build awesome Augmented Reality applications using UrhoSharp.

MutantDemo 소스는 github.com/EgorBo/ARKitXamarinDemo에서 찾을 수 있습니다.You can find the MutantDemo source at github.com/EgorBo/ARKitXamarinDemo.