public void CopyVertexPathData(VertexPath vertexPath, bool useLocalTransform) { space = vertexPath.space; isClosedLoop = vertexPath.isClosedLoop; localPoints = CopyArray(vertexPath.localPoints); localTangents = CopyArray(vertexPath.localTangents); localNormals = CopyArray(vertexPath.localNormals); times = CopyArray(vertexPath.times); length = vertexPath.length; cumulativeLengthAtEachVertex = CopyArray(vertexPath.cumulativeLengthAtEachVertex); bounds = vertexPath.bounds; up = vertexPath.up; if (useLocalTransform) { transformPosition = vertexPath.LinkedTransform.localPosition; transformRotation = vertexPath.LinkedTransform.localRotation; transformLossyScale = vertexPath.LinkedTransform.localScale; } else { transformPosition = vertexPath.LinkedTransform.position; transformRotation = vertexPath.LinkedTransform.rotation; transformLossyScale = vertexPath.LinkedTransform.lossyScale; } pathUpdated?.Invoke(); }
public static Vector3 TransformDirection(Vector3 p, Quaternion r, PathSpace space) { Quaternion constrainedRot = r; ConstrainRot(ref constrainedRot, space); return(constrainedRot * p); }
/// <summary> Creates a path from the supplied 3D points </summary> ///<param name="anchorPoints"> List or array of points to create the path from. </param> ///<param name="isClosed"> Should the end point connect back to the start point? </param> ///<param name="space"> Determines if the path is in 3d space, or clamped to the xy/xz plane </param> public BezierPath(IEnumerable <Vector3> anchorPoints, bool isClosed = false, PathSpace space = PathSpace.xyz) { Vector3[] pointsArray = anchorPoints.ToArray(); if (pointsArray.Length < 2) { Debug.LogError("Path requires at least 2 anchor points."); } else { controlMode = ControlMode.Automatic; this.points = new List <Vector3> { pointsArray[0], Vector3.zero, Vector3.zero, pointsArray[1] }; perAnchorNormalsAngle = new List <float> (new float[] { 0, 0 }); for (int i = 2; i < pointsArray.Length; i++) { AddSegmentToEnd(pointsArray[i]); perAnchorNormalsAngle.Add(0); } } this.Space = space; this.IsClosed = isClosed; }
static void ConstrainPosRot(ref Vector3 pos, ref Quaternion rot, PathSpace space) { Vector3 eulerAngles; switch (space) { case PathSpace.xy: eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.y != 0) { rot = Quaternion.AngleAxis(eulerAngles.z, Vector3.forward); } pos = new Vector3(pos.x, pos.y, 0); break; case PathSpace.xz: eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.z != 0) { rot = Quaternion.AngleAxis(eulerAngles.y, Vector3.up); } pos = new Vector3(pos.x, 0, pos.z); break; } }
// Transform vector from world to local space (affected by rotation, but not position or scale) public static Vector3 InverseTransformDirection(Vector3 p, Transform t, PathSpace space) { Quaternion constrainedRot = t.rotation; ConstrainRot(ref constrainedRot, space); return(Quaternion.Inverse(constrainedRot) * p); }
public static Vector3 TransformPoint(Vector3 p, Transform t, PathSpace space) { var lockedPoint = LockPointToSpace(p, space); var transformedPoint = t.TransformPoint(lockedPoint); return(transformedPoint); }
// Commented the local to world transformation because it is extremely slow to compute public static Vector3 TransformPoint(Vector3 p, Transform t, PathSpace space) { //var original = LockTransformToSpace (t, space); //Vector3 transformedPoint = t.TransformPoint (p); //original.SetTransform (t); return(p); // transformedPoint; }
public static void GetPath(List <Vector3> points, bool isClosed, PathSpace space, ref List <Vector3> results, float step) { results.Clear(); if (points.Count < 2) { Debug.LogError("Path requires at least 2 anchor points."); return; } var bezierPath = new BezierPath(points, isClosed, space); var vertexPath = new VertexPath(bezierPath, 0.3f, 0.01f); float length = vertexPath.length; float distance = 0; while (distance <= length) { Vector3 pos = vertexPath.GetPointAtDistance(distance, EndOfPathInstruction.Stop); results.Add(pos); distance += step; } }
/// <summary> Creates a two-anchor path centred around the given centre point </summary> ///<param name="isClosed"> Should the end point connect back to the start point? </param> ///<param name="space"> Determines if the path is in 3d space, or clamped to the xy/xz plane </param> public BezierPath(NodeNetCreator nodeNetCreator, int id, Vector3 centre, bool isClosed = false, PathSpace space = PathSpace.xz) { this.nodeNetCreator = nodeNetCreator; bezierPathId = id; Debug.Log("Constructed: " + id); Vector3 dir = (space == PathSpace.xz) ? Vector3.forward : Vector3.up; float width = 2; float controlHeight = .5f; float controlWidth = 1f; if (pointsRefs == null) { pointsRefs = new List <int>(); } CreatePoint(centre + Vector3.left * controlWidth + dir * controlHeight + localPosition); CreatePoint(centre + Vector3.left * controlWidth - dir * controlHeight + localPosition); CreatePoint(centre + Vector3.right * controlWidth - dir * controlHeight + localPosition); CreatePoint(centre + Vector3.right * width + localPosition); perAnchorNormalsAngle = new List <float>() { 0, 0 }; Space = space; IsClosed = isClosed; nodeNetCreator.OnPointDeleted += RetargetPointRefs; }
/// <summary> /// Determines mouse position in world. If PathSpace is xy/xz, the position will be locked to that plane. /// If PathSpace is xyz, then depthFor3DSpace will be used as distance from scene camera. /// </summary> public static Vector3 GetMouseWorldPosition(PathSpace space, float depthFor3DSpace = 10) { var mouseRay = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); var worldMouse = mouseRay.GetPoint(depthFor3DSpace); // Mouse can only move on XY plane if (space == PathSpace.xy) { var zDir = mouseRay.direction.z; if (zDir != 0) { var dstToXYPlane = Mathf.Abs(mouseRay.origin.z / zDir); worldMouse = mouseRay.GetPoint(dstToXYPlane); } } // Mouse can only move on XZ plane else if (space == PathSpace.xz) { var yDir = mouseRay.direction.y; if (yDir != 0) { var dstToXZPlane = Mathf.Abs(mouseRay.origin.y / yDir); worldMouse = mouseRay.GetPoint(dstToXZPlane); } } return(worldMouse); }
/// Update point positions for new path space /// (for example, if changing from xy to xz path, y and z axes will be swapped so the path keeps its shape in the new space) void UpdateToNewPathSpace(PathSpace previousSpace) { // If changing from 3d to 2d space, first find the bounds of the 3d path. // The axis with the smallest bounds will be discarded. if (previousSpace == PathSpace.Xyz) { var boundsSize = this.PathBounds.size; var minBoundsSize = Mathf.Min(boundsSize.x, boundsSize.y, boundsSize.z); for (var i = 0; i < this.NumPoints; i++) { if (this.space == PathSpace.Xy) { this.localPosition = new Vector3(this.localPosition.x, this.localPosition.y, 0); var x = (minBoundsSize == boundsSize.x) ? this.points[i].z : this.points[i].x; var y = (minBoundsSize == boundsSize.y) ? this.points[i].z : this.points[i].y; this.points[i] = new Vector3(x, y, 0); } else if (this.space == PathSpace.Xz) { this.localPosition = new Vector3(this.localPosition.x, 0, this.localPosition.z); var x = (minBoundsSize == boundsSize.x) ? this.points[i].y : this.points[i].x; var z = (minBoundsSize == boundsSize.z) ? this.points[i].y : this.points[i].z; this.points[i] = new Vector3(x, 0, z); } } } else { // Nothing needs to change when going to 3d space if (this.space != PathSpace.Xyz) { for (var i = 0; i < this.NumPoints; i++) { // from xz to xy if (this.space == PathSpace.Xy) { this.localPosition = new Vector3(this.localPosition.x, this.localPosition.z); this.points[i] = new Vector3(this.points[i].x, this.points[i].z, 0); } // from xy to xz else if (this.space == PathSpace.Xz) { this.localPosition = new Vector3(this.localPosition.x, 0, this.localPosition.y); this.points[i] = new Vector3(this.points[i].x, 0, this.points[i].y); } } } } if (this.space != PathSpace.Xyz) { var axis = (this.space == PathSpace.Xy) ? Vector3.forward : Vector3.up; var angle = (this.space == PathSpace.Xy) ? this.rotation.eulerAngles.z : this.rotation.eulerAngles.y; this.rotation = Quaternion.AngleAxis(angle, axis); } this.NotifyPathModified(); }
/// Update point positions for new path space /// (for example, if changing from xy to xz path, y and z axes will be swapped so the path keeps its shape in the new space) void UpdateToNewPathSpace(PathSpace previousSpace) { // If changing from 3d to 2d space, first find the bounds of the 3d path. // The axis with the smallest bounds will be discarded. if (previousSpace == PathSpace.xyz) { Vector3 boundsSize = PathBounds.size; float minBoundsSize = Mathf.Min(boundsSize.x, boundsSize.y, boundsSize.z); for (int i = 0; i < NumPoints; i++) { if (space == PathSpace.xy) { localPosition = new Vector3(localPosition.x, localPosition.y, 0); float x = (minBoundsSize == boundsSize.x) ? points[i].z : points[i].x; float y = (minBoundsSize == boundsSize.y) ? points[i].z : points[i].y; points[i] = new Vector3(x, y, 0); } else if (space == PathSpace.xz) { localPosition = new Vector3(localPosition.x, 0, localPosition.z); float x = (minBoundsSize == boundsSize.x) ? points[i].y : points[i].x; float z = (minBoundsSize == boundsSize.z) ? points[i].y : points[i].z; points[i] = new Vector3(x, 0, z); } } } else { // Nothing needs to change when going to 3d space if (space != PathSpace.xyz) { for (int i = 0; i < NumPoints; i++) { // from xz to xy if (space == PathSpace.xy) { localPosition = new Vector3(localPosition.x, localPosition.z); points[i] = new Vector3(points[i].x, points[i].z, 0); } // from xy to xz else if (space == PathSpace.xz) { localPosition = new Vector3(localPosition.x, 0, localPosition.y); points[i] = new Vector3(points[i].x, 0, points[i].y); } } } } if (space != PathSpace.xyz) { Vector3 axis = (space == PathSpace.xy) ? Vector3.forward : Vector3.up; float angle = (space == PathSpace.xy) ? rotation.eulerAngles.z : rotation.eulerAngles.y; rotation = Quaternion.AngleAxis(angle, axis); } NotifyPathModified(); }
public static Vector3 TransformVector(Vector3 p, Transform t, PathSpace space) { var original = LockTransformToSpace(t, space); Vector3 transformedPoint = t.TransformVector(p); original.SetTransform(t); return(transformedPoint); }
public static Vector3 InverseTransformDirection(Vector3 p, Transform t, PathSpace space) { var original = LockTransformToSpace(t, space); Vector3 transformedPoint = t.InverseTransformDirection(p); original.SetTransform(t); return(transformedPoint); }
// Transform vector from local to world space (affected by rotation and scale, but not position) public static Vector3 TransformVector(Vector3 p, Transform t, PathSpace space) { // path only works correctly for uniform scales, so average out xyz global scale float scale = Vector3.Dot(t.lossyScale, Vector3.one) / 3; Quaternion constrainedRot = t.rotation; ConstrainRot(ref constrainedRot, space); return(constrainedRot * p * scale); }
public RoadObject(List <Vector3> _points, List <float> roadMaxAngles, bool _isClosed, PathSpace _space, BezierPath.ControlMode _mode, float _roadWidth) { this.points = _points; this.isClosed = _isClosed; this.space = _space; this.mode = _mode; this.roadWidth = _roadWidth; this.roadMaxAngles = roadMaxAngles; gameObject = new GameObject("Road"); CreatorInitialize(); }
static Vector3 LockPointToSpace(Vector3 p, PathSpace space) { if (space == PathSpace.xy) { return(new Vector3(p.x, p.y, 0)); } if (space == PathSpace.xz) { return(new Vector3(p.x, 0, p.z)); } return(p); }
// Transform point from world to local space public static Vector3 InverseTransformPoint(Vector3 p, Transform t, PathSpace space) { Vector3 constrainedPos = t.position; Quaternion constrainedRot = t.rotation; ConstrainPosRot(ref constrainedPos, ref constrainedRot, space); // path only works correctly for uniform scales, so average out xyz global scale float scale = Vector3.Dot(t.lossyScale, Vector3.one) / 3; var offset = p - constrainedPos; return(Quaternion.Inverse(constrainedRot) * offset / scale); }
//bool shiftLastFrame; //bool hasUpdatedScreenSpaceLine; //bool hasUpdatedNormalsVertexPath; //bool editingNormalsOld; //Vector3 transformPos; //Vector3 transformScale; //Quaternion transformRot; //Color handlesStartCol; //// Constants //const int bezierPathTab = 0; //const int vertexPathTab = 1; //#endregion //#region Inspectors public override void OnInspectorGUI() { showPerSegmentBounds = GUILayout.Toggle(showPerSegmentBounds, new GUIContent("Show Segment Bounds")); displayAnchorPoints = GUILayout.Toggle(displayAnchorPoints, new GUIContent("Show Anchor Points")); visibleBehindObjects = GUILayout.Toggle(visibleBehindObjects, new GUIContent("Visible behind objects")); pathSpace = (PathSpace)EditorGUILayout.EnumPopup("Restrict PathSpace:", pathSpace); handleRadius = EditorGUILayout.FloatField(handleRadius); if (GUILayout.Button("Publish Graph")) { ((Graph)target).Publish(); } base.OnInspectorGUI(); }
/// Update point positions for new path space /// (for example, if changing from xy to xz path, y and z axes will be swapped so the path keeps its shape in the new space) void UpdateToNewPathSpace(PathSpace previousSpace) { // If changing from 3d to 2d space, first find the bounds of the 3d path. // The axis with the smallest bounds will be discarded. if (previousSpace == PathSpace.xyz) { Vector3 boundsSize = PathBounds.size; float minBoundsSize = Mathf.Min(boundsSize.x, boundsSize.y, boundsSize.z); for (int i = 0; i < NumPoints; i++) { if (space == PathSpace.xy) { float x = (minBoundsSize == boundsSize.x) ? points[i].z : points[i].x; float y = (minBoundsSize == boundsSize.y) ? points[i].z : points[i].y; points[i] = new Vector3(x, y, 0); } else if (space == PathSpace.xz) { float x = (minBoundsSize == boundsSize.x) ? points[i].y : points[i].x; float z = (minBoundsSize == boundsSize.z) ? points[i].y : points[i].z; points[i] = new Vector3(x, 0, z); } } } else { // Nothing needs to change when going to 3d space if (space == PathSpace.xyz) { return; } for (int i = 0; i < NumPoints; i++) { // from xz to xy if (space == PathSpace.xy) { points[i] = new Vector3(points[i].x, points[i].z, 0); } // from xy to xz else if (space == PathSpace.xz) { points[i] = new Vector3(points[i].x, 0, points[i].y); } } } NotifyPathModified(); }
void CreateBezier(Vector3 centre, bool defaultIs2D = false) { if (_bezierPath != null) { _bezierPath.OnModified -= BezierPathEdited; } PathSpace space = defaultIs2D ? PathSpace.xy : PathSpace.xyz; _bezierPath = new BezierPath(centre, false, space); _bezierPath.OnModified += BezierPathEdited; vertexPathUpToDate = false; bezierOrVertexPathModified?.Invoke(); bezierCreated?.Invoke(); }
static void ConstrainRot(ref Quaternion rot, PathSpace space) { if (space == PathSpace.xy) { var eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.y != 0) { rot = Quaternion.AngleAxis(eulerAngles.z, Vector3.forward); } } else if (space == PathSpace.xz) { var eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.z != 0) { rot = Quaternion.AngleAxis(eulerAngles.y, Vector3.up); } } }
/// <summary> /// Rebuilds the path with the newly generated points. /// </summary> protected virtual void RebuildPath() { space = is3D ? PathSpace.xyz : PathSpace.xy; if (generatedPoints == null || generatedPoints.Count == 0) { pathCreator.bezierPath = new BezierPath(pathPoints, false, space); //err.. why new? why not return here? } else { foreach (Vector3 p in generatedPoints) { pathCreator.bezierPath.AddSegmentToEnd(p); pathPoints.Add(p); } } pathCreator.bezierPath.ControlPointMode = BezierPath.ControlMode.Mirrored; BuildCollider(); generatedPoints.Clear(); }
/// <summary> Creates a two-anchor path centred around the given centre point </summary> /// <param name="isClosed"> Should the end point connect back to the start point? </param> /// <param name="space"> Determines if the path is in 3d space, or clamped to the xy/xz plane </param> public BezierPath(Vector3 centre, bool isClosed = false, PathSpace space = PathSpace.xyz) { var dir = space == PathSpace.xz ? Vector3.forward : Vector3.up; float width = 2; var controlHeight = .5f; var controlWidth = 1f; points = new List <Vector3> { centre + Vector3.left * width, centre + Vector3.left * controlWidth + dir * controlHeight, centre + Vector3.right * controlWidth - dir * controlHeight, centre + Vector3.right * width }; perAnchorNormalsAngle = new List <float> { 0, 0 }; Space = space; IsClosed = isClosed; }
static PosRotScale LockTransformToSpace(Transform t, PathSpace space) { var original = new PosRotScale(t); if (space == PathSpace.xy) { t.eulerAngles = new Vector3(0, 0, t.eulerAngles.z); //t.position = new Vector3 (t.position.x, t.position.y, 0); } else if (space == PathSpace.xz) { t.eulerAngles = new Vector3(0, t.eulerAngles.y, 0); //t.position = new Vector3 (t.position.x, 0, t.position.z); } //float maxScale = Mathf.Max (t.localScale.x * t.parent.localScale.x, t.localScale.y * t.parent.localScale.y, t.localScale.z * t.parent.localScale.z); float maxScale = Mathf.Max(t.lossyScale.x, t.lossyScale.y, t.lossyScale.z); t.localScale = Vector3.one * maxScale; return(original); }
static void ConstrainPosRot(ref Vector3 pos, ref Quaternion rot, PathSpace space) { if (space == PathSpace.xy) { var eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.y != 0) { rot = Quaternion.AngleAxis(eulerAngles.z, Vector3.forward); } pos = new Vector3(pos.x, pos.y, 0); } else if (space == PathSpace.xz) { var eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.z != 0) { rot = Quaternion.AngleAxis(eulerAngles.y, Vector3.up); } pos = new Vector3(pos.x, 0, pos.z); } }
// Configuration void SetupCarEnvConfiguration() { EnvironmentParameters parameters = Academy.Instance.EnvironmentParameters; // Random Anchors & BezierPath Parameters num_anchors = (int)parameters.GetWithDefault("num_anchors", 10.0f); radius_anchor_circle = parameters.GetWithDefault("radius_anchor_circle", 8.0f); radius_epsilon_ratio = parameters.GetWithDefault("radius_epsilon_ratio", 0.7f); theta_epsilon_ratio = parameters.GetWithDefault("theta_epsilon_ratio", 0.7f); max_anchor_height = parameters.GetWithDefault("max_anchor_height", 3.0f); max_anchor_angle = parameters.GetWithDefault("max_anchor_angle", 15.0f); path_space = (PathSpace)parameters.GetWithDefault("path_space", (float)PathSpace.xz); road_width = parameters.GetWithDefault("road_width", 1.0f); // Agent Setting agent_mass = parameters.GetWithDefault("agent_mass", 1.0f); force_multiplier = parameters.GetWithDefault("force_multiplier", 10.0f); ticker_start = (int)parameters.GetWithDefault("ticker_start", -3.0f); ticker_end = (int)parameters.GetWithDefault("ticker_end", 5.0f); ticker_space = parameters.GetWithDefault("ticker_space", 0.0f); running_penalty = parameters.GetWithDefault("running_penalty", -5.0f); failure_penalty = parameters.GetWithDefault("failure_penalty", -100.0f); // Friction Accident Event Parameters enableFrictionAccident = (parameters.GetWithDefault("enableFrictionAccident", 0.0f) > 0.0f); frictionchanged_time = parameters.GetWithDefault("frictionchanged_time", 3.0f); static_friction = parameters.GetWithDefault("static_friction", 0.0f); dynamic_friction = parameters.GetWithDefault("dynamic_friction", 0.0f); // Wind Accident Event Parameters enableWindAccident = (parameters.GetWithDefault("enableWindAccident", 0.0f) > 0.0f); wind_time = parameters.GetWithDefault("wind_time", 3.0f); wind_force_X = parameters.GetWithDefault("wind_force_X", 0.0f); wind_force_Y = parameters.GetWithDefault("wind_force_Y", 0.0f); wind_force_Z = parameters.GetWithDefault("wind_force_Z", 0.0f); // Loss Control Accident Event Parameter enableLossControlAccident = (parameters.GetWithDefault("enableLossControlAccident", 0.0f) > 0.0f); lossctrl_time = parameters.GetWithDefault("lossctrl_time", 3.0f); lossctrl_Xaxis_ratio = parameters.GetWithDefault("lossctrl_Xaxis_ratio", 1.0f); lossctrl_Zaxis_ratio = parameters.GetWithDefault("lossctrl_Zaxis_ratio", 1.0f); }
/// <summary> Creates a path from the supplied 3D points </summary> ///<param name="points"> List or array of points to create the path from. </param> ///<param name="isClosed"> Should the end point connect back to the start point? </param> ///<param name="space"> Determines if the path is in 3d space, or clamped to the xy/xz plane </param> public BezierPath(NodeNetCreator nodeNetCreator, IEnumerable <Vector3> points, bool isClosed = false, PathSpace space = PathSpace.xz) { this.nodeNetCreator = nodeNetCreator; Vector3[] pointsArray = points.ToArray(); if (pointsArray.Length < 2) { Debug.LogError("Path requires at least 2 anchor points."); } else { controlMode = ControlMode.Automatic; if (pointsRefs == null) { pointsRefs = new List <int>(); } CreatePoint(pointsArray[0]); CreatePoint(Vector3.zero); CreatePoint(Vector3.zero); CreatePoint(pointsArray[1]); perAnchorNormalsAngle = new List <float>(new float[] { 0, 0 }); for (int i = 2; i < pointsArray.Length; i++) { AddSegmentToEnd(pointsArray[i]); perAnchorNormalsAngle.Add(0); } } Space = space; IsClosed = isClosed; nodeNetCreator.OnPointDeleted += RetargetPointRefs; }
static void ConstrainRot(ref Quaternion rot, PathSpace space) { Vector3 eulerAngles; switch (space) { case PathSpace.xy: eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.y != 0) { rot = Quaternion.AngleAxis(eulerAngles.z, Vector3.forward); } break; case PathSpace.xz: eulerAngles = rot.eulerAngles; if (eulerAngles.x != 0 || eulerAngles.z != 0) { rot = Quaternion.AngleAxis(eulerAngles.y, Vector3.up); } break; } }
/// <summary> Creates a path from the supplied 2D points </summary> ///<param name="points"> List or array of 2d points to create the path from. </param> ///<param name="isClosed"> Should the end point connect back to the start point? </param> ///<param name="pathSpace"> Determines if the path is in 3d space, or clamped to the xy/xz plane </param> public BezierPath(IEnumerable <Vector2> points, PathSpace space = PathSpace.xyz, bool isClosed = false) : this(points.Select(p => new Vector3(p.x, p.y)), isClosed, space) { }