예제 #1
0
    public void Initialize()
    {
        StringBuilder sb = new StringBuilder(16);

        SDPlugin.SixDegreesSDK_GetVersion(sb, sb.Capacity);
        SDPlugin.Version = sb.ToString();

        Debug.Log("Will initialize SDK v" + SDPlugin.Version);
        bool initializing;

#if UNITY_IOS && !UNITY_EDITOR
        if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.OpenGLES3)
        {
            unsafe
            {
                initializing = SDPlugin.SixDegreesSDK_InitializeWithEAGL(null);
            }
        }
        else
#endif
        {
            initializing = SDPlugin.SixDegreesSDK_Initialize();
        }

        if (!initializing)
        {
            Debug.Log("Failed to initialize SDK. Check logs for more information.");
        }
        if (isStopped)
        {
            FindObjectOfType <SDBackcam>().enabled = true;
            FindObjectOfType <SDBackcam>().Awake();
            FindObjectOfType <SDBackcam>().SetupBackgroundTexture();
        }
    }
예제 #2
0
        SCNMatrix4 MakeProjectionMatrix(UIInterfaceOrientation orientation)
        {
            const int bufferSize = 16;

            float[] projectionBuffer = new float[bufferSize];

            unsafe
            {
                fixed(float *ptr = &projectionBuffer[0])
                {
                    SDPlugin.SixDegreesSDK_GetProjection(ptr, bufferSize);
                }
            }

            var matrix = new Matrix4
            {
                Row0 = new Vector4(projectionBuffer[0], projectionBuffer[1], projectionBuffer[2], projectionBuffer[3]),
                Row1 = new Vector4(projectionBuffer[4], projectionBuffer[5], projectionBuffer[6], projectionBuffer[7]),
                Row2 = new Vector4(projectionBuffer[8], projectionBuffer[9], projectionBuffer[10], projectionBuffer[11]),
                Row3 = new Vector4(projectionBuffer[12], projectionBuffer[13], projectionBuffer[14], projectionBuffer[15])
            };

            var rotation = MakeInterfaceRotationRadians(orientation);

            var        matrixRotated = CreateMatrixFromRotation(rotation, 0, 0, 1);
            var        newMatrix     = matrix * matrixRotated;
            SCNMatrix4 poseMatrix    = new SCNMatrix4(newMatrix.Row0, newMatrix.Row1, newMatrix.Row2, newMatrix.Row3);

            return(poseMatrix);
        }
예제 #3
0
    private IEnumerator InitializeCoroutine()
    {
        while (!SDPlugin.IsSDKReady)
        {
            SDPlugin.IsSDKReady = SDPlugin.SixDegreesSDK_IsInitialized();

            yield return(null);
        }
    }
예제 #4
0
 public void Awake()
 {
     Screen.sleepTimeout         = SleepTimeout.NeverSleep;
     Application.targetFrameRate = 60;
     if (SDPlugin.SixDegreesSDK_GetState() == (int)SDPlugin.SDState.Stopped)
     {
         Initialize();
     }
 }
예제 #5
0
 private void UpdateSaveStatus()
 {
     unsafe
     {
         fixed(int *saveStatePtr = &saveState, saveErrorPtr = &saveError)
         {
             SDPlugin.SixDegreesSDK_GetSaveStatus(saveStatePtr, saveErrorPtr, null);
         }
     }
 }
예제 #6
0
 private void UpdateLoadStatus()
 {
     unsafe
     {
         fixed(int *loadStatePtr = &loadState, loadErrorPtr = &loadError)
         {
             SDPlugin.SixDegreesSDK_GetLoadStatus(loadStatePtr, loadErrorPtr, null);
         }
     }
 }
예제 #7
0
        void CommonInit()
        {
            // Configure everything
            ConfigureView();
            ConfigureMeshController();
            ConfigureMetal();

            // Initialize 6D SDK
            SDPlugin.SixDegreesSDK_Initialize();

            MeshController.ShowMesh();
        }
예제 #8
0
 void Update()
 {
     if (SDPlugin.IsSDKReady)
     {
         if (!SDPlugin.SixDegreesSDK_HasRealTimeMesh())
         {
             meshingScene.SetActive(false);
             ballScene.SetActive(false);
             Destroy(this);
         }
     }
 }
