コード例 #1
0
        private void ComputeOrthographicViewingFrustum(WaterRenderingCameraFrustum renderingCameraFrustum, bool computePixelSize, Vector2 boundingBoxMin, Vector2 boundingBoxMax, float zFar, bool renderRefraction, bool renderReflection, float reflectionAxis, float reflectionZOffset, float reflectionFrustumHeightScalingFactor, float reflectionYOffset)
        {
            var wnrBoundingBoxMin = _mainModule.TransformPointLocalToWorldNoRotation(boundingBoxMin);
            var wnrBoundingBoxMax = _mainModule.TransformPointLocalToWorldNoRotation(boundingBoxMax);

            float frustumWidth  = wnrBoundingBoxMax.x - wnrBoundingBoxMin.x;
            float frustumHeight = wnrBoundingBoxMax.y - wnrBoundingBoxMin.y;

            if (computePixelSize)
            {
                var   currentCamera = renderingCameraFrustum.CurrentCamera;
                float pixelsPerUnit = currentCamera.pixelHeight * 0.5f / currentCamera.orthographicSize;
                PixelWidth  = (int)(frustumWidth * pixelsPerUnit);
                PixelHeight = (int)(frustumHeight * pixelsPerUnit);

                if (!IsValid)
                {
                    return;
                }
            }

            Vector3 boundingBoxCenter = new Vector3((boundingBoxMin.x + boundingBoxMax.x) * 0.5f, (boundingBoxMin.y + boundingBoxMax.y) * 0.5f, renderingCameraFrustum.Position.z);
            float   halfFrustumWidth  = frustumWidth * 0.5f;
            float   halfFrustumHeight = frustumHeight * 0.5f;

            var rotation = Quaternion.Euler(0f, 0f, _mainModule.ZRotation);

            if (renderRefraction)
            {
                RefractionProperties.Position         = _mainModule.TransformPointLocalToWorld(boundingBoxCenter);
                RefractionProperties.Rotation         = rotation;
                RefractionProperties.ProjectionMatrix = Matrix4x4.Ortho(-halfFrustumWidth, halfFrustumWidth, -halfFrustumHeight, halfFrustumHeight, NEAR_CLIP_PLANE_OFFSET, zFar);
                RefractionProperties.NearClipPlane    = renderingCameraFrustum.CurrentCamera.nearClipPlane;
            }

            if (renderReflection)
            {
                ReflectionProperties.Position = _mainModule.TransformPointLocalToWorld(new Vector2(boundingBoxCenter.x, 2f * reflectionAxis - boundingBoxCenter.y)) + Vector3.up * reflectionYOffset;
                ReflectionProperties.Rotation = rotation;

                if (!renderRefraction || reflectionFrustumHeightScalingFactor != 1f || reflectionZOffset != 0f)
                {
                    ReflectionProperties.ProjectionMatrix = Matrix4x4.Ortho(-halfFrustumWidth, halfFrustumWidth, -halfFrustumHeight, halfFrustumHeight * reflectionFrustumHeightScalingFactor, reflectionZOffset + NEAR_CLIP_PLANE_OFFSET, zFar);
                }
                else
                {
                    ReflectionProperties.ProjectionMatrix = RefractionProperties.ProjectionMatrix;
                }

                ReflectionProperties.NearClipPlane = reflectionZOffset + NEAR_CLIP_PLANE_OFFSET;
            }

            IsOrthographicCamera = true;
            OrthographicSize     = halfFrustumHeight;
            Aspect       = frustumWidth / frustumHeight;
            FarClipPlane = zFar;

            FrustumBottomEdgeLocalSpace = boundingBoxMin.y;
            FrustumTopEdgeLocalSpace    = boundingBoxMax.y;
        }
