예제 #1
0
    public void Render()
    {
        // Shouldn't happen because of the check in Start(), but just in case...
        if (controller == null)
        {
            return;
        }

        var       camera     = GetComponent <Camera>();
        var       monoCamera = controller.GetComponent <Camera>();
        Matrix4x4 proj       = Cardboard.SDK.Projection(eye);

        CopyCameraAndMakeSideBySide(controller, proj[0, 2], proj[1, 2]);

        // Zoom the stereo cameras if requested.
        float lerp = Mathf.Clamp01(controller.matchByZoom) * Mathf.Clamp01(controller.matchMonoFOV);
        // Lerping the reciprocal of proj(1,1) so zooming is linear in the frustum width, not the depth.
        float monoProj11 = monoCamera.projectionMatrix[1, 1];
        float zoom       = 1 / Mathf.Lerp(1 / proj[1, 1], 1 / monoProj11, lerp) / proj[1, 1];

        proj[0, 0] *= zoom;
        proj[1, 1] *= zoom;

        // Calculate stereo adjustments based on the center of interest.
        float ipdScale;
        float eyeOffset;

        controller.ComputeStereoAdjustment(proj[1, 1], transform.lossyScale.z,
                                           out ipdScale, out eyeOffset);

        // Set up the eye's view transform.
        transform.localPosition = ipdScale * Cardboard.SDK.EyeOffset(eye) +
                                  eyeOffset * Vector3.forward;

        // Set up the eye's projection.
        float near = monoCamera.nearClipPlane;
        float far  = monoCamera.farClipPlane;

        FixProjection(ref proj, near, far, ipdScale);
        camera.projectionMatrix = proj;

        if (Application.isEditor)
        {
            // So you can see the approximate frustum in the Scene view when the camera is selected.
            camera.fieldOfView = 2 * Mathf.Atan(1 / proj[1, 1]) * Mathf.Rad2Deg;
        }

        if (!Cardboard.SDK.nativeDistortionCorrection)
        {
            Matrix4x4 realProj = Cardboard.SDK.UndistortedProjection(eye);
            FixProjection(ref realProj, near, far, ipdScale);
            // Parts of the projection matrices that we need to convert texture coordinates between
            // distorted and undistorted frustums.  Include the transform between texture space [0..1]
            // and NDC [-1..1] (that's what the -1 and the /2 are for).  Also note that the zoom
            // factor is removed, because that will interfere with the distortion calculation.
            Vector4 projvec = new Vector4(proj[0, 0] / zoom, proj[1, 1] / zoom,
                                          proj[0, 2] - 1, proj[1, 2] - 1) / 2;
            Vector4 unprojvec = new Vector4(realProj[0, 0], realProj[1, 1],
                                            realProj[0, 2] - 1, realProj[1, 2] - 1) / 2;
            Shader.SetGlobalVector("_Projection", projvec);
            Shader.SetGlobalVector("_Unprojection", unprojvec);
            CardboardProfile p = Cardboard.SDK.Profile;
            Shader.SetGlobalVector("_Undistortion",
                                   new Vector4(p.device.inverse.k1, p.device.inverse.k2));
            Shader.SetGlobalVector("_Distortion",
                                   new Vector4(p.device.distortion.k1, p.device.distortion.k2));
        }

        RenderTexture stereoScreen = controller.StereoScreen;
        int           screenWidth  = stereoScreen ? stereoScreen.width : Screen.width;
        int           screenHeight = stereoScreen ? stereoScreen.height : Screen.height;

        if (stereoScreen == null)
        {
            // We are rendering straight to the screen.  Use the reported rect that is visible
            // through the device's lenses.
            Rect view = Cardboard.SDK.EyeRect(eye);
            Rect rect = camera.rect;
            if (eye == Cardboard.Eye.Right)
            {
                rect.x -= 0.5f;
            }
            rect.width  *= 2 * view.width;
            rect.x       = view.x + 2 * rect.x * view.width;
            rect.height *= view.height;
            rect.y       = view.y + rect.y * view.height;
            if (Application.isEditor)
            {
                // The Game window's aspect ratio may not match the fake device parameters.
                float realAspect       = (float)screenWidth / screenHeight;
                float fakeAspect       = Cardboard.SDK.Profile.screen.width / Cardboard.SDK.Profile.screen.height;
                float aspectComparison = fakeAspect / realAspect;
                if (aspectComparison < 1)
                {
                    rect.width *= aspectComparison;
                    rect.x     *= aspectComparison;
                    rect.x     += (1 - aspectComparison) / 2;
                }
                else
                {
                    rect.height /= aspectComparison;
                }
            }
            camera.rect = rect;
        }

        // Use the "fast" or "slow" method.  Fast means the camera draws right into one half of
        // the stereo screen.  Slow means it draws first to a side buffer, and then the buffer
        // is written to the screen. The slow method is provided because a lot of Image Effects
        // don't work if you draw to only part of the window.
        if (controller.directRender)
        {
            // Redirect to our stereo screen.
            camera.targetTexture = stereoScreen;
            // Draw!
            camera.Render();
        }
        else
        {
            // Save the viewport rectangle and reset to "full screen".
            Rect pixRect = camera.pixelRect;
            camera.rect = new Rect(0, 0, 1, 1);
            // Redirect to a temporary texture.  The defaults are supposedly Android-friendly.
            int depth = stereoScreen ? stereoScreen.depth : 16;
            RenderTextureFormat format = stereoScreen ? stereoScreen.format : RenderTextureFormat.RGB565;
            camera.targetTexture = RenderTexture.GetTemporary((int)pixRect.width, (int)pixRect.height,
                                                              depth, format);
            // Draw!
            camera.Render();
            // Blit the temp texture to the stereo screen.
            RenderTexture oldTarget = RenderTexture.active;
            RenderTexture.active = stereoScreen;
            GL.PushMatrix();
            GL.LoadPixelMatrix(0, screenWidth, screenHeight, 0);
            // Camera rects are in screen coordinates (bottom left is origin), but DrawTexture takes a
            // rect in GUI coordinates (top left is origin).
            Rect blitRect = pixRect;
            blitRect.y = screenHeight - pixRect.height - pixRect.y;
            // Blit!
            Graphics.DrawTexture(blitRect, camera.targetTexture);
            // Clean up.
            GL.PopMatrix();
            RenderTexture.active = oldTarget;
            RenderTexture.ReleaseTemporary(camera.targetTexture);
        }
        camera.targetTexture = null;
    }