예제 #9
0
    public void OnDestroy()
    {
        if (SDPlugin.IsSDKReady && activeCoroutine != null)
        {
            StopCoroutine(activeCoroutine);
            activeCoroutine = null;

            SDPlugin.SixDegreesSDK_CancelLoad();
            SDPlugin.SixDegreesSDK_CancelSave();

            OnCancelledEvent();
        }
    }
예제 #10
0
 void Update()
 {
     if (!sdkController.isStopped && showText)
     {
         feedback.text = "SDK State: " + (SDPlugin.SDState)SDPlugin.SixDegreesSDK_GetState() + "\n\n" +
                         SDPlugin.Version + "\n\n" +
                         "Load State: " + (SDPlugin.SDLoadState)sdkController.loadState + "\n\n" +
                         "Error: " + (SDPlugin.SDLoadError)sdkController.loadError + "\n\n" +
                         "Progress: " + (int)sdkController.downloadProgress + "\n\n" +
                         "Save State: " + (SDPlugin.SDSaveState)sdkController.saveState + "\n\n" +
                         "Error: " + (SDPlugin.SDSaveError)sdkController.saveError + "\n\n" +
                         "Progress: " + sdkController.uploadProgress + "\n\n" +
                         "Location ID: " + SDPlugin.LocationID;
     }
 }
예제 #11
0
    public void Initialize()
    {
        StringBuilder sb = new StringBuilder(16);

        SDPlugin.SixDegreesSDK_GetVersion(sb, sb.Capacity);
        SDPlugin.Version = sb.ToString();

        Debug.Log("Will initialize SDK v" + SDPlugin.Version);
        unsafe
        {
            SDPlugin.SixDegreesSDK_Initialize();
        }

        StartCoroutine(InitializeCoroutine());
    }
    void Awake()
    {
        if (SDPlugin.SixDegreesSDK_IsDeviceSupported() == false)
        {
            initializationText.text = "Sorry, this device is unsupported Cannot initialize SixDegreesSDK";
        }
        StringBuilder sb = new StringBuilder(32);

        GetAPIKey(sb, 32);
        string apiKey = sb.ToString();

        if (string.IsNullOrEmpty(apiKey))
        {
            initializationText.text = "API Key is empty. Make sure you have valid API Keys in your plist file";
        }
    }
예제 #13
0
 private void UpdateSaveStatus()
 {
     unsafe
     {
         fixed(int *saveStatePtr = &saveState, saveErrorPtr = &saveError)
         {
             fixed(long *uploadSizePtr = &uploadSize)
             {
                 fixed(float *uploadProgessPtr = &uploadProgress)
                 {
                     SDPlugin.SixDegreesSDK_GetSaveStatus(timeStamp, saveStatePtr, saveErrorPtr, uploadSizePtr, uploadProgessPtr);
                 }
             }
         }
     }
 }
예제 #14
0
 public void Cancel()
 {
     if (activeCoroutine != null)
     {
         if (saving)
         {
             SDPlugin.SixDegreesSDK_CancelSave(timeStamp);
             UpdateSaveStatus();
         }
         if (loading)
         {
             SDPlugin.SixDegreesSDK_CancelLoad(timeStamp);
             UpdateLoadStatus();
         }
     }
 }
예제 #15
0
 private void UpdateLoadStatus()
 {
     unsafe
     {
         fixed(int *loadStatePtr = &loadState, loadErrorPtr = &loadError)
         {
             fixed(long *downloadSizePtr = &downloadSize)
             {
                 fixed(float *downloadProgressPtr = &downloadProgress)
                 {
                     SDPlugin.SixDegreesSDK_GetLoadStatus(timeStamp, loadStatePtr, loadErrorPtr, downloadSizePtr, downloadProgressPtr);
                 }
             }
         }
     }
 }
예제 #16
0
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            throwController = new ThrowController(this.sixDegreesView);
            ConfigureController();
            ConfigureLights();

            meshButton.TouchUpInside += (sender, e) =>
            {
                meshButton.Selected = !meshButton.Selected;

                if (meshButton.Selected)
                {
                    sixDegreesView.MeshController.ShowMesh();
                }
                else
                {
                    sixDegreesView.MeshController.HideMesh();
                }

                SDPlugin.ShowMesh = meshButton.Selected;
            };

            loadButton.TouchUpInside += (sender, e) =>
            {
                if (SDPlugin.IsSDKReady)
                {
                    loadTime = SDPlugin.SixDegreesSDK_LoadFromARCloud();
                }
            };

            saveButton.TouchUpInside += (sender, e) =>
            {
                if (SDPlugin.IsSDKReady)
                {
                    saveTime = SDPlugin.SixDegreesSDK_SaveToARCloud();
                }
            };

            var updateTimer = NSTimer.CreateRepeatingScheduledTimer(TimeSpan.FromSeconds(0.2), delegate
            {
                UpdateDebug();
            });

            updateTimer.Fire();
        }