コード例 #2
0
        internal void Initialize()
        {
            _meshModule.MeshRenderer.sortingOrder   = _sortingOrder;
            _meshModule.MeshRenderer.sortingLayerID = _sortingLayerID;

            _fullWaterVisibleArea = new WaterRenderingVisibleArea(_mainModule);
            _surfaceVisibleArea   = new WaterRenderingVisibleArea(_mainModule);
            _surfaceBelowSubmergeLevelVisibleArea = new WaterRenderingVisibleArea(_mainModule);

            _renderingCameraFrustum = new WaterRenderingCameraFrustum(_mainModule);

            _clipeePoints = new SimpleFixedSizedList <Vector2>(8);
        }
コード例 #3
0
        private void MatchToCurrentCameraOrthographicViewingFrustum(WaterRenderingCameraFrustum renderingCameraFrustum, bool computePixelSize, float zFar, bool renderRefraction, bool renderReflection, float reflectionAxis, float reflectionZOffset, float reflectionFrustumHeightScalingFactor, float reflectionYOffset)
        {
            Camera currentCamera = renderingCameraFrustum.CurrentCamera;

            float orthographicSize = currentCamera.orthographicSize;
            float aspect           = currentCamera.aspect;

            float halfFrustumHeight = orthographicSize;
            float halfFrustumWidth  = halfFrustumHeight * aspect;

            if (computePixelSize)
            {
                PixelWidth  = currentCamera.pixelWidth;
                PixelHeight = currentCamera.pixelHeight;
            }

            Vector3 lCurrentRenderingCameraPosition = renderingCameraFrustum.Position;

            if (renderRefraction)
            {
                RefractionProperties.Position         = _mainModule.TransformPointLocalToWorld(lCurrentRenderingCameraPosition);
                RefractionProperties.Rotation         = Quaternion.Euler(0f, 0f, renderingCameraFrustum.Rotation.z + _mainModule.ZRotation);
                RefractionProperties.ProjectionMatrix = Matrix4x4.Ortho(-halfFrustumWidth, halfFrustumWidth, -halfFrustumHeight, halfFrustumHeight, NEAR_CLIP_PLANE_OFFSET, zFar);
                RefractionProperties.NearClipPlane    = currentCamera.nearClipPlane;
            }

            if (renderReflection)
            {
                ReflectionProperties.Position = _mainModule.TransformPointLocalToWorld(new Vector3(lCurrentRenderingCameraPosition.x, 2f * reflectionAxis - lCurrentRenderingCameraPosition.y)) + Vector3.up * reflectionYOffset;
                ReflectionProperties.Rotation = Quaternion.Euler(0f, 0f, -renderingCameraFrustum.Rotation.z + _mainModule.ZRotation);

                if (!renderRefraction || reflectionFrustumHeightScalingFactor != 1f || reflectionZOffset != 0f)
                {
                    ReflectionProperties.ProjectionMatrix = Matrix4x4.Ortho(-halfFrustumWidth, halfFrustumWidth, -halfFrustumHeight, halfFrustumHeight * reflectionFrustumHeightScalingFactor, reflectionZOffset + NEAR_CLIP_PLANE_OFFSET, zFar);
                }
                else
                {
                    ReflectionProperties.ProjectionMatrix = RefractionProperties.ProjectionMatrix;
                }

                ReflectionProperties.NearClipPlane = reflectionZOffset + NEAR_CLIP_PLANE_OFFSET;
            }

            IsOrthographicCamera = true;
            OrthographicSize     = orthographicSize;
            Aspect       = aspect;
            FarClipPlane = zFar;

            FrustumBottomEdgeLocalSpace = lCurrentRenderingCameraPosition.y - halfFrustumHeight;
            FrustumTopEdgeLocalSpace    = lCurrentRenderingCameraPosition.y + halfFrustumHeight;
        }
        override internal void Initialize()
        {
            _mainModule     = _waterfallObject.MainModule;
            _meshModule     = _waterfallObject.MeshModule;
            _materialModule = _waterfallObject.MaterialModule;

            _visibleArea            = new WaterRenderingVisibleArea(_mainModule);
            _renderingCameraFrustum = new WaterRenderingCameraFrustum(_mainModule);

            if (_clipeePoints == null)
            {
                _clipeePoints = new SimpleFixedSizeList <Vector2>(8);
            }

            base.Initialize();
        }
