示例#1
0
 public static Fov DistortTanAngles(Fov tanAngles, Distortion distortion)
 {
     return(new Fov
            (
                distortion.Distort(tanAngles.Left),
                distortion.Distort(tanAngles.Right),
                distortion.Distort(tanAngles.Bottom),
                distortion.Distort(tanAngles.Top)
            ));
 }
        private void UpdateUndistortionTex(Distortion distortion, float maxDistortedValue)
        {
            const int n = 16;

            float[] distortedValues = new float[n];

            float distortedValue     = 0f;
            float distortedValueStep = maxDistortedValue / (n - 1);

            // Генерируется n точек
            for (int i = 0; i < n; i++)
            {
                distortedValues[i] = distortedValue;
                distortedValue    += distortedValueStep;
            }

            // Составляется кубический сплайн по n точкам. Сплайн используется для интерполяции функции, обратной к дисторсии
            CubicHermiteSpline spline = new CubicHermiteSpline(distortion, distortedValues);

            distortedValue     = 0f;
            distortedValueStep = maxDistortedValue / (texWidth - 1);

            // Точно известно, что функция дисторсии принимает значения больше своего аргумента
            // Следовательно обратная функция будет всегда меньше аргумента. Это значит, что значение обратной ф-ции можно нормировать.
            // Для каждой точки текстуры вычисляется значение сплайна в точке, после чего делится на значение самой точки. Получается число от [0..1], оно записывается в цвет.
            for (int i = 0; i < _undistortionTex.width; ++i)
            {
                float eyeTanAngleNormalized = 1f;

                if (i > 0)
                {
                    float undistortedValue = spline.GetValue(distortedValue);

                    // Страховка от отклонений сплайна
                    if (undistortedValue < distortedValue)
                    {
                        eyeTanAngleNormalized = undistortedValue / distortedValue;
                    }
                }

                _undistortionTex.SetPixel(i, 0, new Color(eyeTanAngleNormalized, 0f, 0f));

                distortedValue += distortedValueStep;
            }

            _undistortionTex.Apply();
        }
        void UpdateView(HmdParameters hmd, DisplayParameters display)
        {
            Distortion distortion = new Distortion(hmd.DistortionK1, hmd.DistortionK2);

            float zNear = _camWorldLeft.nearClipPlane;
            float zFar  = _camWorldLeft.farClipPlane;

            Fov displayDistancesLeft = Calculator.GetFovDistancesLeft(display, hmd);

            // То, как должен видеть левый глаз свой кусок экрана. Без линзы. C учётом только размеров дисплея
            Fov fovDisplayTanAngles = displayDistancesLeft / hmd.ScreenToLensDist;

            // FoV шлема
            Fov hmdMaxFovTanAngles = Fov.AnglesToTanAngles(hmd.MaxFovAngles);

            // То, как должен видеть левый глаз свой кусок экрана. Без линзы. C учётом размеров дисплея и FoV шлема
            Fov fovEyeTanAglesLeft = Fov.Min(fovDisplayTanAngles, hmdMaxFovTanAngles);

            // То, как должен видеть левый глаз. Мнимое изображение (после увеличения идеальной линзой без искажений). С широким углом. Именно так надо снять сцену
            Fov fovWorldTanAnglesLeft = Calculator.DistortTanAngles(fovEyeTanAglesLeft, distortion);

            Matrix4x4 projWorldLeft;
            Matrix4x4 projWorldRight;

            Calculator.ComposeProjectionMatricesFromFovTanAngles(fovWorldTanAnglesLeft, zNear, zFar, out projWorldLeft, out projWorldRight);

            Matrix4x4 projEyeLeft;
            Matrix4x4 projEyeRight;

            Calculator.ComposeProjectionMatricesFromFovTanAngles(fovDisplayTanAngles, zNear, zFar, out projEyeLeft, out projEyeRight);

            _camWorldLeft.transform.localPosition  = 0.5f * Vector3.left * hmd.InterlensDistance;
            _camWorldRight.transform.localPosition = 0.5f * Vector3.right * hmd.InterlensDistance;

            _camWorldLeft.projectionMatrix  = projWorldLeft;
            _camWorldRight.projectionMatrix = projWorldRight;

            float maxWorldFovTanAngle = GetMaxDiagonalValue(fovWorldTanAnglesLeft);

            UpdateUndistortionTex(distortion, maxWorldFovTanAngle);

            EyeMaterial.SetFloat("_MaxWorldFovTanAngle", maxWorldFovTanAngle);
            EyeMaterial.SetTexture("_UndistortionTex", _undistortionTex);
            EyeMaterial.SetVector("_ProjectionWorldLeft", ComposeProjectionVector(projWorldLeft));
            EyeMaterial.SetVector("_ProjectionEyeLeft", ComposeProjectionVector(projEyeLeft));
        }