Beispiel #1
0
        public static bool Intersect(CubeXCollider src, SphereXCollider dst, out XContact?contact)
        {
            // 反向旋转sphere的位置,使得可以在cube的坐标系下进行碰撞判断
            var extents = src.Size * 0.5f;
            var invQ    = Quaternion.Inverse(src.Quaternion);
            var invP    = invQ * (dst.Position - src.Position);

            // 以下所有操作都是在cube的坐标系下,随后的实际方向需要进行坐标系转换
            var n       = invP;
            var closest = n;

            closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x);
            closest.y = Mathf.Clamp(closest.y, -extents.y, extents.y);
            closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z);
            var inside = false;

            if (n == closest)
            {
                inside = true;
                var disX = extents.x - Mathf.Abs(n.x);
                var disY = extents.y - Mathf.Abs(n.y);
                var disZ = extents.z - Mathf.Abs(n.z);
                //找到最近的一个面
                if (disX < disY && disX < disZ)
                {
                    // 沿X轴
                    if (n.x > 0)
                    {
                        closest.x = extents.x;
                    }
                    else
                    {
                        closest.x = -extents.x;
                    }
                }
                else if (disY < disX && disY < disZ)
                {
                    // 沿Y轴
                    if (n.y > 0)
                    {
                        closest.y = extents.y;
                    }
                    else
                    {
                        closest.y = -extents.y;
                    }
                }
                else
                {
                    // 沿Z轴
                    if (n.z > 0)
                    {
                        closest.z = extents.z;
                    }
                    else
                    {
                        closest.z = -extents.z;
                    }
                }
            }
            var dir      = n - closest;
            var sqrDist  = dir.sqrMagnitude;
            var space    = dst.Radius;
            var sqrSpace = space * space;

            if (sqrDist < sqrSpace || inside)
            {
                var dist        = Mathf.Sqrt(sqrDist);
                var normal      = (src.Quaternion * dir).normalized;
                var penetration = space - dist;
                if (inside)
                {
                    normal      = -normal;
                    penetration = space + dist;
                }
                if (normal == Vector3.zero)
                {
                    normal = Vector3.up;
                }
                contact = new XContact(src, dst, normal, penetration);
                return(true);
            }
            contact = null;
            return(false);
        }
Beispiel #2
0
        public static bool Intersect(CubeXCollider src, CylinderXCollider dst, out XContact?contact)
        {
            var     invP = Quaternion.Inverse(src.Quaternion) * (dst.Position - src.Position);
            Vector3 n    = Vector3.zero;

            n.x = invP.x;
            n.z = invP.z;

            var extents = src.Size * 0.5f;
            var halfHa  = extents.y;
            var topA    = halfHa;
            var bottomA = -halfHa;
            var halfHb  = dst.Height * 0.5f;
            var topB    = invP.y + halfHb;
            var bottomB = invP.y - halfHb;

            var space    = dst.Radius;
            var sqrSpace = space * space;

            // 相撞时,俯视图下的圆和矩形必然相交
            var closest = n;

            closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x);
            closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z);

            if ((n - closest).sqrMagnitude > sqrSpace)
            {
                contact = null;
                return(false);
            }

            // 处理相交的情况
            Vector3 normal;
            float   penetration;
            float   verticalP = float.PositiveInfinity;
            float   horizontalP;

            var inside = false;

            if (n == closest)
            {
                inside = true;
                var disX = extents.x - Mathf.Abs(n.x);
                var disZ = extents.z - Mathf.Abs(n.z);
                //找到最近的一个面
                if (disX < disZ)
                {
                    // 沿X轴
                    if (n.x > 0)
                    {
                        closest.x = extents.x;
                    }
                    else
                    {
                        closest.x = -extents.x;
                    }
                }
                else
                {
                    // 沿Z轴
                    if (n.z > 0)
                    {
                        closest.z = extents.z;
                    }
                    else
                    {
                        closest.z = -extents.z;
                    }
                }
                horizontalP = space + (n - closest).magnitude;
            }
            else
            {
                horizontalP = space - (n - closest).magnitude;
            }

            if (Mathf.Sign(topA - topB) != Mathf.Sign(bottomB - bottomA))
            {
                // 斜向相撞
                if (topB > topA)
                {
                    verticalP = topA - bottomB;
                }
                else
                {
                    verticalP = topB - bottomA;
                }
            }

            if (horizontalP < verticalP)
            {
                normal = (src.Quaternion * (n - closest)).normalized;
                if (inside)
                {
                    normal = -normal;
                }
                penetration = horizontalP;
            }
            else
            {
                normal      = topB > topA ? Vector3.up : Vector3.down;
                penetration = verticalP;
            }
            if (normal == Vector3.zero)
            {
                normal = Vector3.up;
            }
            contact = new XContact(src, dst, normal, penetration);
            return(true);
        }