コード例 #5
0
        private void MatchVisibleAreaToCameraFrustum(WaterRenderingCameraFrustum cameraFrustum, float zFar, bool isReflectionEnabled, float reflectionAxis, float heightScaleFactor)
        {
            _position   = cameraFrustum.WorldSpace.Position;
            _position.z = _mainModule.Position.z;
            _rotation   = Quaternion.Euler(0f, 0f, cameraFrustum.WorldSpace.ZRotation);

            if (isReflectionEnabled)
            {
                Vector2 cameraPositionInLocalSpace = cameraFrustum.WaterLocalSpace.Position;
                _positionReflection = _mainModule.TransformLocalToWorld(new Vector3(cameraPositionInLocalSpace.x, 2f * reflectionAxis - cameraPositionInLocalSpace.y));
                _rotationReflection = Quaternion.Euler(0f, 0f, -cameraFrustum.WaterLocalSpace.ZRotation + _mainModule.ZRotation);
            }

            _width  = cameraFrustum.WorldSpace.Width;
            _height = cameraFrustum.WorldSpace.Height;

            float halfWidth  = _width * 0.5f;
            float halfHeight = _height * 0.5f;

            _projectionMatrix = Matrix4x4.Ortho(-halfWidth, halfWidth, -halfHeight, halfHeight * heightScaleFactor, 0f, zFar);
        }
コード例 #6
0
        internal void UpdateArea(SimpleFixedSizedList <Vector2> points, WaterRenderingCameraFrustum cameraFrustrum, bool isFullyContainedInWaterBox, float zFar, bool isReflectionEnabled, float reflectionAxis, float viewingFrustrumHeightScalingFactor = 1f)
        {
            _isValid = true;

            if (isFullyContainedInWaterBox)
            {
                MatchVisibleAreaToCameraFrustum(cameraFrustrum, zFar, isReflectionEnabled, reflectionAxis, viewingFrustrumHeightScalingFactor);
                return;
            }

            _isValid = points.Count > 0;
            if (!_isValid)
            {
                return;
            }

            // Compute the AABB of provided points
            Vector2 boundingBoxMin = points[0];
            Vector2 boundingBoxMax = points[0];

            for (int i = 1, imax = points.Count; i < imax; i++)
            {
                Vector2 point = points[i];

                if (point.x < boundingBoxMin.x)
                {
                    boundingBoxMin.x = point.x;
                }

                if (point.x > boundingBoxMax.x)
                {
                    boundingBoxMax.x = point.x;
                }

                if (point.y < boundingBoxMin.y)
                {
                    boundingBoxMin.y = point.y;
                }

                if (point.y > boundingBoxMax.y)
                {
                    boundingBoxMax.y = point.y;
                }
            }

            float boundingBoxArea = (boundingBoxMax.x - boundingBoxMin.x) * (boundingBoxMax.y - boundingBoxMin.y);

            _isValid = boundingBoxArea > 0f;
            if (!_isValid)
            {
                return;
            }

            if (boundingBoxArea > cameraFrustrum.WaterLocalSpace.Area)
            {
                MatchVisibleAreaToCameraFrustum(cameraFrustrum, zFar, isReflectionEnabled, reflectionAxis, viewingFrustrumHeightScalingFactor);
                return;
            }

            Vector2 boundsCenter = (boundingBoxMin + boundingBoxMax) * 0.5f;

            _position = _mainModule.TransformLocalToWorld(boundsCenter);
            _rotation = Quaternion.Euler(0f, 0f, _mainModule.ZRotation);

            if (isReflectionEnabled)
            {
                _positionReflection = _mainModule.TransformLocalToWorld(new Vector3(boundsCenter.x, 2f * reflectionAxis - boundsCenter.y));
                _rotationReflection = _rotation;
            }

            if (_mainModule.ZRotation != 0f)
            {
                Vector2 topLeft    = _mainModule.TransformLocalToWorld(new Vector2(boundingBoxMin.x, boundingBoxMax.y));
                Vector2 bottomLeft = _mainModule.TransformLocalToWorld(boundingBoxMin);
                Vector2 topRight   = _mainModule.TransformLocalToWorld(boundingBoxMax);
                _width  = Vector2.Distance(topLeft, topRight);
                _height = Vector2.Distance(bottomLeft, topLeft);
            }
            else
            {
                boundingBoxMin = _mainModule.TransformLocalToWorld(boundingBoxMin);
                boundingBoxMax = _mainModule.TransformLocalToWorld(boundingBoxMax);
                _width         = boundingBoxMax.x - boundingBoxMin.x;
                _height        = boundingBoxMax.y - boundingBoxMin.y;
            }

            float halfWidth  = _width * 0.5f;
            float halfHeight = _height * 0.5f;

            _projectionMatrix = Matrix4x4.Ortho(-halfWidth, halfWidth, -halfHeight, halfHeight * viewingFrustrumHeightScalingFactor, 0f, zFar);
        }
