Exemple #1
0
        public static NQuaternion GetDeltaQuaternionWithDirectionVectors(NVector3 a, NVector3 b)
        {
            var dot = NVector3.Dot(a, b);

            if (dot < -0.999999)
            {
                var cross = NVector3.Cross(a, b);
                if (cross.Length() < 0.000001)
                {
                    cross = NVector3.Cross(NVector3.UnitY, a);
                }
                cross = NVector3.Normalize(cross);
                return(NQuaternion.CreateFromAxisAngle(cross, Pi));
            }
            else if (dot > 0.999999)
            {
                return(new NQuaternion(0, 0, 0, 1));
            }
            else
            {
                var xyz = NVector3.Cross(a, b);
                var w   = (float)(Math.Sqrt(a.Length() * a.Length() + b.Length() * b.Length()) + dot);
                return(new NQuaternion(xyz.X, xyz.Y, xyz.Z, w));
            }
        }
Exemple #2
0
 public Plane(Vector3 position, Vector3 normal, JsonMaterial material)
 {
     Position      = position;
     Scale         = new Vector3(1000f, 1000f, 1000f);
     this.normal   = Vector3.Normalize(normal);
     this.material = material;
 }
Exemple #3
0
        /// <summary>
        /// Sets up the joint transforms by automatically creating perpendicular vectors to complete the bases.
        /// </summary>
        /// <param name="worldTwistAxisA">Twist axis in world space to attach to entity A.</param>
        /// <param name="worldTwistAxisB">Twist axis in world space to attach to entity B.</param>
        public void SetupJointTransforms(System.Numerics.Vector3 worldTwistAxisA, System.Numerics.Vector3 worldTwistAxisB)
        {
            worldTwistAxisA.Normalize();
            worldTwistAxisB.Normalize();

            System.Numerics.Vector3 worldXAxis;
            Vector3Ex.Cross(ref worldTwistAxisA, ref Toolbox.UpVector, out worldXAxis);
            float length = worldXAxis.LengthSquared();

            if (length < Toolbox.Epsilon)
            {
                Vector3Ex.Cross(ref worldTwistAxisA, ref Toolbox.RightVector, out worldXAxis);
            }
            worldXAxis.Normalize();

            //Complete A's basis.
            System.Numerics.Vector3 worldYAxis;
            Vector3Ex.Cross(ref worldTwistAxisA, ref worldXAxis, out worldYAxis);

            basisA.rotationMatrix = connectionA.orientationMatrix;
            basisA.SetWorldAxes(worldTwistAxisA, worldXAxis, worldYAxis);

            //Rotate the axis to B since it could be arbitrarily rotated.
            System.Numerics.Quaternion rotation;
            QuaternionEx.GetQuaternionBetweenNormalizedVectors(ref worldTwistAxisA, ref worldTwistAxisB, out rotation);
            QuaternionEx.Transform(ref worldXAxis, ref rotation, out worldXAxis);

            basisB.rotationMatrix = connectionB.orientationMatrix;
            basisB.SetWorldAxes(worldTwistAxisB, worldXAxis);
        }
Exemple #4
0
        public override Vector3 Extrude(Vector3 point)
        {
            var     center = Body.CenterOfMassPosition;
            Vector3 vec    = point - new Vector3(center.X, center.Y, center.Z);

            return(Vector3.Normalize(vec) * _radius - vec);
        }
Exemple #5
0
 public Disc(Vector3 position, Vector3 normal, float radius, JsonMaterial material)
 {
     Position      = position;
     Scale         = new Vector3(radius);
     this.normal   = Vector3.Normalize(normal);
     this.material = material;
 }
Exemple #6
0
        public override void Redraw(float currentTime, float elapsedTime)
        {
            // selected vehicle (user can mouse click to select another)
            IVehicle selected = Demo.SelectedVehicle;

            // vehicle nearest mouse (to be highlighted)
            IVehicle nearMouse = Demo.VehicleNearestToMouse();

            // update camera
            Demo.UpdateCamera(elapsedTime, selected);

            // draw "ground plane" centered between base and selected vehicle
            Vector3 goalOffset    = Globals.HomeBaseCenter - Demo.Camera.Position;
            Vector3 goalDirection = Vector3.Normalize(goalOffset);
            Vector3 cameraForward = Demo.Camera.xxxls().Forward;
            float   goalDot       = Vector3.Dot(cameraForward, goalDirection);
            float   blend         = Utilities.RemapIntervalClip(goalDot, 1, 0, 0.5f, 0);
            Vector3 gridCenter    = Vector3.Lerp(selected.Position, Globals.HomeBaseCenter, blend);

            Demo.GridUtility(gridCenter);

            // draw the seeker, obstacles and home base
            CtfSeeker.Draw();
            DrawObstacles();
            DrawHomeBase();

            // draw each enemy
            foreach (CtfEnemy enemy in CtfEnemies)
            {
                enemy.Draw();
            }

            // highlight vehicle nearest mouse
            Demo.HighlightVehicleUtility(nearMouse);
        }
 public XYZ GetNormal(XYZ position)
 {
     if (!_WeightedNormals.TryGetValue(position, out XYZ normal))
     {
         normal = position;
     }
     return(normal == XYZ.Zero ? XYZ.UnitX : XYZ.Normalize(normal));
 }
Exemple #8
0
        public void LoadScene(JsonScene scene)
        {
            currentScene = scene;

            editorObjects.Clear();

            foreach (JsonGeometry geometry in scene.Geometry)
            {
                JsonMaterial material = scene.Materials.SingleOrDefault(m => m.ID == geometry.Material);
                switch (geometry.Type)
                {
                case "plane":
                {
                    editorObjects.Add(new Plane(geometry.Position, geometry.Normal, material));
                    break;
                }

                case "sphere":
                {
                    editorObjects.Add(new Sphere(geometry.Position, geometry.Radius, material));
                    break;
                }

                case "disc":
                {
                    editorObjects.Add(new Disc(geometry.Position, geometry.Normal, geometry.Radius, material));
                    break;
                }
                }
            }

            foreach (JsonLight light in scene.Lights)
            {
                switch (light.Type)
                {
                case "disc":
                {
                    editorObjects.Add(new Disc(light.Position, light.Normal, light.Radius, new JsonMaterial()
                        {
                            Emission = new JsonEmissionSettings()
                            {
                                Color      = light.Color,
                                Brightness = light.Brightness
                            }
                        }));
                    lightPosition  = new Vector4(light.Position.X, light.Position.Y, light.Position.Z, light.Radius);
                    lightDirection = Vector3.Normalize(light.Normal);
                    lightColor     = new Vector4(light.Color.X, light.Color.Y, light.Color.Z, light.Brightness);
                    break;
                }
                }
            }

            if (initialized)
            {
                editorObjects.ForEach(o => o.Initialize());
            }
        }