예제 #17
0
        void UpdateDebug()
        {
            if (SDPlugin.IsSDKReady)
            {
            }
            else
            {
                return;
            }

            float[] pose           = new float[16];
            int     mTrackingState = 0;

            unsafe
            {
                fixed(float *ptr = &pose[0])
                {
                    // R T
                    // 0 1
                    int bufferSize = 16;

                    mTrackingState = SDPlugin.SixDegreesSDK_GetPose(ptr, bufferSize);
                }
            }
            var angle = Math.Atan2(pose[8], pose[0]);

            string quality = "";

            switch (mTrackingState)
            {
            case 0:
                quality = "None";
                break;

            case 1:
                quality = "Limited";
                break;

            case 2:
                quality = "Good";
                break;

            default:
                break;
            }
            statusLabel.Text = ("Tracking: " + quality + "\nX: " + Math.Round(pose[12], 2).ToString() + ", Y: " + Math.Round(pose[13], 2).ToString() + ", Z: " + Math.Round(pose[14], 2).ToString() + "\nHeading: " + Math.Round(ConvertRadiansToDegrees(angle), 2).ToString());
        }
예제 #18
0
    public void Load()
    {
        if (!SDPlugin.IsSDKReady)
        {
            return;
        }

        Debug.Log("Will load location map data from AR Cloud");

        if (activeCoroutine != null)
        {
            StopCoroutine(activeCoroutine);
        }

        SDPlugin.SixDegreesSDK_LoadFromARCloud();
        activeCoroutine = StartCoroutine(LoadCoroutine());
    }
예제 #19
0
    public void Save()
    {
        if (!SDPlugin.IsSDKReady)
        {
            return;
        }

        Debug.Log("Will save location map data to AR Cloud");

        if (activeCoroutine != null)
        {
            StopCoroutine(activeCoroutine);
        }

        SDPlugin.SixDegreesSDK_SaveToARCloud();
        activeCoroutine = StartCoroutine(SaveCoroutine());
    }
예제 #20
0
 public void RetrySave()
 {
     if (timeStamp == -1 || !SDPlugin.IsSDKReady)
     {
         return;
     }
     else
     {
         Debug.Log("Will retry saving location map data to AR Cloud");
         if (activeCoroutine != null)
         {
             StopCoroutine(activeCoroutine);
         }
         SDPlugin.SixDegreesSDK_RetrySaveToARCloud(timeStamp);
         activeCoroutine = StartCoroutine(SaveCoroutine());
     }
 }
예제 #21
0
        CGSize MakeBackgroundTextureSize()
        {
            int width  = 0;
            int height = 0;

            unsafe
            {
                SDPlugin.SixDegreesSDK_GetBackgroundTextureSize(&width, &height);
            }
            if (width > 0 && height > 0)
            {
                return(new CGSize(width, height));
            }
            else
            {
                return(CGSize.Empty);
            }
        }