コード例 #7
0
        internal void UpdateArea(SimpleFixedSizeList <Vector2> points, WaterRenderingCameraFrustum cameraFrustum, bool isFullyContainedInWaterBox, bool computePixelSize, float zFar, bool renderRefraction = true, bool renderReflection = false, float reflectionZOffset = 0f, float reflectionAxis = 0f, float reflectionFrustumHeightScalingFactor = 1f)
        {
            IsValid = true;

            var currentCamera = cameraFrustum.CurrentCamera;

            if (isFullyContainedInWaterBox && currentCamera.orthographic && !cameraFrustum.IsIsometric)
            {
                MatchToCurrentCameraOrthographicViewingFrustum(cameraFrustum, computePixelSize, zFar, renderRefraction, renderReflection, reflectionAxis, reflectionZOffset, reflectionFrustumHeightScalingFactor);
                return;
            }

            IsValid = points.Count > 0;
            if (!IsValid)
            {
                return;
            }

            // Compute the AABB of provided points (in water-local space)
            Vector2 boundingBoxMin = points[0];
            Vector2 boundingBoxMax = points[0];

            for (int i = 1, imax = points.Count; i < imax; i++)
            {
                Vector2 point = points[i];

                if (point.x < boundingBoxMin.x)
                {
                    boundingBoxMin.x = point.x;
                }

                if (point.x > boundingBoxMax.x)
                {
                    boundingBoxMax.x = point.x;
                }

                if (point.y < boundingBoxMin.y)
                {
                    boundingBoxMin.y = point.y;
                }

                if (point.y > boundingBoxMax.y)
                {
                    boundingBoxMax.y = point.y;
                }
            }

            if (currentCamera.orthographic)
            {
                if (cameraFrustum.IsIsometric)
                {
                    ComputeIsometricViewingFrustum(cameraFrustum, computePixelSize, boundingBoxMin, boundingBoxMax, zFar, renderRefraction, renderReflection, reflectionAxis, reflectionZOffset, reflectionFrustumHeightScalingFactor);
                }
                else
                {
                    ComputeOrthographicViewingFrustum(cameraFrustum, computePixelSize, boundingBoxMin, boundingBoxMax, zFar, renderRefraction, renderReflection, reflectionAxis, reflectionZOffset, reflectionFrustumHeightScalingFactor);
                }

                return;
            }

            ComputePerspectiveViewingFrustum(cameraFrustum, computePixelSize, boundingBoxMin, boundingBoxMax, zFar, renderRefraction, renderReflection, reflectionAxis, reflectionZOffset, reflectionFrustumHeightScalingFactor, isFullyContainedInWaterBox);
        }
