//////////////////////////////////////////////////////////////// /// <summary> /// Returns a valid bridge that can be used to create a mesh /// </summary> /// <param name="validBridgeInput"></param> /// <returns></returns> public static Bridge PrepareBridge(CreateBridgeParameters createBridgParamters) { FindMirrorPointsForBridge(ref createBridgParamters); float bridgeLength = 0.0f; FindUVsForBridge(ref createBridgParamters, out bridgeLength); return(new Bridge(createBridgParamters.BridgePoints.ToArray(), bridgeLength)); }
//////////////////////////////////////////////////////////////// /// <summary> /// Finds the UVs for all points along a bridge /// </summary> /// <param name="inOutBridgePoints"></param> private static void FindUVsForBridge(ref CreateBridgeParameters inOutBridgePoints, out float bridgeLength) { Assert.IsTrue(inOutBridgePoints.BridgePoints.Count >= 2); //////////////////////////////////////////////////////////////// bridgeLength = 0.0f; ValidBridgePoint startPoint = inOutBridgePoints.BridgePoints[0]; startPoint.UV = new Vector2(bridgeLength, 0.0f); for (int i = 0; i < inOutBridgePoints.BridgePoints.Count - 1; i++) { Vector3 pointA = inOutBridgePoints.BridgePoints[i].PositionWS; Vector3 pointB = inOutBridgePoints.BridgePoints[i + 1].PositionWS; bridgeLength += Vector3.Distance(pointA, pointB); ValidBridgePoint bridgePoint = inOutBridgePoints.BridgePoints[i + 1]; bridgePoint.UV = new Vector2(bridgeLength, 0.0f); inOutBridgePoints.BridgePoints[i + 1] = bridgePoint; } }
/// <summary> /// Places the given bridge point /// </summary> /// <param name="placePoint"></param> /// <returns>True, if the bridge needs to be updated now</returns> bool PlaceBridgePoint(RawBridgePoint placePoint, out CreateBridgeParameters outBridgeParamters) { outBridgeParamters = new CreateBridgeParameters(); bool firstPointIsValid = m_FirstBridgePoint.IsValid(); bool secondPointIsValid = m_SecondBridgePoint.IsValid(); //////////////////////////////////////////////////////////////// if (!firstPointIsValid && !secondPointIsValid) { // No point set? Set the first point m_FirstBridgePoint = placePoint; } else if (firstPointIsValid && !secondPointIsValid) { // Does this point work to create a bridge? CreateBridgeParameters createBridgeParamters; BridgeValidationResult result = BridgePlanner.ValidateBridgePlacement(new ValidateBridgeInput(m_FirstBridgePoint, placePoint), out createBridgeParamters); if (result == BridgeValidationResult.Success) { // Yes! Lets prepare everything for updating the bridge m_SecondBridgePoint = placePoint; outBridgeParamters = createBridgeParamters; return(true); } else { // No. Instead, override the first point! m_FirstBridgePoint = placePoint; return(false); } } else if (firstPointIsValid && secondPointIsValid) { // First try to override second point, if that fails, try to override first point. // Try first point. CreateBridgeParameters createBridgeParamters; BridgeValidationResult result = BridgePlanner.ValidateBridgePlacement(new ValidateBridgeInput(m_FirstBridgePoint, placePoint), out createBridgeParamters); if (result == BridgeValidationResult.Success) { // Make the new point the second point m_SecondBridgePoint = placePoint; outBridgeParamters = createBridgeParamters; return(true); } else { result = BridgePlanner.ValidateBridgePlacement(new ValidateBridgeInput(placePoint, m_SecondBridgePoint), out createBridgeParamters); if (result == BridgeValidationResult.Success) { // Make the previous second the first point & the new point the second point m_FirstBridgePoint = m_SecondBridgePoint; m_SecondBridgePoint = placePoint; outBridgeParamters = createBridgeParamters; return(true); } else { return(false); } } } else { Debug.LogError("BridgePlanner: Second point is valid but first is not?!"); } return(false); }
//////////////////////////////////////////////////////////////// /// <summary> /// Checks if a valid bridge could exist between two input points /// </summary> /// <param name="bridgeInput"></param> /// <param name="bridgeOutput"></param> /// <returns></returns> public static BridgeValidationResult ValidateBridgePlacement(ValidateBridgeInput bridgeInput, out CreateBridgeParameters bridgeOutput) { bridgeOutput = CreateBridgeParameters.INVALIED; //////////////////////////////////////////////////////////////// // Input //////////////////////////////////////////////////////////////// Vector3 startPoint = bridgeInput.PointStart.PositionWS; Vector3 endPoint = bridgeInput.PointEnd.PositionWS; Vector3 startNormal = bridgeInput.PointStart.WallNormalWS; Vector3 endNormal = bridgeInput.PointEnd.WallNormalWS; Vector3 startToEnd = endPoint - startPoint; Vector3 startToEndRight = Vector3.Cross(startToEnd, Vector3.up); //////////////////////////////////////////////////////////////// // Get right extends //////////////////////////////////////////////////////////////// Vector3 startPointWallExtendRight = Vector3.Cross(startNormal, Vector3.up); Vector3 endPointWallExtendRight = Vector3.Cross(endNormal, Vector3.up); // The two normals should face each other if (Vector3.Dot(startPointWallExtendRight, endPointWallExtendRight) > 0) { return(BridgeValidationResult.TooNarrowToWallAngle); } // Start Point is facing opposite direction of End Point, so it checks for "< 0" instead of ">= 0" if (Vector3.Dot(startToEndRight, startPointWallExtendRight) < 0) { startPointWallExtendRight *= -1; } if (Vector3.Dot(startToEndRight, endPointWallExtendRight) >= 0) { endPointWallExtendRight *= -1; } //////////////////////////////////////////////////////////////// // Check both Wall Angles //////////////////////////////////////////////////////////////// float startPointWallAngle = Vector3.Angle(-startToEnd, startNormal); float endPointWallAngle = Vector3.Angle(startToEnd, endNormal); bool startAngleTooNarrow = startPointWallAngle < BridgeOptions.MIN_TO_WALL_ANGLE; bool endAngleTooNarrow = endPointWallAngle < BridgeOptions.MIN_TO_WALL_ANGLE; if (startAngleTooNarrow || endAngleTooNarrow) { return(BridgeValidationResult.TooNarrowToWallAngle); } //////////////////////////////////////////////////////////////// // Check Steepness //////////////////////////////////////////////////////////////// float steepness = Vector3.Angle(startToEnd, new Vector3(startToEnd.x, 0, startToEnd.z)); bool isPathTooSteep = steepness >= BridgeOptions.MAX_STEEP_ANGLE; if (isPathTooSteep) { return(BridgeValidationResult.TooSteep); } //////////////////////////////////////////////////////////////// // Check Blocking //////////////////////////////////////////////////////////////// float bridgeWidthHalf = BridgeOptions.WIDTH_WS / 2.0f; Vector3 startLeft = startPoint - startPointWallExtendRight * bridgeWidthHalf; Vector3 startRight = startPoint + startPointWallExtendRight * bridgeWidthHalf; //Vector3 endLeft = endPoint - startPointWallExtendRight * bridgeWidthHalf; //Vector3 endRight = endPoint + startPointWallExtendRight * bridgeWidthHalf; float rayLength = startToEnd.magnitude - 0.2f; Vector3 startToEndNormalized = startPoint.normalized; Ray rayLeft = new Ray(startLeft + startToEndNormalized * 0.1f, startToEndNormalized); Ray rayMid = new Ray(startPoint + startToEndNormalized * 0.1f, startToEndNormalized); Ray rayRight = new Ray(startRight + startToEndNormalized * 0.1f, startToEndNormalized); if (Physics.Raycast(rayLeft, rayLength) || Physics.Raycast(rayMid, rayLength) || Physics.Raycast(rayRight, rayLength)) { return(BridgeValidationResult.Blocked); } // UV not yet set, will be set when the bridge is created bridgeOutput = new CreateBridgeParameters( new ValidBridgePoint(bridgeInput.PointStart.PositionWS, bridgeInput.PointStart.WallNormalWS, bridgeInput.PointStart.IsMirror, startPointWallExtendRight, Vector3.up, Vector2.zero), new ValidBridgePoint(bridgeInput.PointEnd.PositionWS, bridgeInput.PointEnd.WallNormalWS, bridgeInput.PointEnd.IsMirror, endPointWallExtendRight, Vector3.up, Vector2.zero)); return(BridgeValidationResult.Success); }
/*////////////////////////////////////////////////////////////// * //// Private Helpers //// * //////////////////////////////////////////////////////////////*/ /// <summary> /// Finds all bridge points a bridge would have. /// </summary> /// <param name="validBridgeInput"></param> /// <returns></returns> private static void FindMirrorPointsForBridge(ref CreateBridgeParameters inOutBridgePoints) { Assert.IsTrue(inOutBridgePoints.BridgePoints.Count >= 2); #if DEBUG int debugCount = 0; #endif //////////////////////////////////////////////////////////////// // For both start & end point of the bridge parameters: // If the point is a mirror, try to find the point before. Continue until no mirror is hit anymore. //////////////////////////////////////////////////////////////// int indexMirrorPoint = 0; int indexOther = 1; // Start Point while (inOutBridgePoints.BridgePoints[indexMirrorPoint].IsMirror) { Vector3 backToFront = inOutBridgePoints.BridgePoints[indexOther].PositionWS - inOutBridgePoints.BridgePoints[indexMirrorPoint].PositionWS; Vector3 mirroredVector = Vector3.Reflect(backToFront, inOutBridgePoints.BridgePoints[indexMirrorPoint].WallNormalWS); Vector3 mirroredVectorN = mirroredVector.normalized; Vector3 startPosition = inOutBridgePoints.BridgePoints[indexMirrorPoint].PositionWS + mirroredVectorN * BridgeOptions.RAYCAST_PADDING; Ray ray = new Ray(startPosition, mirroredVector * BridgeOptions.MAX_BRIDGE_LENGTH); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { RawBridgePoint newPoint; if (ValidateBridgePoint(hit, out newPoint) == BridgePointValidationResult.Success) { Vector3 wallExtendRight = Vector3.Cross(hit.normal, Vector3.up); ValidBridgePoint newValidPoint = new ValidBridgePoint(newPoint.PositionWS, newPoint.WallNormalWS, newPoint.IsMirror, wallExtendRight, Vector3.up, Vector3.zero); inOutBridgePoints.BridgePoints.Insert(indexMirrorPoint, newValidPoint); } #if DEBUG Assert.IsTrue(debugCount < 20); #endif continue; } break; } // End Point indexMirrorPoint = inOutBridgePoints.BridgePoints.Count - 1; indexOther = inOutBridgePoints.BridgePoints.Count - 2; // End Point while (inOutBridgePoints.BridgePoints[indexMirrorPoint].IsMirror) { Vector3 backToFront = inOutBridgePoints.BridgePoints[indexMirrorPoint].PositionWS - inOutBridgePoints.BridgePoints[indexOther].PositionWS; Vector3 mirroredVector = Vector3.Reflect(backToFront, inOutBridgePoints.BridgePoints[indexMirrorPoint].WallNormalWS); Vector3 mirroredVectorN = mirroredVector.normalized; Vector3 startPosition = inOutBridgePoints.BridgePoints[indexMirrorPoint].PositionWS + mirroredVectorN * BridgeOptions.RAYCAST_PADDING; Ray ray = new Ray(startPosition, mirroredVector * BridgeOptions.MAX_BRIDGE_LENGTH); RaycastHit hit; if (Physics.Raycast(ray, out hit)) { RawBridgePoint newPoint; if (ValidateBridgePoint(hit, out newPoint) == BridgePointValidationResult.Success) { Vector3 wallExtendRight = Vector3.Cross(hit.normal, Vector3.up); ValidBridgePoint newValidPoint = new ValidBridgePoint(newPoint.PositionWS, newPoint.WallNormalWS, newPoint.IsMirror, wallExtendRight, Vector3.up, Vector3.zero); inOutBridgePoints.BridgePoints.Add(newValidPoint); } #if DEBUG Assert.IsTrue(debugCount < 20); #endif indexMirrorPoint = inOutBridgePoints.BridgePoints.Count - 1; indexOther = inOutBridgePoints.BridgePoints.Count - 2; continue; } break; } }