예제 #2
0
    private void Setup()
    {
        // Shouldn't happen because of the check in Start(), but just in case...
        if (controller == null)
        {
            return;
        }

        var       monoCamera = controller.GetComponent <Camera>();
        Matrix4x4 proj       = Cardboard.SDK.Projection(eye);

        CopyCameraAndMakeSideBySide(controller, proj[0, 2], proj[1, 2]);

        // Zoom the stereo cameras if requested.
        float lerp = Mathf.Clamp01(controller.matchByZoom) * Mathf.Clamp01(controller.matchMonoFOV);
        // Lerping the reciprocal of proj(1,1) so zooming is linear in the frustum width, not the depth.
        float monoProj11 = monoCamera.projectionMatrix[1, 1];
        float zoom       = 2 / Mathf.Lerp(1 / proj[1, 1], 1 / monoProj11, lerp) / proj[1, 1];

        proj[0, 0] *= zoom;
        proj[1, 1] *= zoom;

        // Calculate stereo adjustments based on the center of interest.
        float ipdScale;
        float eyeOffset;

        controller.ComputeStereoAdjustment(proj[1, 1], transform.lossyScale.z,
                                           out ipdScale, out eyeOffset);

        // Set up the eye's view transform.
        transform.localPosition = ipdScale * Cardboard.SDK.EyePose(eye).Position +
                                  eyeOffset * Vector3.forward;

        // Set up the eye's projection.
        float near = monoCamera.nearClipPlane;
        float far  = monoCamera.farClipPlane;

        FixProjection(ref proj, near, far, ipdScale);
        camera.projectionMatrix = proj;

        if (Application.isEditor)
        {
            // So you can see the approximate frustum in the Scene view when the camera is selected.
            camera.fieldOfView = 2 * Mathf.Atan(1 / proj[1, 1]) * Mathf.Rad2Deg;
        }

        Vuforia.VuforiaBehaviour.Instance.ApplyCorrectedProjectionMatrix(proj, eye == Cardboard.Eye.Left);

        // Set up variables for an image effect that will do distortion correction, e.g. the
        // RadialDistortionEffect.  Note that native distortion correction should take precedence
        // over an image effect, so if that is active then we don't need to compute these variables.
        // (Exception: we're in the editor, so we use the image effect to preview the distortion
        // correction, because native distortion correction only works on the phone.)
        if (Cardboard.SDK.UseDistortionEffect)
        {
            Matrix4x4 realProj = Cardboard.SDK.Projection(eye, Cardboard.Distortion.Undistorted);
            FixProjection(ref realProj, near, far, ipdScale);
            // Parts of the projection matrices that we need to convert texture coordinates between
            // distorted and undistorted frustums.  Include the transform between texture space [0..1]
            // and NDC [-1..1] (that's what the -1 and the /2 are for).  Also note that the zoom
            // factor is removed, because that will interfere with the distortion calculation.
            Vector4 projvec = new Vector4(proj[0, 0] / zoom, proj[1, 1] / zoom,
                                          proj[0, 2] - 1, proj[1, 2] - 1) / 2;
            Vector4 unprojvec = new Vector4(realProj[0, 0], realProj[1, 1],
                                            realProj[0, 2] - 1, realProj[1, 2] - 1) / 2;
            Shader.SetGlobalVector("_Projection", projvec);
            Shader.SetGlobalVector("_Unprojection", unprojvec);
            CardboardProfile p = Cardboard.SDK.Profile;
            Shader.SetGlobalVector("_Undistortion",
                                   new Vector4(p.device.inverse.k1, p.device.inverse.k2));
            Shader.SetGlobalVector("_Distortion",
                                   new Vector4(p.device.distortion.k1, p.device.distortion.k2));
        }

        if (controller.StereoScreen == null)
        {
            Rect rect = camera.rect;
            if (!Cardboard.SDK.DistortionCorrection ||
                Cardboard.SDK.UseDistortionEffect)
            {
                // We are rendering straight to the screen.  Use the reported rect that is visible
                // through the device's lenses.
                Rect view = Cardboard.SDK.Viewport(eye);
                if (eye == Cardboard.Eye.Right)
                {
                    rect.x -= 0.5f;
                }
                rect.width  *= 2 * view.width;
                rect.x       = view.x + 2 * rect.x * view.width;
                rect.height *= view.height;
                rect.y       = view.y + rect.y * view.height;
            }
            if (Application.isEditor)
            {
                // The Game window's aspect ratio may not match the fake device parameters.
                float realAspect       = (float)Screen.width / Screen.height;
                float fakeAspect       = Cardboard.SDK.Profile.screen.width / Cardboard.SDK.Profile.screen.height;
                float aspectComparison = fakeAspect / realAspect;
                if (aspectComparison < 1)
                {
                    rect.width *= aspectComparison;
                    rect.x     *= aspectComparison;
                    rect.x     += (1 - aspectComparison) / 2;
                }
                else
                {
                    rect.height /= aspectComparison;
                }
            }
            camera.rect = rect;
        }
    }