コード例 #8
0
        private void ComputePerspectiveViewingFrustum(WaterRenderingCameraFrustum renderingCameraFrustum, bool computePixelSize, Vector2 boundingBoxMin, Vector2 boundingBoxMax, float zFar, bool renderRefraction, bool renderReflection, float reflectionAxis, float reflectionZOffset, float reflectionFrustumHeightScalingFactor, bool isFullyContainedInWaterBox)
        {
            var wnrBoundingBoxMin = _mainModule.TransformPointLocalToWorldNoRotation(boundingBoxMin);
            var wnrBoundingBoxMax = _mainModule.TransformPointLocalToWorldNoRotation(boundingBoxMax);

            var currentCamera = renderingCameraFrustum.CurrentCamera;

            if (computePixelSize)
            {
                if (isFullyContainedInWaterBox)
                {
                    PixelWidth  = currentCamera.pixelWidth;
                    PixelHeight = currentCamera.pixelHeight;
                }
                else
                {
                    var sBoundingBoxMin = currentCamera.WorldToScreenPoint(wnrBoundingBoxMin);
                    var sBoundingBoxMax = currentCamera.WorldToScreenPoint(wnrBoundingBoxMax);

                    if (renderingCameraFrustum.Rotation.z != 0f && renderingCameraFrustum.Rotation.z != 180f)
                    {
                        var sBoundingBoxMinXMaxY = currentCamera.WorldToScreenPoint(new Vector3(wnrBoundingBoxMin.x, wnrBoundingBoxMax.y, wnrBoundingBoxMin.z));
                        var sBoundingBoxMaxXMinY = currentCamera.WorldToScreenPoint(new Vector3(wnrBoundingBoxMax.x, wnrBoundingBoxMin.y, wnrBoundingBoxMin.z));
                        PixelWidth  = (int)(Mathf.Max(Vector2.Distance(sBoundingBoxMinXMaxY, sBoundingBoxMax), Vector2.Distance(sBoundingBoxMin, sBoundingBoxMaxXMinY)));
                        PixelHeight = (int)(Mathf.Max(Vector2.Distance(sBoundingBoxMin, sBoundingBoxMinXMaxY), Vector2.Distance(sBoundingBoxMaxXMinY, sBoundingBoxMax)));
                    }
                    else
                    {
                        PixelWidth  = (int)(sBoundingBoxMax.x - sBoundingBoxMin.x);
                        PixelHeight = (int)(sBoundingBoxMax.y - sBoundingBoxMin.y);
                    }
                }

                if (!IsValid)
                {
                    return;
                }
            }

            Vector3 lCurrentRenderingCameraPosition   = renderingCameraFrustum.Position;
            Vector3 wnrCurrentRenderingCameraPosition = _mainModule.TransformPointLocalToWorldNoRotation(lCurrentRenderingCameraPosition);

            float nearClipPlane = _mainModule.Position.z - wnrCurrentRenderingCameraPosition.z;
            float farClipPlane  = nearClipPlane + zFar;

            float frustumLeft   = wnrBoundingBoxMin.x - wnrCurrentRenderingCameraPosition.x;
            float frustumRight  = wnrBoundingBoxMax.x - wnrCurrentRenderingCameraPosition.x;
            float frustumTop    = wnrBoundingBoxMax.y - wnrCurrentRenderingCameraPosition.y;
            float frustumBottom = wnrBoundingBoxMin.y - wnrCurrentRenderingCameraPosition.y;

            var rotation = Quaternion.Euler(0f, 0f, _mainModule.ZRotation);

            if (renderRefraction)
            {
                RefractionProperties.Position         = _mainModule.TransformPointLocalToWorld(renderingCameraFrustum.Position);
                RefractionProperties.Rotation         = rotation;
                RefractionProperties.ProjectionMatrix = Matrix4x4.Frustum(frustumLeft, frustumRight, frustumBottom, frustumTop, nearClipPlane - 0.001f, farClipPlane);
                RefractionProperties.NearClipPlane    = nearClipPlane;
            }

            if (renderReflection)
            {
                lCurrentRenderingCameraPosition.y = 2f * reflectionAxis - lCurrentRenderingCameraPosition.y;

                ReflectionProperties.Position = _mainModule.TransformPointLocalToWorld(lCurrentRenderingCameraPosition);
                ReflectionProperties.Rotation = rotation;

                float reflectionFrustumTop;

                if (reflectionFrustumHeightScalingFactor != 1f)
                {
                    float wnrReflectionFrustumTopEdge = 0.5f * (wnrBoundingBoxMin.y * (1f + reflectionFrustumHeightScalingFactor) + wnrBoundingBoxMax.y * (1f - reflectionFrustumHeightScalingFactor));
                    reflectionFrustumTop = wnrCurrentRenderingCameraPosition.y - wnrReflectionFrustumTopEdge;
                }
                else
                {
                    reflectionFrustumTop = -frustumBottom;
                }

                if (reflectionZOffset == 0f)
                {
                    ReflectionProperties.NearClipPlane    = nearClipPlane;
                    ReflectionProperties.ProjectionMatrix = Matrix4x4.Frustum(frustumLeft, frustumRight, -frustumTop, reflectionFrustumTop, nearClipPlane, farClipPlane);
                }
                else
                {
                    float reflectionNearClipPlane = Mathf.Clamp(nearClipPlane + reflectionZOffset, 0.01f, farClipPlane - 0.01f);
                    float s = reflectionNearClipPlane / nearClipPlane;

                    float reflectionFrustumLeft   = frustumLeft * s;
                    float reflectionFrustumRight  = frustumRight * s;
                    float reflectionFrustumBottom = -frustumTop * s;
                    reflectionFrustumTop *= s;

                    ReflectionProperties.NearClipPlane    = reflectionNearClipPlane;
                    ReflectionProperties.ProjectionMatrix = Matrix4x4.Frustum(reflectionFrustumLeft, reflectionFrustumRight, reflectionFrustumBottom, reflectionFrustumTop, reflectionNearClipPlane, farClipPlane);
                }
            }

            IsOrthographicCamera = false;
            FieldOfView          = currentCamera.fieldOfView;
            Aspect       = (frustumRight - frustumLeft) / (frustumTop - frustumBottom);
            FarClipPlane = farClipPlane;
        }