예제 #22
0
        unsafe void UpdatePose()
        {
            float[] mPoseBuffer    = new float[16];
            int     mTrackingState = 0;

            fixed(float *ptr = &mPoseBuffer[0])
            {
                // R T
                // 0 1
                int bufferSize = 16;

                mTrackingState = SDPlugin.SixDegreesSDK_GetPose(ptr, bufferSize);
            }

            switch (mTrackingState)
            {
            case (int)SDPlugin.SDTrackingQuality.Good:
            case (int)SDPlugin.SDTrackingQuality.Limited:
            {
                if (mTrackingState > 0)
                {
                    // Update camera pose
                    var        row0       = new SCNVector4(mPoseBuffer[0], mPoseBuffer[1], mPoseBuffer[2], mPoseBuffer[3]);
                    var        row1       = new SCNVector4(mPoseBuffer[4], mPoseBuffer[5], mPoseBuffer[6], mPoseBuffer[7]);
                    var        row2       = new SCNVector4(mPoseBuffer[8], mPoseBuffer[9], mPoseBuffer[10], mPoseBuffer[11]);
                    var        row3       = new SCNVector4(mPoseBuffer[12], mPoseBuffer[13], mPoseBuffer[14], mPoseBuffer[15]);
                    SCNMatrix4 poseMatrix = new SCNMatrix4(row0, row1, row2, row3);
                }

                break;
            }

            case (int)SDPlugin.SDTrackingQuality.None:
            default:
            {
                break;
            }
            }
        }
        void SetupARBackgroundTexture()
        {
            IntPtr texturePtr = IntPtr.Zero;

#if UNITY_IOS && !UNITY_EDITOR
            if (SystemInfo.graphicsDeviceType == UnityEngine.Rendering.GraphicsDeviceType.OpenGLES3)
            {
                int textureId = SDPlugin.SixDegreesSDK_GetEAGLBackgroundTexture();
                texturePtr = new IntPtr(textureId);
            }
            else
#endif
            {
                texturePtr = SDPlugin.SixDegreesSDK_GetBackgroundTexture();
            }

            if (texturePtr != IntPtr.Zero)
            {
                int width  = 1920;
                int height = 1080;
                unsafe
                {
                    int *widthPtr = &width, heightPtr = &height;
                    SDPlugin.SixDegreesSDK_GetBackgroundTextureSize(widthPtr, heightPtr);
                }

                Debug.Log("Create External Texture:" + texturePtr + "(" + width + "x" + height + ")");
                _ARBackgroundTexture = Texture2D.CreateExternalTexture(
                    width,
                    height,
                    TextureFormat.RGBA32,
                    false,
                    false,
                    texturePtr);
                _ARBackgroundTexture.filterMode = FilterMode.Point;
                _ARBackgroundTexture.name       = "AR_Background_Texture";
            }
        }
예제 #24
0
        public void Update()
        {
            // Get new mesh version and buffer sizes
            int blockBufferSize  = 0;
            int vertexBufferSize = 0;
            int faceBufferSize   = 0;

            unsafe
            {
                var newVersion = SDPlugin.SixDegreesSDK_GetBlockMeshInfo(&blockBufferSize, &vertexBufferSize, &faceBufferSize);

                if (newVersion > MeshVersion)
                {
                    if (blockBufferSize > 0 &&
                        vertexBufferSize > 0 &&
                        faceBufferSize > 0)
                    {
                    }
                    else
                    {
                        return;
                    }

                    if (MeshVersion < 0)
                    {
                        BlockSize = SDPlugin.SixDegreesSDK_GetMeshBlockSize();
                    }
                    UpdateMesh(newVersion: newVersion, blockBufferSize: blockBufferSize, vertexBufferSize: vertexBufferSize, faceBufferSize: faceBufferSize);
                }
                else if (newVersion == 0 &&
                         MeshVersion > 0)
                {
                    ClearMesh();
                }
            }
        }
예제 #25
0
        void UpdateStatus()
        {
            saveState = (int)SDPlugin.SDSaveState.None;

            if (SDPlugin.IsSDKReady && (saveTime > 0 || loadTime > 0))
            {
            }
            else
            {
                return;
            }

            var status = "";

            if (saveTime > loadTime)
            {
                unsafe
                {
                    fixed(int *saveStatePtr = &saveState, saveErrorPtr = &saveError)
                    {
                        fixed(long *uploadSizePtr = &uploadSize)
                        {
                            fixed(float *uploadProgessPtr = &uploadProgress)
                            {
                                SDPlugin.SixDegreesSDK_GetSaveStatus(saveTime, saveStatePtr, saveErrorPtr, uploadSizePtr, uploadProgessPtr);
                            }
                        }
                    }
                }
            }

            StringBuilder sb = new StringBuilder(16);

            SDPlugin.SixDegreesSDK_GetLocationId(sb, sb.Capacity);
            SDPlugin.LocationID = sb.ToString();
        }
