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; }
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); }
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(); }
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); }
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); }
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); }
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; }
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; }