Beispiel #3
0
            private void RenderUpcomingEvents()
            {
                string vessel_guid           = vessel_.id.ToString();
                double current_time          = plugin_.CurrentTime();
                bool   should_clear_guidance = true;

                for (int i = 0; i < burn_editors_.Count; ++i)
                {
                    NavigationManoeuvre manoeuvre =
                        plugin_.FlightPlanGetManoeuvre(vessel_guid, i);
                    if (manoeuvre.final_time > current_time)
                    {
                        if (manoeuvre.burn.initial_time > current_time)
                        {
                            UnityEngine.GUILayout.TextArea("Upcoming manœuvre: #" + (i + 1));
                            UnityEngine.GUILayout.Label(
                                "Ignition " + FormatTimeSpan(TimeSpan.FromSeconds(
                                                                 current_time - manoeuvre.burn.initial_time)));
                        }
                        else
                        {
                            UnityEngine.GUILayout.TextArea("Ongoing manœuvre: #" + (i + 1));
                            UnityEngine.GUILayout.Label(
                                "Cutoff " + FormatTimeSpan(TimeSpan.FromSeconds(
                                                               current_time - manoeuvre.final_time)));
                        }
                        show_guidance_ =
                            UnityEngine.GUILayout.Toggle(show_guidance_, "Show on navball");
                        if (show_guidance_ &&
                            !double.IsNaN(manoeuvre.inertial_direction.x +
                                          manoeuvre.inertial_direction.y +
                                          manoeuvre.inertial_direction.z))
                        {
                            if (guidance_node_ == null)
                            {
                                guidance_node_ = vessel_.patchedConicSolver.AddManeuverNode(
                                    manoeuvre.burn.initial_time);
                            }
                            Vector3d stock_velocity_at_node_time =
                                vessel_.orbit.getOrbitalVelocityAtUT(
                                    manoeuvre.burn.initial_time).xzy;
                            Vector3d stock_displacement_from_parent_at_node_time =
                                vessel_.orbit.getRelativePositionAtUT(
                                    manoeuvre.burn.initial_time).xzy;
                            UnityEngine.Quaternion stock_frenet_frame_to_world =
                                UnityEngine.Quaternion.LookRotation(
                                    stock_velocity_at_node_time,
                                    Vector3d.Cross(stock_velocity_at_node_time,
                                                   stock_displacement_from_parent_at_node_time));
                            guidance_node_.OnGizmoUpdated(
                                ((Vector3d)manoeuvre.burn.delta_v).magnitude *
                                (Vector3d)(stock_frenet_frame_to_world.Inverse() *
                                           (Vector3d)manoeuvre.inertial_direction),
                                manoeuvre.burn.initial_time);
                            should_clear_guidance = false;
                        }
                        break;
                    }
                }
                if (should_clear_guidance && guidance_node_ != null)
                {
                    vessel_.patchedConicSolver.RemoveManeuverNode(guidance_node_);
                    guidance_node_ = null;
                }
            }
Beispiel #4
0
 static Matrix4x4 ToMatrix(Vector3 position, Quaternion rotation, Vector2 scale)
 {
     return(Matrix4x4.TRS(position, Quaternion.Inverse(rotation), new Vector3(scale.x, scale.y, -1)));
 }