コード例 #9
0
        private void ComputeIsometricViewingFrustum(WaterRenderingCameraFrustum renderingCameraFrustum, bool computePixelSize, Vector2 boundingBoxMin, Vector2 boundingBoxMax, float zFar, bool renderRefraction, bool renderReflection, float reflectionAxis, float reflectionZOffset, float reflectionFrustumHeightScalingFactor)
        {
            var currentCamera = renderingCameraFrustum.CurrentCamera;

            var waterLocalSpaceToCameraSpaceMatrix = currentCamera.worldToCameraMatrix * _mainModule.LocalToWorldMatrix;

            Vector3 cBoundingBoxMin      = waterLocalSpaceToCameraSpaceMatrix.MultiplyPoint3x4(boundingBoxMin);
            Vector3 cBoundingBoxMax      = waterLocalSpaceToCameraSpaceMatrix.MultiplyPoint3x4(boundingBoxMax);
            Vector3 cBoundingBoxMinXMaxY = waterLocalSpaceToCameraSpaceMatrix.MultiplyPoint3x4(new Vector3(boundingBoxMin.x, boundingBoxMax.y));
            Vector3 cBoundingBoxMaxXMinY = waterLocalSpaceToCameraSpaceMatrix.MultiplyPoint3x4(new Vector3(boundingBoxMax.x, boundingBoxMin.y));

            Vector3 frustumBottomLeft, frustumTopRight;

            frustumBottomLeft.x = WaterUtility.Min(cBoundingBoxMin.x, cBoundingBoxMinXMaxY.x, cBoundingBoxMax.x, cBoundingBoxMaxXMinY.x);
            frustumBottomLeft.y = WaterUtility.Min(cBoundingBoxMin.y, cBoundingBoxMinXMaxY.y, cBoundingBoxMax.y, cBoundingBoxMaxXMinY.y);

            frustumTopRight.x = WaterUtility.Max(cBoundingBoxMin.x, cBoundingBoxMinXMaxY.x, cBoundingBoxMax.x, cBoundingBoxMaxXMinY.x);
            frustumTopRight.y = WaterUtility.Max(cBoundingBoxMin.y, cBoundingBoxMinXMaxY.y, cBoundingBoxMax.y, cBoundingBoxMaxXMinY.y);

            float nearClipPlane = -WaterUtility.Max(cBoundingBoxMin.z, cBoundingBoxMinXMaxY.z, cBoundingBoxMax.z, cBoundingBoxMaxXMinY.z);

            float frustumWidth  = frustumTopRight.x - frustumBottomLeft.x;
            float frustumHeight = frustumTopRight.y - frustumBottomLeft.y;

            if (computePixelSize)
            {
                float pixelsPerUnit = currentCamera.pixelHeight * 0.5f / currentCamera.orthographicSize;
                PixelWidth  = (int)(frustumWidth * pixelsPerUnit);
                PixelHeight = (int)(frustumHeight * pixelsPerUnit);

                if (!IsValid)
                {
                    return;
                }
            }

            float farClipPlane = nearClipPlane + zFar;

            Vector3 position = currentCamera.cameraToWorldMatrix.MultiplyPoint3x4(new Vector3((frustumBottomLeft.x + frustumTopRight.x) * 0.5f, (frustumBottomLeft.y + frustumTopRight.y) * 0.5f));

            if (renderRefraction)
            {
                RefractionProperties.Position         = position;
                RefractionProperties.Rotation         = currentCamera.transform.rotation;
                RefractionProperties.ProjectionMatrix = ComputeObliqueOrthographicMatrix(frustumWidth, frustumHeight, nearClipPlane, farClipPlane, RefractionProperties.Position, RefractionProperties.Rotation, _mainModule.Position, _mainModule.ForwardDirection, -0.001f, 1f);
                RefractionProperties.NearClipPlane    = nearClipPlane;
            }

            if (renderReflection)
            {
                Vector3 lPosition = _mainModule.TransformPointWorldToLocal(position);
                lPosition.y = 2f * reflectionAxis - lPosition.y;

                Vector3 rotationEulerAngles = renderingCameraFrustum.Rotation;
                rotationEulerAngles.x *= -1f;
                rotationEulerAngles.z  = -rotationEulerAngles.z + _mainModule.ZRotation;

                ReflectionProperties.Position         = _mainModule.TransformPointLocalToWorld(lPosition);
                ReflectionProperties.Rotation         = Quaternion.Euler(rotationEulerAngles);
                ReflectionProperties.NearClipPlane    = nearClipPlane + reflectionZOffset;
                ReflectionProperties.ProjectionMatrix = ComputeObliqueOrthographicMatrix(frustumWidth, frustumHeight, ReflectionProperties.NearClipPlane, farClipPlane, ReflectionProperties.Position, ReflectionProperties.Rotation, _mainModule.Position, _mainModule.ForwardDirection, reflectionZOffset, reflectionFrustumHeightScalingFactor);
            }

            IsOrthographicCamera = true;
            OrthographicSize     = frustumHeight * 0.5f;
            Aspect       = frustumWidth / frustumHeight;
            FarClipPlane = farClipPlane;
        }