Exemple #9
0
 /// <summary>
 /// 获取光线追踪辐照度
 /// </summary>
 /// <param name="ray">光线</param>
 /// <param name="deep">当前追踪深度</param>
 /// <returns>颜色,追踪距离</returns>
 public (Light, float) Light(Ray ray, int deep, RenderObject callerObj, RenderObject ignore = null)
 {
     if (deep < 0 || Objects == null || Objects.Count == 0)
     {
         return(Core.Light.Dark, 0.0f);
     }
     ray = new Ray(ray.Origin, Vector3.Normalize(ray.Direction));
     float        minDistance = float.NaN;
     Vector3      point = default, normal = default;
Exemple #10
0
        public override RayCastResult Intersection(Ray ray, float nowbest)
        {
            {
                float distance = (Position - ray.Origin).Length();
                if (nowbest + R < distance)
                {
                    return(null);
                }
            }
            Vector3f A = ray.Origin, B = ray.Direction, C = Position;
            Float    a = Vector3f.Dot(B, B);
            Float    b = Vector3f.Dot(B, (A - C)) * 2.0f;
            Float    c = (A - C).LengthSquared() - R * R;

            float drt = b * b - 4 * a * c;

            if (drt < 0)
            {
                return(null);
            }
            drt = Math.Sqrt(drt);
            float x1 = (-b + drt) / a / 2;
            float x2 = (-b - drt) / a / 2;

            if (x1 < 0 && x2 < 0)
            {
                return(null);
            }

            float d;

            if (x1 > 0 && x2 > 0)
            {
                d = Math.Max(x1, x2);
            }
            else if (x1 > 0)
            {
                d = x1;
            }
            else
            {
                d = x2;
            }

            RayCastResult result = new RayCastResult();

            //result.happened = true;
            result.obj      = this;
            result.material = Material;
            result.coords   = ray.Origin + ray.Direction * d;
            result.distance = d;
            result.normal   = Vector3f.Normalize(result.coords - Position);

            return(result);
        }
Exemple #11
0
 private void UpdateRestrictedAxes()
 {
     localConstrainedAxis1 = System.Numerics.Vector3.Cross(Vector3Ex.Up, localAxisA);
     if (localConstrainedAxis1.LengthSquared() < .001f)
     {
         localConstrainedAxis1 = System.Numerics.Vector3.Cross(Vector3Ex.Right, localAxisA);
     }
     localConstrainedAxis2 = System.Numerics.Vector3.Cross(localAxisA, localConstrainedAxis1);
     localConstrainedAxis1.Normalize();
     localConstrainedAxis2.Normalize();
 }
Exemple #12
0
        // draws a "wide line segment": a rectangle of the given width and color
        // whose mid-line connects two given endpoints
        public static void DrawXZWideLine(Vector3 startPoint, Vector3 endPoint, Color color, float width)
        {
            Vector3 offset = Vector3.Normalize(endPoint - startPoint);
            Vector3 perp   = _localSpace.LocalRotateForwardToSide(offset);
            Vector3 radius = perp * width / 2;

            Vector3 a = startPoint + radius;
            Vector3 b = endPoint + radius;
            Vector3 c = endPoint - radius;
            Vector3 d = startPoint - radius;

            iDrawQuadrangle(a, b, c, d, color);
        }
 private void FireMissile(Fighter launcher, Fighter target)
 {
     if (_missiles.Count(m => m.Target == target) < 3)
     {
         _missiles.Add(new Missile(_pd, target, Annotations)
         {
             Position = launcher.Position,
             Forward  = Vector3.Normalize(launcher.Forward * 0.9f + Vector3Helpers.RandomUnitVector() * 0.1f),
             Speed    = launcher.Speed,
             Color    = _team1.Contains(launcher) ? Color.Black : Color.White
         });
     }
 }
Exemple #14
0
        //--------------------------------OTHERS----------------------------------------//

        /**
         * Computes the distance from the line point to another point
         *
         * @param otherPoint the point to compute the distance from the line point. The point
         * is supposed to be on the same line.
         * @return points distance. If the point submitted is behind the direction, the
         * distance is negative
         */
        public double computePointToPointDistance(Point3d otherPoint)
        {
            //float distance = otherPoint.distance(point);
            float distance = Vector3d.Distance(otherPoint, point);

            Vector3d vec = Vector3d.Normalize(new Vector3d(otherPoint.X - point.X, otherPoint.Y - point.Y, otherPoint.Z - point.Z));

            if (Vector3d.Dot(vec, direction) < 0)
            {
                return(-distance);
            }
            else
            {
                return(distance);
            }
        }
Exemple #15
0
        /// <summary>
        /// 返回折射光方向和能量强度
        /// </summary>
        /// <param name="dir"></param>
        /// <param name="niOverNt"></param>
        /// <returns></returns>
        public static (float, Vector3) Refract(Vector3 dir, Vector3 normal, float niOverNt)
        {
            dir = -Vector3.Normalize(dir);
            float cosAlpha     = Vector3.Dot(dir, normal);
            float discriminant = 1.0f - niOverNt * niOverNt * (1.0f - cosAlpha * cosAlpha);

            if (discriminant > 0)
            {
                float   cosGamma = MathF.Sqrt(discriminant);
                Vector3 re       = ((normal * cosAlpha) - dir) * niOverNt - normal * cosGamma;
                return(1.0f - Schlick(cosAlpha, niOverNt), re);
            }
            else
            {
                return(float.NegativeInfinity, Vector3.Zero);
            }
        }
Exemple #16
0
        /**
         * Gets the face normal
         *
         * @return face normal
         */
        public Vector3d getNormal()
        {
            Point3d  p1 = v1.getPosition();
            Point3d  p2 = v2.getPosition();
            Point3d  p3 = v3.getPosition();
            Vector3d xy, xz, normal;

            xy = new Vector3d(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
            xz = new Vector3d(p3.X - p1.X, p3.Y - p1.Y, p3.Z - p1.Z);

            /*normal = new Vector3d();
             * normal.cross(xy, xz);
             * normal.normalize();*/

            normal = Vector3d.Normalize(Vector3d.Cross(xy, xz));

            return(normal);
        }
Exemple #17
0
        private static IFlowField GenerateFlowField()
        {
            var f = new SimpleFlowField(50, 1, 50, new Vector3(25, 0.5f, 25));

            //Start random
            f.Randomize(1);

            //Swirl around center
            //Half the field is a swirl (basically just concentric circles) while the other half has a slight bias to spiral inwards towards the center
            f.Func(pos => Vector3.Lerp(pos / 5, Vector3.Normalize(Vector3.Cross(pos, Vector3.UnitY)), pos.X > 0.5f ? 0.75f : 0.9f), 0.85f);

            //Keep it flat on the plane
            f.ClampXZ();

            //Clean NaN values
            f.Clean();

            return(f);
        }
Exemple #18
0
        //----------------------------------CONSTRUCTORS---------------------------------//

        /**
         * Constructor for a line. The line created is the intersection between two planes
         *
         * @param face1 face representing one of the planes
         * @param face2 face representing one of the planes
         */
        public Line(Face face1, Face face2)
        {
            Vector3d normalFace1 = face1.getNormal();
            Vector3d normalFace2 = face2.getNormal();

            //direction: cross product of the faces normals
            //direction = new Vector3d();
            //direction.cross(normalFace1, normalFace2);

            direction = Vector3d.Cross(normalFace1, normalFace2);

            //if direction lenght is not zero (the planes aren't parallel )...
            if (!(direction.Length() < TOL))
            {
                //getting a line point, zero is set to a coordinate whose direction
                //component isn't zero (line intersecting its origin plan)
                point = new Point3d();
                float d1 = -(normalFace1.X * face1.v1.X + normalFace1.Y * face1.v1.Y + normalFace1.Z * face1.v1.Z);
                float d2 = -(normalFace2.X * face2.v1.X + normalFace2.Y * face2.v1.Y + normalFace2.Z * face2.v1.Z);
                if (Math.Abs(direction.X) > TOL)
                {
                    point.X = 0;
                    point.Y = (d2 * normalFace1.Z - d1 * normalFace2.Z) / direction.X;
                    point.Z = (d1 * normalFace2.Y - d2 * normalFace1.Y) / direction.X;
                }
                else if (Math.Abs(direction.Y) > TOL)
                {
                    point.X = (d1 * normalFace2.Z - d2 * normalFace1.Z) / direction.Y;
                    point.Y = 0;
                    point.Z = (d2 * normalFace1.X - d1 * normalFace2.X) / direction.Y;
                }
                else
                {
                    point.X = (d2 * normalFace1.Y - d1 * normalFace2.Y) / direction.Z;
                    point.Y = (d1 * normalFace2.X - d2 * normalFace1.X) / direction.Z;
                    point.Z = 0;
                }
            }

            direction = Vector3d.Normalize(direction);
        }
Exemple #19
0
            private readonly void DrawTriangle(int lod, XYZ a, XYZ b, XYZ c)
            {
                a = XYZ.Normalize(a);
                b = XYZ.Normalize(b);
                c = XYZ.Normalize(c);

                if (lod <= 0)
                {
                    Span <Point3> abc = stackalloc Point3[3];

                    if (_FaceFlip)
                    {
                        abc[2] = _Center + a * _Radius;
                        abc[1] = _Center + b * _Radius;
                        abc[0] = _Center + c * _Radius;
                    }
                    else
                    {
                        abc[0] = _Center + a * _Radius;
                        abc[1] = _Center + b * _Radius;
                        abc[2] = _Center + c * _Radius;
                    }

                    _Context.DrawConvexSurface(abc, _Color);

                    return;
                }

                --lod;

                var ab = (a + b) * 0.5f;
                var bc = (b + c) * 0.5f;
                var ca = (c + a) * 0.5f;

                DrawTriangle(lod, a, ab, ca);
                DrawTriangle(lod, ab, b, bc);
                DrawTriangle(lod, bc, c, ca);
                DrawTriangle(lod, ab, bc, ca);
            }
Exemple #20
0
        // called when steerToFollowPath decides steering is required
        public void AnnotatePathFollowing(Vector3 future, Vector3 onPath, Vector3 target, float outside)
        {
            Color yellow      = Color.Yellow;
            Color lightOrange = new Color((byte)(255.0f * 1.0f), (byte)(255.0f * 0.5f), 0);
            Color darkOrange  = new Color((byte)(255.0f * 0.6f), (byte)(255.0f * 0.3f), 0);

            // draw line from our position to our predicted future position
            annotation.Line(Position, future, yellow.ToVector3().FromXna());

            // draw line from our position to our steering target on the path
            annotation.Line(Position, target, Color.Orange.ToVector3().FromXna());

            // draw a two-toned line between the future test point and its
            // projection onto the path, the change from dark to light color
            // indicates the boundary of the tube.
            Vector3 boundaryOffset = Vector3.Normalize(onPath - future);

            boundaryOffset *= outside;
            Vector3 onPathBoundary = future + boundaryOffset;

            annotation.Line(onPath, onPathBoundary, darkOrange.ToVector3().FromXna());
            annotation.Line(onPathBoundary, future, lightOrange.ToVector3().FromXna());
        }
Exemple #21
0
        static TrigleFace[] Smooth(List <PW_Trigle> faces, List <Vector3f> v, List <Vector2f> vt, Dictionary <int, List <PW_Trigle> > faceList)
        {
            if (faces == null || faces.Count == 0)
            {
                return(null);
            }
            Dictionary <int, Vector3f> pointNormal = new Dictionary <int, Vector3f>();

            TrigleFace[] re = new TrigleFace[faces.Count];
            foreach (KeyValuePair <int, List <PW_Trigle> > kv in faceList)
            {
                Vector3f n = new Vector3f();
                foreach (PW_Trigle trigle in kv.Value)
                {
                    n += trigle.Normal;
                }
                n = Vector3f.Normalize(n);
                pointNormal[kv.Key] = n;
            }

            int idx = 0;

            foreach (PW_Trigle trigle in faces)
            {
                TrigleFace t = new TrigleFace(v[trigle.v0], v[trigle.v1], v[trigle.v2]);
                t.sp0 = vt[trigle.vt0];
                t.sp1 = vt[trigle.vt1];
                t.sp2 = vt[trigle.vt2];
                t.n0  = pointNormal[trigle.v0];
                t.n1  = pointNormal[trigle.v1];
                t.n2  = pointNormal[trigle.v2];

                re[idx] = t;
                idx++;
            }
            return(re);
        }
Exemple #22
0
        virtual public Transform Step(double time, LocationOptions options)
        {
            Clamp(options);


            var up = new Vector3(normal.x, normal.y, -normal.z);


            Vector3 east = new Vector3(local_orientation.v11, local_orientation.v21, local_orientation.v31);;
            Vector3 north;

            if (options.RotationOptions.HasFlag(RotationOptions.AlignToSurface))
            {
                east  = Vector3.Normalize(east - (Vector3.Dot(east, up) * up));
                north = Vector3.Cross(east, up);
            }
            else
            {
                north = new Vector3(-local_orientation.v12, -local_orientation.v22, -local_orientation.v32);
            }

            var m = new Matrix4x4(east.X, east.Y, east.Z, 0,
                                  up.X, up.Y, up.Z, 0,
                                  north.X, north.Y, north.Z, 0,
                                  0, 0, 0, 1);

            var qm = Quaternion.CreateFromRotationMatrix(m);

            var r = qm * Rotation;

            return(new Transform
            {
                Pos = { X = (float)position.x, Y = (float)position.y, Z = (float)position.z },
                Rot = r
            });
        }
Exemple #23
0
        public void AxisAngle_ToQuaternionConversion()
        {
            AxisAngle  aa;
            Quaternion q;

            Vector  v;
            SysVec  normV;
            SysQuat sq;

            double x, y, z, angle;
            bool   zero;

            // Test random quaternions
            for (var i = 0; i < 50; i++)
            {
                x     = Random(-100, 100);
                y     = Random(-100, 100);
                z     = Random(-100, 100);
                angle = Random(-720, 720);

                Trace.WriteLine("");
                Trace.WriteLine(x + " " + y + " " + z + " " + angle + " length: " + Geometry.Length(x, y, z));

                aa = new AxisAngle(x, y, z, angle);
                q  = aa.ToQuaternion();     // this method will normalize the Quaternion, as neccesary for spatial rotation representation
                Trace.WriteLine(aa);
                Trace.WriteLine(q);

                // TEST 1: compare to System.Numeric.Quaternion
                normV = new SysVec((float)x, (float)y, (float)z);
                normV = SysVec.Normalize(normV);
                sq    = SysQuat.CreateFromAxisAngle(normV, (float)(angle * Math.PI / 180.0)); // now this Quaternion SHOULD be normalized...
                Trace.WriteLine(sq + " length: " + sq.Length());

                Assert.AreEqual(q.W, sq.W, 0.000001, "Failed W");  // can't go very precise due to float imprecision in sys quat
                Assert.AreEqual(q.X, sq.X, 0.000001, "Failed X");
                Assert.AreEqual(q.Y, sq.Y, 0.000001, "Failed Y");
                Assert.AreEqual(q.Z, sq.Z, 0.000001, "Failed Z");
            }

            // Test all permutations of unitary components quaternions (including zero)
            for (x = -1; x <= 1; x++)
            {
                for (y = -1; y <= 1; y++)
                {
                    for (z = -1; z <= 1; z++)
                    {
                        for (angle = -720; angle <= 720; angle += 22.5)
                        {
                            Trace.WriteLine("");
                            Trace.WriteLine(x + " " + y + " " + z + " " + angle + " length: " + Geometry.Length(x, y, z));

                            // Normalize
                            v = new Vector(x, y, z);
                            v.Normalize();

                            aa = new AxisAngle(v, angle);
                            q  = aa.ToQuaternion();
                            Trace.WriteLine(aa);
                            Trace.WriteLine(q);

                            zero = aa.IsZero();

                            if (zero)
                            {
                                Assert.IsTrue(new Quaternion(1, 0, 0, 0).IsSimilar(q), "Failed zero quaternion");
                            }
                            else
                            {
                                // TEST 1: compare to System.Numeric.Quaternion
                                //sq = SysQuat.CreateFromAxisAngle(new Vector3((float)x, (float)y, (float)z), (float)(angle * Math.PI / 180.0));  // this Quaternion is not a versor (not unit)
                                normV = new SysVec((float)x, (float)y, (float)z);
                                normV = SysVec.Normalize(normV);
                                sq    = SysQuat.CreateFromAxisAngle(normV, (float)(angle * Math.PI / 180.0)); // now this Quaternion SHOULD be normalized...
                                Trace.WriteLine(sq + " length: " + sq.Length());

                                Assert.AreEqual(q.W, sq.W, 0.000001, "Failed W");  // can't go very precise due to float imprecision in sys quat
                                Assert.AreEqual(q.X, sq.X, 0.000001, "Failed X");
                                Assert.AreEqual(q.Y, sq.Y, 0.000001, "Failed Y");
                                Assert.AreEqual(q.Z, sq.Z, 0.000001, "Failed Z");
                            }
                        }
                    }
                }
            }
        }
Exemple #24
0
        internal void PreStep(float dt)
        {
            vehicleEntity    = wheel.Vehicle.Body;
            supportEntity    = wheel.SupportingEntity;
            supportIsDynamic = supportEntity != null && supportEntity.isDynamic;

            Vector3Ex.Cross(ref wheel.normal, ref wheel.slidingFriction.slidingFrictionAxis, out forceAxis);
            forceAxis.Normalize();
            //Do not need to check for normalize safety because normal and sliding friction axis must be perpendicular.

            linearAX = forceAxis.X;
            linearAY = forceAxis.Y;
            linearAZ = forceAxis.Z;

            //angular A = Ra x N
            angularAX = (wheel.ra.Y * linearAZ) - (wheel.ra.Z * linearAY);
            angularAY = (wheel.ra.Z * linearAX) - (wheel.ra.X * linearAZ);
            angularAZ = (wheel.ra.X * linearAY) - (wheel.ra.Y * linearAX);

            //Angular B = N x Rb
            angularBX = (linearAY * wheel.rb.Z) - (linearAZ * wheel.rb.Y);
            angularBY = (linearAZ * wheel.rb.X) - (linearAX * wheel.rb.Z);
            angularBZ = (linearAX * wheel.rb.Y) - (linearAY * wheel.rb.X);

            //Compute inverse effective mass matrix
            float entryA, entryB;

            //these are the transformed coordinates
            float tX, tY, tZ;

            if (vehicleEntity.isDynamic)
            {
                tX     = angularAX * vehicleEntity.inertiaTensorInverse.M11 + angularAY * vehicleEntity.inertiaTensorInverse.M21 + angularAZ * vehicleEntity.inertiaTensorInverse.M31;
                tY     = angularAX * vehicleEntity.inertiaTensorInverse.M12 + angularAY * vehicleEntity.inertiaTensorInverse.M22 + angularAZ * vehicleEntity.inertiaTensorInverse.M32;
                tZ     = angularAX * vehicleEntity.inertiaTensorInverse.M13 + angularAY * vehicleEntity.inertiaTensorInverse.M23 + angularAZ * vehicleEntity.inertiaTensorInverse.M33;
                entryA = tX * angularAX + tY * angularAY + tZ * angularAZ + vehicleEntity.inverseMass;
            }
            else
            {
                entryA = 0;
            }

            if (supportIsDynamic)
            {
                tX     = angularBX * supportEntity.inertiaTensorInverse.M11 + angularBY * supportEntity.inertiaTensorInverse.M21 + angularBZ * supportEntity.inertiaTensorInverse.M31;
                tY     = angularBX * supportEntity.inertiaTensorInverse.M12 + angularBY * supportEntity.inertiaTensorInverse.M22 + angularBZ * supportEntity.inertiaTensorInverse.M32;
                tZ     = angularBX * supportEntity.inertiaTensorInverse.M13 + angularBY * supportEntity.inertiaTensorInverse.M23 + angularBZ * supportEntity.inertiaTensorInverse.M33;
                entryB = tX * angularBX + tY * angularBY + tZ * angularBZ + supportEntity.inverseMass;
            }
            else
            {
                entryB = 0;
            }

            velocityToImpulse = -1 / (entryA + entryB); //Softness?

            currentFrictionCoefficient = gripFrictionBlender(gripFriction, wheel.supportMaterial.kineticFriction, true, wheel);

            //Compute the maximum force
            if (targetSpeed > 0)
            {
                maxMotorForceDt = maximumForwardForce * dt;
            }
            else
            {
                maxMotorForceDt = -maximumBackwardForce * dt;
            }
        }
Exemple #25
0
        internal void PreStep(float dt)
        {
            vehicleEntity    = wheel.Vehicle.Body;
            supportEntity    = wheel.SupportingEntity;
            supportIsDynamic = supportEntity != null && supportEntity.isDynamic;
            Vector3Ex.Cross(ref wheel.worldForwardDirection, ref wheel.normal, out slidingFrictionAxis);
            float axisLength = slidingFrictionAxis.LengthSquared();

            //Safety against bad cross product
            if (axisLength < Toolbox.BigEpsilon)
            {
                Vector3Ex.Cross(ref wheel.worldForwardDirection, ref Toolbox.UpVector, out slidingFrictionAxis);
                axisLength = slidingFrictionAxis.LengthSquared();
                if (axisLength < Toolbox.BigEpsilon)
                {
                    Vector3Ex.Cross(ref wheel.worldForwardDirection, ref Toolbox.RightVector, out slidingFrictionAxis);
                }
            }
            slidingFrictionAxis.Normalize();

            linearAX = slidingFrictionAxis.X;
            linearAY = slidingFrictionAxis.Y;
            linearAZ = slidingFrictionAxis.Z;

            //angular A = Ra x N
            angularAX = (wheel.ra.Y * linearAZ) - (wheel.ra.Z * linearAY);
            angularAY = (wheel.ra.Z * linearAX) - (wheel.ra.X * linearAZ);
            angularAZ = (wheel.ra.X * linearAY) - (wheel.ra.Y * linearAX);

            //Angular B = N x Rb
            angularBX = (linearAY * wheel.rb.Z) - (linearAZ * wheel.rb.Y);
            angularBY = (linearAZ * wheel.rb.X) - (linearAX * wheel.rb.Z);
            angularBZ = (linearAX * wheel.rb.Y) - (linearAY * wheel.rb.X);

            //Compute inverse effective mass matrix
            float entryA, entryB;

            //these are the transformed coordinates
            float tX, tY, tZ;

            if (vehicleEntity.isDynamic)
            {
                tX     = angularAX * vehicleEntity.inertiaTensorInverse.M11 + angularAY * vehicleEntity.inertiaTensorInverse.M21 + angularAZ * vehicleEntity.inertiaTensorInverse.M31;
                tY     = angularAX * vehicleEntity.inertiaTensorInverse.M12 + angularAY * vehicleEntity.inertiaTensorInverse.M22 + angularAZ * vehicleEntity.inertiaTensorInverse.M32;
                tZ     = angularAX * vehicleEntity.inertiaTensorInverse.M13 + angularAY * vehicleEntity.inertiaTensorInverse.M23 + angularAZ * vehicleEntity.inertiaTensorInverse.M33;
                entryA = tX * angularAX + tY * angularAY + tZ * angularAZ + vehicleEntity.inverseMass;
            }
            else
            {
                entryA = 0;
            }

            if (supportIsDynamic)
            {
                tX     = angularBX * supportEntity.inertiaTensorInverse.M11 + angularBY * supportEntity.inertiaTensorInverse.M21 + angularBZ * supportEntity.inertiaTensorInverse.M31;
                tY     = angularBX * supportEntity.inertiaTensorInverse.M12 + angularBY * supportEntity.inertiaTensorInverse.M22 + angularBZ * supportEntity.inertiaTensorInverse.M32;
                tZ     = angularBX * supportEntity.inertiaTensorInverse.M13 + angularBY * supportEntity.inertiaTensorInverse.M23 + angularBZ * supportEntity.inertiaTensorInverse.M33;
                entryB = tX * angularBX + tY * angularBY + tZ * angularBZ + supportEntity.inverseMass;
            }
            else
            {
                entryB = 0;
            }

            velocityToImpulse = -1 / (entryA + entryB); //Softness?

            //Compute friction.
            //Which coefficient? Check velocity.
            if (Math.Abs(RelativeVelocity) < staticFrictionVelocityThreshold)
            {
                blendedCoefficient = frictionBlender(staticCoefficient, wheel.supportMaterial.staticFriction, false, wheel);
            }
            else
            {
                blendedCoefficient = frictionBlender(kineticCoefficient, wheel.supportMaterial.kineticFriction, true, wheel);
            }
        }
 private void UpdateRestrictedAxes()
 {
     localRestrictedAxis1 = System.Numerics.Vector3.Cross(Vector3Ex.Up, localLineDirection);
     if (localRestrictedAxis1.LengthSquared() < .001f)
     {
         localRestrictedAxis1 = System.Numerics.Vector3.Cross(Vector3Ex.Right, localLineDirection);
     }
     localRestrictedAxis2 = System.Numerics.Vector3.Cross(localLineDirection, localRestrictedAxis1);
     localRestrictedAxis1.Normalize();
     localRestrictedAxis2.Normalize();
 }
Exemple #27
0
        bool TryToStepUsingContact(ref ContactData contact, ref System.Numerics.Vector3 down, out System.Numerics.Vector3 newPosition)
        {
            System.Numerics.Vector3 position = characterBody.Position;
            //The normal of the contact may not be facing perfectly out to the side.
            //The detection process allows a bit of slop.
            //Correct it by removing any component of the normal along the local up vector.
            System.Numerics.Vector3 normal = contact.Normal;
            float dot;

            Vector3Ex.Dot(ref normal, ref down, out dot);
            System.Numerics.Vector3 error;
            Vector3Ex.Multiply(ref down, dot, out error);
            Vector3Ex.Subtract(ref normal, ref error, out normal);
            normal.Normalize();

            //Now we need to ray cast out from the center of the character in the direction of this normal to check for obstructions.
            //Compute the ray origin location.  Fire it out of the top of the character; if we're stepping, this must be a valid location.
            //Putting it as high as possible helps to reject more invalid step geometry.
            Ray   ray;
            float downRayLength = characterBody.Height;// MaximumStepHeight + upStepMargin;

            Vector3Ex.Multiply(ref down, characterBody.Height * .5f - downRayLength, out ray.Position);
            Vector3Ex.Add(ref ray.Position, ref position, out ray.Position);
            ray.Direction = normal;
            //Include a little margin in the length.
            //Technically, the character only needs to teleport horizontally by the complicated commented expression.
            //That puts it just far enough to have traction on the new surface.
            //In practice, the current contact refreshing approach used for many pair types causes contacts to persist horizontally a bit,
            //which can cause side effects for the character.
            float horizontalOffsetAmount = characterBody.CollisionInformation.Shape.CollisionMargin; // (float)((1 - character.SupportFinder.sinMaximumSlope) * character.Body.CollisionInformation.Shape.CollisionMargin + 0);
            float length = characterBody.Radius + horizontalOffsetAmount;                            // -contact.PenetrationDepth;


            if (QueryManager.RayCastHitAnything(ray, length))
            {
                //The step is obstructed!
                newPosition = new System.Numerics.Vector3();
                return(false);
            }

            //The down-cast ray origin has been verified by the previous ray cast.
            //Let's look for a support!
            System.Numerics.Vector3 horizontalOffset;
            Vector3Ex.Multiply(ref normal, length, out horizontalOffset);
            Vector3Ex.Add(ref ray.Position, ref horizontalOffset, out ray.Position);
            ray.Direction = down;

            //Find the earliest hit, if any.
            RayHit earliestHit;

            if (!QueryManager.RayCast(ray, downRayLength, out earliestHit) ||      //Can't do anything if it didn't hit.
                earliestHit.T <= 0 ||                                              //Can't do anything if the hit was invalid.
                earliestHit.T - downRayLength > -minimumUpStepHeight ||            //Don't bother doing anything if the step is too small.
                earliestHit.T - downRayLength < -maximumStepHeight - upStepMargin) //Can't do anything if the step is too tall.
            {
                //No valid hit was detected.
                newPosition = new System.Numerics.Vector3();
                return(false);
            }

            //Ensure the candidate surface supports traction.
            System.Numerics.Vector3 supportNormal;
            Vector3Ex.Normalize(ref earliestHit.Normal, out supportNormal);
            //Calibrate the normal to face in the same direction as the down vector for consistency.
            Vector3Ex.Dot(ref supportNormal, ref down, out dot);
            if (dot < 0)
            {
                Vector3Ex.Negate(ref supportNormal, out supportNormal);
                dot = -dot;
            }

            //If the new surface does not have traction, do not attempt to step up.
            if (dot < ContactCategorizer.TractionThreshold)
            {
                newPosition = new System.Numerics.Vector3();
                return(false);
            }

            //Since contact queries are frequently expensive compared to ray cast tests,
            //do one more ray cast test.  This time, starting from the same position, cast upwards.
            //In order to step up, the previous down-ray hit must be at least a character height away from the result of the up-ray.
            Vector3Ex.Negate(ref down, out ray.Direction);
            //Find the earliest hit, if any.
            //RayHit earliestHitUp = new RayHit();
            //earliestHitUp.T = float.MaxValue;
            float upLength = characterBody.Height - earliestHit.T;

            //If the sum of the up and down distances is less than the height, the character can't fit.
            if (QueryManager.RayCastHitAnything(ray, upLength))
            {
                newPosition = new System.Numerics.Vector3();
                return(false);
            }

            //By now, a valid ray hit has been found.  Now we need to validate it using contact queries.
            //This process is very similar in concept to the down step verification, but it has some extra
            //requirements.

            //Predict a hit location based on the time of impact and the normal at the intersection.
            //Take into account the radius of the character (don't forget the collision margin!)



            RigidTransform transform = characterBody.CollisionInformation.WorldTransform;

            //The transform must be modified to position the query body at the right location.
            //The horizontal offset of the queries ensures that a tractionable part of the character will be put onto the new support.
            Vector3Ex.Multiply(ref normal, horizontalOffsetAmount, out horizontalOffset);
            Vector3Ex.Add(ref transform.Position, ref horizontalOffset, out transform.Position);
            System.Numerics.Vector3 verticalOffset;
            Vector3Ex.Multiply(ref down, -downRayLength, out verticalOffset);
            Vector3Ex.Add(ref transform.Position, ref verticalOffset, out transform.Position);

            //We know that the closest point to the plane will be the extreme point in the plane's direction.
            //Use it as the ray origin.
            Ray downRay;

            characterBody.CollisionInformation.Shape.GetExtremePoint(supportNormal, ref transform, out downRay.Position);
            downRay.Direction = down;

            //Intersect the ray against the plane defined by the support hit.
            System.Numerics.Vector3 intersection;
            Vector3Ex.Dot(ref earliestHit.Location, ref supportNormal, out dot);
            Plane plane = new Plane(supportNormal, dot);

            System.Numerics.Vector3 candidatePosition;

            //Define the interval bounds to be used later.

            //The words 'highest' and 'lowest' here refer to the position relative to the character's body.
            //The ray cast points downward relative to the character's body.
            float highestBound  = -maximumStepHeight;
            float lowestBound   = characterBody.CollisionInformation.Shape.CollisionMargin - downRayLength + earliestHit.T;
            float currentOffset = lowestBound;
            float hintOffset;

            var tractionContacts = new QuickList <CharacterContact>(BufferPools <CharacterContact> .Thread);
            var supportContacts  = new QuickList <CharacterContact>(BufferPools <CharacterContact> .Thread);
            var sideContacts     = new QuickList <CharacterContact>(BufferPools <CharacterContact> .Thread);
            var headContacts     = new QuickList <CharacterContact>(BufferPools <CharacterContact> .Thread);

            try
            {
                //This guess may either win immediately, or at least give us a better idea of where to search.
                float hitT;
                if (Toolbox.GetRayPlaneIntersection(ref downRay, ref plane, out hitT, out intersection))
                {
                    hitT = -downRayLength + hitT + CollisionDetectionSettings.AllowedPenetration;
                    if (hitT < highestBound)
                    {
                        //Don't try a location known to be too high.
                        hitT = highestBound;
                    }
                    currentOffset = hitT;
                    if (currentOffset > lowestBound)
                    {
                        lowestBound = currentOffset;
                    }
                    candidatePosition = characterBody.Position + down * currentOffset + horizontalOffset;
                    switch (TryUpStepPosition(ref normal, ref candidatePosition, ref down,
                                              ref tractionContacts, ref supportContacts, ref sideContacts, ref headContacts,
                                              out hintOffset))
                    {
                    case CharacterContactPositionState.Accepted:
                        currentOffset += hintOffset;
                        //Only use the new position location if the movement distance was the right size.
                        if (currentOffset < 0 && currentOffset > -maximumStepHeight - CollisionDetectionSettings.AllowedPenetration)
                        {
                            //It's possible that we let a just-barely-too-high step occur, limited by the allowed penetration.
                            //Just clamp the overall motion and let it penetrate a bit.
                            newPosition = characterBody.Position + Math.Max(-maximumStepHeight, currentOffset) * down + horizontalOffset;
                            return(true);
                        }
                        else
                        {
                            newPosition = new System.Numerics.Vector3();
                            return(false);
                        }

                    case CharacterContactPositionState.Rejected:
                        newPosition = new System.Numerics.Vector3();
                        return(false);

                    case CharacterContactPositionState.NoHit:
                        highestBound  = currentOffset + hintOffset;
                        currentOffset = (lowestBound + currentOffset) * .5f;
                        break;

                    case CharacterContactPositionState.Obstructed:
                        lowestBound   = currentOffset;
                        currentOffset = (highestBound + currentOffset) * .5f;
                        break;

                    case CharacterContactPositionState.HeadObstructed:
                        highestBound  = currentOffset + hintOffset;
                        currentOffset = (lowestBound + currentOffset) * .5f;
                        break;

                    case CharacterContactPositionState.TooDeep:
                        currentOffset += hintOffset;
                        lowestBound    = currentOffset;
                        break;
                    }
                } //TODO: If the ray cast doesn't hit, that could be used to early out...  Then again, it pretty much can't happen.

                //Our guesses failed.
                //Begin the regular process.  Start at the time of impact of the ray itself.
                //How about trying the time of impact of the ray itself?

                //Since we wouldn't be here unless there were no contacts at the body's current position,
                //testing the ray cast location gives us the second bound we need to do an informed binary search.



                int attempts = 0;
                //Don't keep querying indefinitely.  If we fail to reach it in a few informed steps, it's probably not worth continuing.
                //The bound size check prevents the system from continuing to search a meaninglessly tiny interval.
                while (attempts++ < 5 && lowestBound - highestBound > Toolbox.BigEpsilon)
                {
                    candidatePosition = characterBody.Position + currentOffset * down + horizontalOffset;
                    switch (TryUpStepPosition(ref normal, ref candidatePosition, ref down,
                                              ref tractionContacts, ref supportContacts, ref sideContacts, ref headContacts,
                                              out hintOffset))
                    {
                    case CharacterContactPositionState.Accepted:
                        currentOffset += hintOffset;
                        //Only use the new position location if the movement distance was the right size.
                        if (currentOffset < 0 && currentOffset > -maximumStepHeight - CollisionDetectionSettings.AllowedPenetration)
                        {
                            //It's possible that we let a just-barely-too-high step occur, limited by the allowed penetration.
                            //Just clamp the overall motion and let it penetrate a bit.
                            newPosition = characterBody.Position + Math.Max(-maximumStepHeight, currentOffset) * down + horizontalOffset;
                            return(true);
                        }
                        else
                        {
                            newPosition = new System.Numerics.Vector3();
                            return(false);
                        }

                    case CharacterContactPositionState.Rejected:
                        newPosition = new System.Numerics.Vector3();
                        return(false);

                    case CharacterContactPositionState.NoHit:
                        highestBound  = currentOffset + hintOffset;
                        currentOffset = (lowestBound + highestBound) * .5f;
                        break;

                    case CharacterContactPositionState.Obstructed:
                        lowestBound   = currentOffset;
                        currentOffset = (highestBound + lowestBound) * .5f;
                        break;

                    case CharacterContactPositionState.HeadObstructed:
                        highestBound  = currentOffset + hintOffset;
                        currentOffset = (lowestBound + currentOffset) * .5f;
                        break;

                    case CharacterContactPositionState.TooDeep:
                        currentOffset += hintOffset;
                        lowestBound    = currentOffset;
                        break;
                    }
                }
            }
            finally
            {
                tractionContacts.Dispose();
                supportContacts.Dispose();
                sideContacts.Dispose();
                headContacts.Dispose();
            }
            //Couldn't find a candidate.
            newPosition = new System.Numerics.Vector3();
            return(false);
        }
Exemple #28
0
        /// <summary>
        /// 相交点辐射光
        /// </summary>
        /// <param name="point"></param>
        /// <param name="normal"></param>
        /// <param name="deep"></param>
        /// <returns></returns>
        public virtual Light IntersectLight(Vector3 point, Vector3 dir, Vector3 normal, int deep)
        {
#if RayDebugger
            SceneDebug Debugger = Scene.debugger;
            if (Debugger != null)
            {
                Debugger.BeginBranch(point);
            }
#endif

            Light returnlight = default;
            // 发光体返回发光颜色
            if (Material.LightAble)
            {
                returnlight = Material.LightColor;
                goto returnPoint;
            }
            // 递归深度极限
            if (deep <= 1)
            {
                returnlight = Material.BaseColor * 0.3f;
                goto returnPoint;
            }

            dir = Vector3.Normalize(dir);
            bool IsBackFace = false;
            if (Vector3.Dot(dir, normal) > 0)               // 背面
            {
                IsBackFace = true;
                normal     = -normal;
            }

            #region 计算追踪光线总数
            int traceRayNum = RenderConfiguration.Configurations.ReflectSmapingLevel - RenderConfiguration.Configurations.RayTraceDeep + deep;
            {
                traceRayNum = (int)(traceRayNum * Material.AMetalDegree);
                if (traceRayNum < 1)
                {
                    traceRayNum = 1;
                }
                traceRayNum = traceRayNum * 3 - 2;
            }
            #endregion

            #region 计算折射光
            Light refractl     = default;         // 折射光
            float refractPower = 0.0f;            // 折射光强度
            if (Material.IsTransparent)
            {
                float riindex = Material.RefractiveIndices;
                if (!IsBackFace)
                {
                    riindex = 1.0f / riindex;
                }
                // 计算折射光线
                (float pow, Vector3 rdir) = Tools.Refract(dir, normal, riindex);
                if (pow < 0)
                {
                    goto endRefract;
                }

                refractPower = pow * Material.TransparentIndex;

                int raycount = (int)(traceRayNum * refractPower);
                traceRayNum -= raycount;

                float randomScale = Material.AMetalDegree * Material.AMetalDegree * 0.5f;
                //raycount = (int)(traceRayNum * randomScale);
                //raycount = (int)(traceRayNum * Material.AMetalDegree);
                if (raycount < 1 && refractPower > 0.00001)
                {
                    raycount = 1;
                }

                if (raycount == 0)
                {
                    refractl = Material.BaseColor;
                    goto endRefract;
                }

                rdir = normal * randomScale + rdir * (1.0f - randomScale);

                for (int nsmap = 0; nsmap < raycount; nsmap++)
                {
                    Vector3 raydir = Tools.RandomPointInSphere() * randomScale + rdir;

                    Ray r = new Ray(point, raydir);
                    //Console.WriteLine('\t' + this.Name + " [refract] : " + r);
                    (Light c, float distance) = Scene.Light(r, deep - 1, this);

                    if (IsBackFace)                       //内部光线,进行吸收计算
                    {
                        float xsl = Math.Log(distance + 1.0f) + 1.0f;
                        refractl *= Material.BaseColor / xsl;
                    }
                    refractl += c;
                }
                refractl /= raycount;
            }

endRefract:
            #endregion

            #region 计算反射光
            Light reflectl = default;             // 反射光
            {
                int raycount = traceRayNum;
                if (raycount < 1)
                {
                    if (refractPower < 0.99f)
                    {
                        raycount = 1;
                    }
                    else
                    {
                        reflectl = Material.BaseColor;
                        goto endReflact;
                    }
                }

                Vector3 spO;
                {
                    //Vector3 spRO = Tools.Reflect(dir, normal);
                    Vector3 spRO = Vector3.Reflect(dir, normal);
                    //spO = normal * (1.0f - Material.MetalDegree) + spRO * Material.MetalDegree;
                    spO = Vector3.Lerp(normal, spRO, Material.MetalDegree);
                }
                for (int nsmap = 0; nsmap < raycount; nsmap++)
                {
                    Vector3 tp     = Tools.RandomPointInSphere() * Material.AMetalDegree + spO;
                    Vector3 raydir = tp;
                    while (raydir.LengthSquared() < 0.1)
                    {
                        tp     = Tools.RandomPointInSphere() + spO;
                        raydir = tp;
                    }

                    Ray r = new Ray(point, raydir);
                    //Console.WriteLine('\t' + this.Name + " [reflact] : " + r);
                    (Light c, float _) = Scene.Light(r, deep - 1, this);                     //, this);
                    reflectl          += c;
                }
                reflectl /= raycount;
                reflectl *= (0.06f * Material.MetalDegree + 0.93f) * Material.BaseColor;
            }
            #endregion

            returnlight = refractl * refractPower + reflectl * (1.0f - refractPower);
endReflact:
returnPoint:
#if RayDebugger
            if (Debugger != null)
            {
                Debugger.EndBranch();
            }
#endif
            return(returnlight);
        }
Exemple #29
0
        public ImportedFLVER2Model ImportFromAssimpScene(Scene scene, FLVER2ImportSettings settings)
        {
            LoadMaterialInfoBankForGame(settings.Game);

            var result = new ImportedFLVER2Model();
            var flver  = result.Flver = new FLVER2();

            flver.Header.BigEndian      = settings.FlverHeader.BigEndian;
            flver.Header.BoundingBoxMax = new NVector3(float.MinValue);
            flver.Header.BoundingBoxMin = new NVector3(float.MaxValue);
            flver.Header.Unicode        = settings.FlverHeader.Unicode;
            flver.Header.Unk4A          = settings.FlverHeader.Unk4A;
            flver.Header.Unk4C          = settings.FlverHeader.Unk4C;
            flver.Header.Unk5C          = settings.FlverHeader.Unk5C;
            flver.Header.Unk5D          = settings.FlverHeader.Unk5D;
            flver.Header.Unk68          = settings.FlverHeader.Unk68;
            flver.Header.Version        = settings.FlverHeader.Version;

            var flverSceneMatrix = NMatrix.CreateScale(NVector3.One * settings.SceneScale);



            if (settings.ConvertFromZUp)
            {
                flverSceneMatrix *= SapMath.ZUpToYUpNMatrix;
            }

            //flverSceneMatrix *= NMatrix.CreateRotationY(SapMath.Pi);

            flverSceneMatrix *= settings.SceneCorrectMatrix;



            flverSceneMatrix *= NMatrix.CreateScale(1, 1, -1);


            var coordMat = AssimpUtilities.GetSceneCoordSystemMatrix(scene);

            scene.RootNode.Transform *= coordMat;

            var skeletonRootNode = AssimpUtilities.FindRootNode(scene, settings.RootNodeName, out Matrix4x4 skeletonRootNodeMatrix);


            var metaskeleton = FLVERImportHelpers.GenerateFlverMetaskeletonFromRootNode(
                skeletonRootNode, skeletonRootNodeMatrix, settings.SceneScale);

            flver.Bones   = metaskeleton.Bones;
            flver.Dummies = metaskeleton.DummyPoly;

            foreach (var b in flver.Bones)
            {
                // Mark as dummied-out bone until iterating over them later and seeing which are weighted to meshes.
                if (b.ParentIndex == -1)
                {
                    b.Unk3C = 1;
                }
            }

            var usesIndirectBones = flver.Header.Version <= 0x20010;

            if (settings.SkeletonTransformsOverride != null)
            {
                flver.Bones = settings.SkeletonTransformsOverride;
            }



            //var flverMaterialList = new List<FLVER2.Material>();

            foreach (var material in scene.Materials)
            {
                string[] materialNameSplit = material.Name.Split('|');
                string   mtd = materialNameSplit.Length > 1 ? materialNameSplit[1].Trim() + ".mtd" : null;

                // If MTD doesn't exist, use original
                mtd = MaterialInfoBankPerGame[settings.Game].FallbackToDefaultMtdIfNecessary(mtd, Logger);

                //ErrorTODO: materialNameSplit should be 2 items long.
                var flverMaterial = new FLVER2.Material(materialNameSplit[0].Trim(), mtd, 0);


                void AddTextureSlot(TextureSlot slot, string ingameSlot)
                {
                    flverMaterial.Textures.Add(new FLVER2.Texture(type: ingameSlot,
                                                                  path: slot.FilePath != null ? Path.GetFullPath(slot.FilePath) : "",
                                                                  scale: System.Numerics.Vector2.One,
                                                                  1, true, 0, 0, 0));

                    string texName = Path.GetFileNameWithoutExtension(slot.FilePath);

                    byte[] texData = scene.GetEmbeddedTexture(slot.FilePath)?.CompressedData;

                    if (texData != null)
                    {
                        var ddsFormat = TPFTextureFormatFinder.GetTpfFormatFromDdsBytes(texData);

                        result.Textures.Add(new TPF.Texture(texName, format: ddsFormat, flags1: 0, bytes: texData));
                    }
                }

                var materialDefinition = MaterialInfoBankPerGame[settings.Game].MaterialDefs[mtd.ToLower()];
                var texChanDefs        = materialDefinition.TextureChannels;
                foreach (var kvp in texChanDefs)
                {
                    if (kvp.Key.Index == 0)
                    {
                        if (kvp.Key.Semantic == TextureChannelSemantic.Diffuse)
                        {
                            AddTextureSlot(material.TextureDiffuse, kvp.Value);
                        }
                        else if (kvp.Key.Semantic == TextureChannelSemantic.Specular)
                        {
                            AddTextureSlot(material.TextureSpecular, kvp.Value);
                        }
                        else if (kvp.Key.Semantic == TextureChannelSemantic.Normals)
                        {
                            AddTextureSlot(material.TextureNormal, kvp.Value);
                        }
                        else if (kvp.Key.Semantic == TextureChannelSemantic.Emissive)
                        {
                            AddTextureSlot(material.TextureEmissive, kvp.Value);
                        }
                        else
                        {
                            flverMaterial.Textures.Add(new FLVER2.Texture(type: kvp.Value,
                                                                          path: string.Empty,
                                                                          scale: System.Numerics.Vector2.One,
                                                                          0, false, 0, 0, 0));
                        }
                    }
                }

                if (materialDefinition.GXItems.Count > 0)
                {
                    flverMaterial.GXIndex = flver.GXLists.Count;
                    var gxList = new FLVER2.GXList();

                    for (int i = 0; i < materialDefinition.GXItems.Count; i++)
                    {
                        var    gxid  = materialDefinition.GXItems[i].GXID;
                        var    unk04 = materialDefinition.GXItems[i].Unk04;
                        byte[] data  = MaterialInfoBankPerGame[settings.Game].DefaultGXItemDataExamples[mtd][i];
                        gxList.Add(new FLVER2.GXItem(gxid, unk04, data));
                    }
                    flver.GXLists.Add(gxList);
                }

                flver.Materials.Add(flverMaterial);
                //flverMaterialList.Add(flverMaterial);
            }

            //var properBoneParentRegistry = new Dictionary<Bone, string>();

            //foreach (var mesh in scene.Meshes)
            //{
            //    foreach (var b in mesh.Bones)
            //    {
            //        bool alreadyRegistered = false;
            //        foreach (var bone in properBoneParentRegistry.Keys)
            //        {
            //            if (bone.Name == b.Name)
            //            {
            //                alreadyRegistered = true;
            //                break;
            //            }
            //        }
            //        if (alreadyRegistered)
            //            continue;
            //        mesh.
            //        properBoneParentRegistry.Add(b, b.)
            //    }
            //}

            if (settings.BoneNameRemapper != null)
            {
                foreach (var bn in settings.BoneNameRemapper)
                {
                    var bone = flver.Bones.FindIndex(b => b.Name == bn.Key);
                    if (bone >= 0)
                    {
                        flver.Bones[bone].Name = bn.Value;
                    }
                }
            }

            foreach (var mesh in scene.Meshes)
            {
                var flverMesh = new FLVER2.Mesh();

                flverMesh.BoundingBox = new FLVER2.Mesh.BoundingBoxes();

                //TODO: ACTUALLY READ FROM THINGS
                flverMesh.Dynamic = 1;



                // Register mesh transform bone:
                //flverMesh.DefaultBoneIndex = flver.Bones.Count;
                //int flverLastRootBoneIndex = flver.Bones.FindLastIndex(b => b.ParentIndex == -1);
                //// Register this new bone as a sibling.
                //if (flverLastRootBoneIndex >= 0)
                //    flver.Bones[flverLastRootBoneIndex].NextSiblingIndex = (short)flverMesh.DefaultBoneIndex;
                //flver.Bones.Add(new FLVER.Bone()
                //{
                //    Name = mesh.Name,
                //    Translation = NVector3.Zero,
                //    Rotation = NVector3.Zero,
                //    Scale = NVector3.One,
                //    BoundingBoxMin = NVector3.One * -0.05f,
                //    BoundingBoxMax = NVector3.One * 0.05f,
                //    // Cross-register sibling from above.
                //    PreviousSiblingIndex = (short)flverLastRootBoneIndex,
                //    NextSiblingIndex = -1,
                //    ParentIndex = -1,
                //    ChildIndex = -1,
                //    Unk3C = 1,
                //});



                int meshUVCount = 0;
                for (int i = 0; i < mesh.UVComponentCount.Length; i++)
                {
                    if (mesh.UVComponentCount[i] > 0)
                    {
                        meshUVCount++;
                    }
                }
                if (mesh.PrimitiveType != PrimitiveType.Triangle)
                {
                    Console.WriteLine();
                }

                var flverFaceSet = new FLVER2.FaceSet();

                //flverFaceSet.TriangleStrip = true;

                // Handle vertex buffers / layouts:
                flverMesh.MaterialIndex = mesh.MaterialIndex;
                //var newMat = flverMaterialList[mesh.MaterialIndex];
                //var indexOfNewMat = flver.Materials.IndexOf(newMat);
                //if (indexOfNewMat >= 0)
                //{
                //    flverMesh.MaterialIndex = indexOfNewMat;
                //}
                //else
                //{
                //    flverMesh.MaterialIndex = flver.Materials.Count;
                //    flver.Materials.Add(newMat);
                //}


                var flverMaterial            = flver.Materials[flverMesh.MaterialIndex];
                var matDefinition            = MaterialInfoBankPerGame[settings.Game].MaterialDefs[flverMaterial.MTD.ToLower()];
                var defaultBufferDeclaration = matDefinition.AcceptableVertexBufferDeclarations[0];

                Dictionary <FLVER.LayoutSemantic, int> requiredVertexBufferMembers =
                    new Dictionary <FLVER.LayoutSemantic, int>();

                foreach (var buff in defaultBufferDeclaration.Buffers)
                {
                    foreach (var m in buff)
                    {
                        if (!requiredVertexBufferMembers.ContainsKey(m.Semantic))
                        {
                            requiredVertexBufferMembers.Add(m.Semantic, 0);
                        }
                        requiredVertexBufferMembers[m.Semantic]++;
                    }

                    int nextLayoutIndex = flver.BufferLayouts.Count;
                    flver.BufferLayouts.Add(buff);
                    var vertBuffer = new FLVER2.VertexBuffer(nextLayoutIndex);
                    flverMesh.VertexBuffers.Add(vertBuffer);
                }



                flverMesh.Vertices = new List <FLVER.Vertex>(mesh.VertexCount);

                for (int i = 0; i < mesh.VertexCount; i++)
                {
                    var newVert = new FLVER.Vertex(uvCapacity: meshUVCount,
                                                   //TODO: Figure out what multiple tangents are used for etc and implement all
                                                   //      of that into the XML vert layout system stuff etc etc.
                                                   tangentCapacity: mesh.HasTangentBasis ? 1 : 0,
                                                   colorCapacity: mesh.VertexColorChannelCount);

                    newVert.Position = NVector3.Transform(mesh.Vertices[i].ToNumerics(), flverSceneMatrix);

                    flver.Header.UpdateBoundingBox(newVert.Position);
                    if (flverMesh.BoundingBox != null)
                    {
                        flverMesh.UpdateBoundingBox(newVert.Position);
                    }

                    newVert.Normal = NVector3.Normalize(NVector3.TransformNormal(mesh.Normals[i].ToNumerics(), flverSceneMatrix));

                    //TODO: TEST THIS AGAINST OTHER GAMES ETC
                    //newVert.NormalW = 127;

                    if (mesh.HasTangentBasis)
                    {
                        //ErrorTODO: Throw error if mesh somehow has tangents but not normals.
                        var tan      = mesh.Tangents[i];
                        var bitanXYZ = mesh.BiTangents[i];
                        //TODO: Check Bitangent W calculation
                        var bitanW = Vector3D.Dot(Vector3D.Cross(tan, mesh.Normals[i]), bitanXYZ) >= 0 ? 1 : -1;
                        var bitanXYZTransformed = NVector3.Normalize(NVector3.TransformNormal(bitanXYZ.ToNumerics(), flverSceneMatrix));
                        newVert.Tangents.Add(new System.Numerics.Vector4(bitanXYZTransformed, bitanW));
                        //TODO: CHECK THIS AND SEE WTF IT EVEN IS SUPPOSED TO BE
                        newVert.Bitangent = new System.Numerics.Vector4(
                            NVector3.TransformNormal(tan.ToNumerics(), flverSceneMatrix), 0);
                    }

                    for (int j = 0; j < meshUVCount; j++)
                    {
                        var uv = mesh.TextureCoordinateChannels[j][i];
                        newVert.UVs.Add(new NVector3(uv.X, 1 - uv.Y, uv.Z));
                    }

                    for (int j = 0; j < mesh.VertexColorChannelCount; j++)
                    {
                        newVert.Colors.Add(mesh.VertexColorChannels[j][i].ToFlverVertexColor());
                    }

                    for (int j = 0; j < 4; j++)
                    {
                        newVert.BoneIndices[j] = -1;
                    }

                    newVert.EnsureLayoutMembers(requiredVertexBufferMembers);

                    flverMesh.Vertices.Add(newVert);
                }

                if (usesIndirectBones)
                {
                    var bonesInMesh = mesh.Bones.OrderByDescending(mb => mb.VertexWeightCount).ToList();
                    foreach (var bone in bonesInMesh)
                    {
                        var boneIndex = flver.Bones.FindIndex(b => b.Name == bone.Name);

                        if (!flverMesh.BoneIndices.Contains(boneIndex))
                        {
                            flverMesh.BoneIndices.Add(boneIndex);
                        }
                    }

                    flverMesh.BoneIndices = flverMesh.BoneIndices.OrderBy(idx => idx).ToList();
                }



                foreach (var bone in mesh.Bones)
                {
                    var boneIndex = flver.Bones.FindIndex(b => b.Name == bone.Name);

                    if (boneIndex == -1)
                    {
                        Logger.LogWarning($"No bone with exact name '{bone.Name}' found. Looking for a bone that starts with that name");
                        boneIndex = flver.Bones.FindIndex(b => b.Name.StartsWith(bone.Name));
                    }

                    var boneDoesNotExist = false;

                    // Mark bone as not-dummied-out since there is geometry skinned to it.
                    if (boneIndex >= 0 && boneIndex < flver.Bones.Count)
                    {
                        flver.Bones[boneIndex].Unk3C = 0;
                    }
                    else
                    {
                        Logger.LogWarning($"Vertex skinned to bone '{bone.Name}' which does NOT exist in the skeleton.");
                        boneDoesNotExist = true;
                    }

                    int GetNextAvailableBoneSlotOfVert(int vertIndex)
                    {
                        if (flverMesh.Vertices[vertIndex].BoneIndices[0] < 0)
                        {
                            return(0);
                        }
                        else if (flverMesh.Vertices[vertIndex].BoneIndices[1] < 0)
                        {
                            return(1);
                        }
                        else if (flverMesh.Vertices[vertIndex].BoneIndices[2] < 0)
                        {
                            return(2);
                        }
                        else if (flverMesh.Vertices[vertIndex].BoneIndices[3] < 0)
                        {
                            return(3);
                        }
                        else
                        {
                            return(-1);
                        }
                    }

                    foreach (var weight in bone.VertexWeights)
                    {
                        int boneSlot = GetNextAvailableBoneSlotOfVert(weight.VertexID);
                        if (boneSlot >= 0)
                        {
                            var indexToAssign = usesIndirectBones ? flverMesh.BoneIndices.IndexOf(boneIndex) : boneIndex;
                            if (indexToAssign == -1)
                            {
                                Console.WriteLine("fatcat");
                            }
                            flverMesh.Vertices[weight.VertexID].BoneIndices[boneSlot] = boneDoesNotExist ? 0 : indexToAssign;
                            flverMesh.Vertices[weight.VertexID].BoneWeights[boneSlot] = boneDoesNotExist ? 0 : weight.Weight;
                            if (!boneDoesNotExist)
                            {
                                flver.Bones[boneIndex].UpdateBoundingBox(flver.Bones, flverMesh.Vertices[weight.VertexID].Position);
                            }
                        }
                    }
                }

                for (int i = 0; i < flverMesh.Vertices.Count; i++)
                {
                    float weightMult = 1 / (
                        flverMesh.Vertices[i].BoneWeights[0] +
                        flverMesh.Vertices[i].BoneWeights[1] +
                        flverMesh.Vertices[i].BoneWeights[2] +
                        flverMesh.Vertices[i].BoneWeights[3]);

                    for (int j = 0; j < 4; j++)
                    {
                        //flverMesh.Vertices[i].BoneWeights[j] = flverMesh.Vertices[i].BoneWeights[j] * weightMult;
                        if (flverMesh.Vertices[i].BoneIndices[j] < 0)
                        {
                            flverMesh.Vertices[i].BoneIndices[j] = 0;
                        }
                    }

                    //TODO: TEST THIS AGAINST OTHER GAMES ETC
                    if (!requiredVertexBufferMembers.ContainsKey(FLVER.LayoutSemantic.BoneIndices))
                    {
                        flverMesh.Vertices[i].NormalW = flverMesh.Vertices[i].BoneIndices[0];
                    }
                }

                //foreach (var face in mesh.Faces)
                //{
                //    //TODO: See if resets need to be added inbetween or anything.
                //    flverFaceSet.Indices.AddRange(face.Indices);
                //}

                flverFaceSet.Indices.AddRange(mesh.GetIndices());

                flverMesh.FaceSets.Add(flverFaceSet);
                GenerateLodAndMotionBlurFacesets(flverMesh);

                flver.Meshes.Add(flverMesh);
            }

            // DEBUGGING

            //flver.Bones.RemoveAt(0);
            //foreach (var mm in flver.Meshes)
            //    for (int mbi = 0; mbi < mm.BoneIndices.Count; mbi++)
            //        mm.BoneIndices[mbi] = mm.BoneIndices[mbi] - 1;
            //foreach (var b in flver.Bones)
            //{
            //    if (b.ParentIndex >= 0)
            //        b.ParentIndex--;
            //    if (b.ChildIndex >= 0)
            //        b.ChildIndex--;
            //    if (b.NextSiblingIndex >= 0)
            //        b.NextSiblingIndex--;
            //    if (b.PreviousSiblingIndex >= 0)
            //        b.PreviousSiblingIndex--;
            //}

            ///////////////////

            foreach (var b in flver.Bones)
            {
                if (settings.SkeletonTransformsOverride != null)
                {
                    var match = settings.SkeletonTransformsOverride.FindIndex(bn => bn.Name == b.Name);
                    if (match >= 0)
                    {
                        b.Translation = settings.SkeletonTransformsOverride[match].Translation;
                        b.Rotation    = settings.SkeletonTransformsOverride[match].Rotation;
                        b.Scale       = settings.SkeletonTransformsOverride[match].Scale;
                    }
                }

                if (float.IsInfinity(b.BoundingBoxMin.X) || float.IsInfinity(b.BoundingBoxMin.Y) || float.IsInfinity(b.BoundingBoxMin.Z) ||
                    float.IsInfinity(b.BoundingBoxMax.X) || float.IsInfinity(b.BoundingBoxMax.Y) || float.IsInfinity(b.BoundingBoxMax.Z))
                {
                    b.BoundingBoxMin = NVector3.One * -0.1f;
                    b.BoundingBoxMax = NVector3.One * 0.1f;
                }
            }

            return(result);
        }
Exemple #30
0
 /**
  * Constructor for a ray
  *
  * @param direction direction ray
  * @param point beginning of the ray
  */
 public Line(Vector3d direction, Point3d point)
 {
     this.direction = Vector3d.Normalize(direction);
     this.point     = point;
     //direction.normalize();
 }
Exemple #31
0
        /// <summary>
        /// Finds a supporting entity, the contact location, and the contact normal.
        /// </summary>
        /// <param name="location">Contact point between the wheel and the support.</param>
        /// <param name="normal">Contact normal between the wheel and the support.</param>
        /// <param name="suspensionLength">Length of the suspension at the contact.</param>
        /// <param name="supportingCollidable">Collidable supporting the wheel, if any.</param>
        /// <param name="entity">Supporting object.</param>
        /// <param name="material">Material of the wheel.</param>
        /// <returns>Whether or not any support was found.</returns>
        protected internal override bool FindSupport(out System.Numerics.Vector3 location, out System.Numerics.Vector3 normal, out float suspensionLength, out Collidable supportingCollidable, out Entity entity, out Material material)
        {
            suspensionLength     = float.MaxValue;
            location             = Toolbox.NoVector;
            supportingCollidable = null;
            entity   = null;
            normal   = Toolbox.NoVector;
            material = null;

            Collidable testCollidable;
            RayHit     rayHit;

            bool hit = false;

            for (int i = 0; i < detector.CollisionInformation.pairs.Count; i++)
            {
                var pair = detector.CollisionInformation.pairs[i];
                testCollidable = (pair.BroadPhaseOverlap.entryA == detector.CollisionInformation ? pair.BroadPhaseOverlap.entryB : pair.BroadPhaseOverlap.entryA) as Collidable;
                if (testCollidable != null)
                {
                    if (CollisionRules.CollisionRuleCalculator(this, testCollidable) == CollisionRule.Normal &&
                        testCollidable.RayCast(new Ray(wheel.suspension.worldAttachmentPoint, wheel.suspension.worldDirection), wheel.suspension.restLength, out rayHit) &&
                        rayHit.T < suspensionLength)
                    {
                        suspensionLength = rayHit.T;
                        EntityCollidable entityCollidable;
                        if ((entityCollidable = testCollidable as EntityCollidable) != null)
                        {
                            entity   = entityCollidable.Entity;
                            material = entityCollidable.Entity.Material;
                        }
                        else
                        {
                            entity = null;
                            supportingCollidable = testCollidable;
                            var materialOwner = testCollidable as IMaterialOwner;
                            if (materialOwner != null)
                            {
                                material = materialOwner.Material;
                            }
                        }
                        location = rayHit.Location;
                        normal   = rayHit.Normal;
                        hit      = true;
                    }
                }
            }
            if (hit)
            {
                if (suspensionLength > 0)
                {
                    normal.Normalize();
                }
                else
                {
                    Vector3Ex.Negate(ref wheel.suspension.worldDirection, out normal);
                }
                return(true);
            }
            return(false);
        }