Beispiel #5
0
        public static bool GenerateExtrudedShapeAsset(CSGBrushMeshAsset brushMeshAsset, Curve2D shape, Path path, int curveSegments, CSGSurfaceAsset[] surfaceAssets, ref SurfaceDescription[] surfaceDescriptions)
        {
            var shapeVertices       = new List <Vector2>();
            var shapeSegmentIndices = new List <int>();

            GetPathVertices(shape, curveSegments, shapeVertices, shapeSegmentIndices);

            Vector2[][] polygonVerticesArray;
            int[][]     polygonIndicesArray;

            if (!Decomposition.ConvexPartition(shapeVertices, shapeSegmentIndices,
                                               out polygonVerticesArray,
                                               out polygonIndicesArray))
            {
                return(false);
            }

            // TODO: make each extruded quad split into two triangles when it's not a perfect plane,
            //			split it to make sure it's convex

            // TODO: make it possible to smooth (parts) of the shape

            // TODO: make materials work well
            // TODO: make it possible to 'draw' shapes on any surface

            // TODO: make path work as a spline, with subdivisions
            // TODO:	make this work well with twisted rotations
            // TODO: make shape/path subdivisions be configurable / automatic



            var subMeshes = new List <CSGBrushSubMesh>();

            for (int p = 0; p < polygonVerticesArray.Length; p++)
            {
                var polygonVertices = polygonVerticesArray[p];
                var segmentIndices  = polygonIndicesArray[p];
                var shapeSegments   = polygonVertices.Length;

                for (int s = 0; s < path.segments.Length - 1; s++)
                {
                    var pathPointA       = path.segments[s];
                    var pathPointB       = path.segments[s + 1];
                    int subSegments      = 1;
                    var offsetQuaternion = pathPointB.rotation * Quaternion.Inverse(pathPointA.rotation);
                    var offsetEuler      = offsetQuaternion.eulerAngles;
                    if (offsetEuler.x > 180)
                    {
                        offsetEuler.x = 360 - offsetEuler.x;
                    }
                    if (offsetEuler.y > 180)
                    {
                        offsetEuler.y = 360 - offsetEuler.y;
                    }
                    if (offsetEuler.z > 180)
                    {
                        offsetEuler.z = 360 - offsetEuler.z;
                    }
                    var maxAngle = Mathf.Max(offsetEuler.x, offsetEuler.y, offsetEuler.z);
                    if (maxAngle != 0)
                    {
                        subSegments = Mathf.Max(1, (int)Mathf.Ceil(maxAngle / 5));
                    }

                    if ((pathPointA.scale.x / pathPointA.scale.y) != (pathPointB.scale.x / pathPointB.scale.y) &&
                        (subSegments & 1) == 1)
                    {
                        subSegments += 1;
                    }

                    for (int n = 0; n < subSegments; n++)
                    {
                        var matrix0 = PathPoint.Lerp(ref path.segments[s], ref path.segments[s + 1], n / (float)subSegments);
                        var matrix1 = PathPoint.Lerp(ref path.segments[s], ref path.segments[s + 1], (n + 1) / (float)subSegments);

                        // TODO: this doesn't work if top and bottom polygons intersect
                        //			=> need to split into two brushes then, invert one of the two brushes
                        var invertDot = Vector3.Dot(matrix0.MultiplyVector(Vector3.forward).normalized, (matrix1.MultiplyPoint(shapeVertices[0]) - matrix0.MultiplyPoint(shapeVertices[0])).normalized);

                        if (invertDot == 0.0f)
                        {
                            continue;
                        }

                        Vector3[] vertices;
                        if (invertDot < 0)
                        {
                            var m = matrix0; matrix0 = matrix1; matrix1 = m;
                        }
                        if (!GetExtrudedVertices(polygonVertices, matrix0, matrix1, out vertices))
                        {
                            continue;
                        }

                        var subMesh = new CSGBrushSubMesh();
                        CreateExtrudedSubMesh(subMesh, shapeSegments, segmentIndices, 0, 1, vertices, surfaceAssets, surfaceDescriptions);
                        subMeshes.Add(subMesh);
                    }
                }
            }

            brushMeshAsset.SubMeshes = subMeshes.ToArray();
            brushMeshAsset.CalculatePlanes();
            brushMeshAsset.OnValidate();
            brushMeshAsset.SetDirty();
            return(true);
        }