예제 #26
0
        void UpdateMesh(int newVersion, int blockBufferSize, int vertexBufferSize, int faceBufferSize)
        {
            MeshVersion = newVersion;

            int[]   blockArray  = new int[blockBufferSize];
            float[] vertexArray = new float[vertexBufferSize];
            int[]   faceArray   = new int[faceBufferSize];

            int fullBlocks = 0;

            unsafe
            {
                fixed(int *blockBufferPtr = &blockArray[0], faceBufferPtr = &faceArray[0])
                {
                    fixed(float *vertexBufferPtr = &vertexArray[0])
                    {
                        fullBlocks = SDPlugin.SixDegreesSDK_GetBlockMesh(blockBufferPtr, vertexBufferPtr, faceBufferPtr, blockBufferSize, vertexBufferSize, faceBufferSize);
                    }
                }
            }
            bool gotAllBlocks = (fullBlocks == blockBufferSize / 6);

            if (fullBlocks > 0)
            {
            }
            else
            {
                Console.WriteLine("SixDegreesSDK_GetMeshBlocks() gave us an empty mesh, will not update.");
                return;
            }

            if (!gotAllBlocks)
            {
                Console.WriteLine("SixDegreesSDK_GetMeshBlocks() returned %d full blocks, expected %d, will not update", fullBlocks, (blockBufferSize / 6));
                return;
            }

            var vertexCount    = vertexBufferSize / 6;
            var blocksToUpdate = new List <Vector3>();

            var firstBlockVertex = 0;
            var firstBlockFace   = 0;

            // Update all the full blocks returned by the API
            for (int b = 0; b < blockBufferSize; b += 6)
            {
                // Transform block coordinates from 6D right-handed coordinates to Unity left-handed coordinates
                // By flipping the sign of Z
                Vector3 blockCoords      = new Vector3(blockArray[b], blockArray[b + 1], blockArray[b + 2]);
                int     blockVertexCount = blockArray[b + 3];
                int     blockFaceCount   = blockArray[b + 4];
                int     blockVersion     = blockArray[b + 5];

                var block = GetOrCreateBlock(blockCoords);
                block.MeshVersion = MeshVersion;

                // Update block if it is outdated
                if (block.Version < blockVersion)
                {
                    blocksToUpdate.Add(blockCoords);
                    block.Version  = blockVersion;
                    block.Vertices = new List <SCNVector3>();
                    block.Normals  = new List <SCNVector3>();
                    block.Faces    = new List <int>();

                    // copy vertices
                    for (int j = firstBlockVertex; j < firstBlockVertex + blockVertexCount; j++)
                    {
                        var vertex = j;
                        var pos    = vertex * 3;
                        block.Vertices.Add(new SCNVector3(vertexArray[pos],
                                                          vertexArray[pos + 1],
                                                          vertexArray[pos + 2]));

                        var norm = (vertex + vertexCount) * 3;
                        block.Normals.Add(new SCNVector3(vertexArray[norm],
                                                         vertexArray[norm + 1],
                                                         vertexArray[norm + 2]));
                    }

                    // copy faces
                    var offset = firstBlockVertex;
                    for (int face = firstBlockFace; face < firstBlockFace + blockFaceCount; face++)
                    {
                        var f = face * 3;
                        block.Faces.Add(faceArray[f] - offset);
                        block.Faces.Add(faceArray[f + 1] - offset);
                        block.Faces.Add(faceArray[f + 2] - offset);
                    }
                }
                firstBlockVertex += blockVertexCount;
                firstBlockFace   += blockFaceCount;
            }

            var blocksToDelete = new List <Vector3>();

            // Clean up outdated blocks
            foreach (var item in Blocks.Values)
            {
                if (item.MeshVersion != MeshVersion)
                {
                    blocksToDelete.Add(item.Coordinates);
                }
            }

            DeleteBlocks(blocksToDelete);
            UpdateBlocks(blocksToUpdate);
        }
예제 #27
0
 public void Stop()
 {
     isStopped = SDPlugin.SixDegreesSDK_Stop();
     Texture2D.DestroyImmediate(FindObjectOfType <SDBackcam>().background.mainTexture, true);
     FindObjectOfType <SDBackcam>().enabled = false;
 }
예제 #28
0
    private IEnumerator LoadCoroutine()
    {
        loadState = (int)SDPlugin.SDLoadState.None;

        yield return(new WaitForSeconds(0.1f));

        bool loading = true;

        while (loading)
        {
            UpdateLoadStatus();

            switch (loadState)
            {
            case (int)SDPlugin.SDLoadState.DoneFailed:
            case (int)SDPlugin.SDLoadState.DoneSuccess:
            case (int)SDPlugin.SDLoadState.DoneCancelled:
                loading = false;
                break;

            case (int)SDPlugin.SDLoadState.Positioning:
                if (OnFindingLocationEvent != null)
                {
                    OnFindingLocationEvent();
                }
                break;

            case (int)SDPlugin.SDLoadState.Downloading:
                if (OnDownloadingEvent != null)
                {
                    OnDownloadingEvent();
                }
                break;

            case (int)SDPlugin.SDLoadState.Relocalizing:
                if (OnRelocalizingEvent != null)
                {
                    OnRelocalizingEvent();
                }
                break;

            default:
                break;
            }

            yield return(null);
        }

        if (loadState == (int)SDPlugin.SDLoadState.DoneSuccess)
        {
            StringBuilder sb = new StringBuilder(16);
            SDPlugin.SixDegreesSDK_GetLocationId(sb, sb.Capacity);
            SDPlugin.LocationID = sb.ToString();
            if (OnLoadSucceededEvent != null)
            {
                OnLoadSucceededEvent();
            }
        }
        else if (loadState == (int)SDPlugin.SDLoadState.DoneFailed)
        {
            if (OnLoadErrorEvent != null)
            {
                OnLoadErrorEvent(loadError);
            }
        }

        yield return(null);

        activeCoroutine = null;
    }