예제 #3
0
    public void Render()
    {
        // Shouldn't happen because of the check in Start(), but just in case...
        if (controller == null)
        {
            return;
        }

        var       camera     = GetComponent <Camera>();
        var       monoCamera = controller.GetComponent <Camera>();
        Matrix4x4 proj       = Cardboard.SDK.Projection(eye);

        CopyCameraAndMakeSideBySide(controller, proj[0, 2], proj[1, 2]);

        // Calculate stereo adjustments based on the center of interest.
        float ipdScale;
        float eyeOffset;

        controller.ComputeStereoAdjustment(proj[1, 1], transform.lossyScale.z,
                                           out ipdScale, out eyeOffset);

        // Set up the eye's view transform.
        transform.localPosition = ipdScale * Cardboard.SDK.EyeOffset(eye) +
                                  eyeOffset * Vector3.forward;

        // Set up the eye's projection.

        // Adjust for non-fullscreen camera.  Cardboard SDK assumes fullscreen,
        // so the aspect ratio might not match.
        proj[0, 0] *= camera.rect.height / camera.rect.width / 2;

        // Adjust for IPD scale.  This changes the vergence of the two frustums.
        Vector2 dir = transform.localPosition; // ignore Z

        dir         = dir.normalized * ipdScale;
        proj[0, 2] *= Mathf.Abs(dir.x);
        proj[1, 2] *= Mathf.Abs(dir.y);

        // Cardboard had to pass "nominal" values of near/far to the SDK, which
        // we fix here to match our mono camera's specific values.
        float near = monoCamera.nearClipPlane;
        float far  = monoCamera.farClipPlane;

        proj[2, 2] = (near + far) / (near - far);
        proj[2, 3] = 2 * near * far / (near - far);

        camera.projectionMatrix = proj;

        if (Application.isEditor)
        {
            // So you can see the approximate frustum in the Scene view when the camera is selected.
            camera.fieldOfView = 2 * Mathf.Atan(1 / proj[1, 1]) * Mathf.Rad2Deg;
        }

        RenderTexture stereoScreen = controller.StereoScreen;

        // Use the "fast" or "slow" method.  Fast means the camera draws right into one half of
        // the stereo screen.  Slow means it draws first to a side buffer, and then the buffer
        // is written to the screen. The slow method is provided because a lot of Image Effects
        // don't work if you draw to only part of the window.
        if (controller.directRender)
        {
            // Redirect to our stereo screen.
            camera.targetTexture = stereoScreen;
            // Draw!
            camera.Render();
        }
        else
        {
            // Save the viewport rectangle and reset to "full screen".
            Rect pixRect = camera.pixelRect;
            camera.rect = new Rect(0, 0, 1, 1);
            // Redirect to a temporary texture.  The defaults are supposedly Android-friendly.
            int depth = stereoScreen ? stereoScreen.depth : 16;
            RenderTextureFormat format = stereoScreen ? stereoScreen.format : RenderTextureFormat.RGB565;
            camera.targetTexture = RenderTexture.GetTemporary((int)pixRect.width, (int)pixRect.height,
                                                              depth, format);
            // Draw!
            camera.Render();
            // Blit the temp texture to the stereo screen.
            RenderTexture oldTarget = RenderTexture.active;
            RenderTexture.active = stereoScreen;
            GL.PushMatrix();
            GL.LoadPixelMatrix(0, stereoScreen ? stereoScreen.width : Screen.width,
                               stereoScreen ? stereoScreen.height : Screen.height, 0);
            Graphics.DrawTexture(pixRect, camera.targetTexture);
            // Clean up.
            GL.PopMatrix();
            RenderTexture.active = oldTarget;
            RenderTexture.ReleaseTemporary(camera.targetTexture);
            camera.targetTexture = null;
        }
    }