예제 #29
0
        public void Draw(MTKView view)
        {
            if (!SDPlugin.IsSDKReady)
            {
                return;
            }

            // Update sizes
            if (backgroundTextureSize.Width == 0 && backgroundTextureSize.Height == 0)
            {
                var size = MakeBackgroundTextureSize();
                backgroundTextureSize = size;
                UpdateMTKViewFrame();
            }

            // Draw meshes
            if (SDPlugin.ShowMesh)
            {
                MeshController.Update();
            }

            // Get pose and tracking quality
            var localOrientation = UIApplication.SharedApplication.StatusBarOrientation;

            float[] mPoseBuffer     = new float[16];
            int     trackingQuality = 0;

            unsafe
            {
                fixed(float *ptr = &mPoseBuffer[0])
                {
                    // R T
                    // 0 1
                    int bufferSize = 16;

                    trackingQuality = SDPlugin.SixDegreesSDK_GetPose(ptr, bufferSize);
                }
            }

            if (trackingQuality > 0)
            {
                // Update camera pose
                var        row0       = new SCNVector4(mPoseBuffer[0], mPoseBuffer[1], mPoseBuffer[2], mPoseBuffer[3]);
                var        row1       = new SCNVector4(mPoseBuffer[4], mPoseBuffer[5], mPoseBuffer[6], mPoseBuffer[7]);
                var        row2       = new SCNVector4(mPoseBuffer[8], mPoseBuffer[9], mPoseBuffer[10], mPoseBuffer[11]);
                var        row3       = new SCNVector4(mPoseBuffer[12], mPoseBuffer[13], mPoseBuffer[14], mPoseBuffer[15]);
                SCNMatrix4 poseMatrix = new SCNMatrix4(row0, row1, row2, row3);

                CameraNode.WorldTransform = poseMatrix;

                // Update camera projection
                var projectionTransform = MakeProjectionMatrix(localOrientation);
                CameraNode.Camera.ProjectionTransform = projectionTransform;
            }

            // Update vertex factory
            if (vertexFactory.IsComplete == false || orientation != localOrientation)
            {
                vertexFactory.Update(localOrientation, backgroundTextureSize);
            }
            orientation = localOrientation;

            // Draw background texture
            var texturePtr = SDPlugin.SixDegreesSDK_GetBackgroundTexture();

            if (texturePtr != IntPtr.Zero)
            {
                var obj = ObjCRuntime.Runtime.GetINativeObject <IMTLTexture>(texturePtr, false);
                Draw((IMTLTexture)obj);
            }

            if (commandQueue != null)
            {
                var    commandBuffer   = commandQueue.CommandBuffer();
                var    currentDrawable = mtkView.CurrentDrawable;
                double CurrentTime     = CAAnimation.CurrentMediaTime();
                var    screenScale     = UIScreen.MainScreen.Scale;
                var    viewport        = new CGRect(x: 0, y: 0,
                                                    width: mtkView.Frame.Width * screenScale,
                                                    height: mtkView.Frame.Height * screenScale);

                var renderPassDescriptor = MTLRenderPassDescriptor.CreateRenderPassDescriptor();
                renderPassDescriptor.ColorAttachments[0].Texture     = currentDrawable.Texture;
                renderPassDescriptor.ColorAttachments[0].LoadAction  = MTLLoadAction.Load;
                renderPassDescriptor.ColorAttachments[0].StoreAction = MTLStoreAction.Store;

                renderer.Render(CurrentTime,
                                viewport,
                                commandBuffer,
                                renderPassDescriptor);

                commandBuffer.PresentDrawable(currentDrawable);
                commandBuffer.Commit();
            }
        }