Exemple #1
0
        //todo -- this needs to fleshed out more once weapons work.
        //probably dont want an object for each point. Probably want
        //to add a gunslot component here to contain this data instead.
        private GameObject CreateMissilePoints()
        {
            if (!model.HasMissileSlots)
            {
                return(null);
            }
            GameObject         retn         = new GameObject("Missile Points");
            List <MissileSlot> missileSlots = model.missileSlots;

            for (int i = 0; i < missileSlots.Count; i++)
            {
                MissileSlot slot = missileSlots[i];

                for (int j = 0; j < slot.missilePoints.Length; j++)
                {
                    GameObject     go           = new GameObject("Missile Point " + i + " -- " + j);
                    PositionNormal missilePoint = slot.missilePoints[j];
                    go.transform.parent   = retn.transform;
                    go.transform.position = missilePoint.point;
                    if (missilePoint.normal == Vector3.zero)
                    {
                        missilePoint.normal = Vector3.forward;
                    }
                    go.transform.rotation = Quaternion.LookRotation(missilePoint.normal, Vector3.up);
                }
            }

            return(retn);
        }
Exemple #2
0
        //todo -- this needs to fleshed out more once weapons work.
        //probably dont want an object for each point. Probably want
        //to add a gunslot component here to contain this data instead.
        private GameObject CreateGunPoints()
        {
            if (!model.HasGunSlots)
            {
                return(null);
            }
            GameObject     retn     = new GameObject("Gun Points");
            List <GunSlot> gunSlots = model.gunSlots;

            for (int i = 0; i < gunSlots.Count; i++)
            {
                GunSlot slot = gunSlots[i];

                for (int j = 0; j < slot.gunPoints.Length; j++)
                {
                    GameObject     go       = new GameObject("Gun Point " + i + " -- " + j);
                    PositionNormal gunPoint = slot.gunPoints[j];
                    go.transform.parent   = retn.transform;
                    go.transform.position = gunPoint.point;
                    if (gunPoint.normal == Vector3.zero)
                    {
                        gunPoint.normal = Vector3.forward;
                    }
                    go.transform.rotation = Quaternion.LookRotation(gunPoint.normal, Vector3.up);
                }
            }

            return(retn);
        }
Exemple #3
0
        private void CalculateNormal(PositionNormal v1, PositionNormal v2, PositionNormal v3)
        {
            Vector3 vu = v3.Position - v1.Position;
            Vector3 vt = v2.Position - v1.Position;
            Vector3 normal = Vector3.Cross(vu, vt);
            normal.Normalize();

            v1.Normal += normal;
            v2.Normal += normal;
            v3.Normal += normal;
        }
Exemple #4
0
        public void GetObjectPositionOnWater(ObjectGeometry obj, WaterShader shader)
        {
            PositionNormal p11 = new PositionNormal();
            PositionNormal p12 = new PositionNormal();
            PositionNormal p13 = new PositionNormal();
            PositionNormal p21 = new PositionNormal();
            PositionNormal p22 = new PositionNormal();
            PositionNormal p23 = new PositionNormal();
            PositionNormal p31 = new PositionNormal();
            PositionNormal p32 = new PositionNormal();
            PositionNormal p33 = new PositionNormal();

            Vector3 position = obj.ModelMatrix.Translation;
            position.Y = 20;

            p11.Position = CalculatePosition(Vector3.Transform(position + new Vector3(-5, 0, 5), obj.RotationMatrix), shader);
            p12.Position = CalculatePosition(Vector3.Transform(position + new Vector3(0, 0, 5), obj.RotationMatrix), shader);
            p13.Position = CalculatePosition(Vector3.Transform(position + new Vector3(5, 0, 5), obj.RotationMatrix), shader);

            p21.Position = CalculatePosition(Vector3.Transform(position + new Vector3(-5, 0, 0), obj.RotationMatrix), shader);
            p22.Position = CalculatePosition(Vector3.Transform(position + new Vector3(0, 0, 0), obj.RotationMatrix), shader);
            p23.Position = CalculatePosition(Vector3.Transform(position + new Vector3(5, 0, 0), obj.RotationMatrix), shader);

            p31.Position = CalculatePosition(Vector3.Transform(position + new Vector3(-5, 0, -5), obj.RotationMatrix), shader);
            p32.Position = CalculatePosition(Vector3.Transform(position + new Vector3(0, 0, -5), obj.RotationMatrix), shader);
            p33.Position = CalculatePosition(Vector3.Transform(position + new Vector3(5, 0, -5), obj.RotationMatrix), shader);

            CalculateNormal(p11, p22, p23);
            CalculateNormal(p11, p12, p23);

            CalculateNormal(p12, p22, p23);
            CalculateNormal(p12, p13, p23);

            CalculateNormal(p21, p31, p32);
            CalculateNormal(p21, p22, p32);

            CalculateNormal(p22, p32, p33);
            CalculateNormal(p22, p23, p33);

            obj.Translate(new Vector3(position.X,p22.Position.Y,position.Z));
            obj.Update();

            obj.UpVector = p22.Normal;
            obj.RightVector = Vector3.Cross(obj.ForwardVector, obj.UpVector);
            obj.RightVector = Vector3.Normalize(obj.RightVector);

            obj.ForwardVector = Vector3.Cross(obj.UpVector, obj.RightVector);
            obj.ForwardVector = Vector3.Normalize(obj.ForwardVector);
        }
Exemple #5
0
        private PositionNormal[] CreatePointCloudData()
        {
            // Performance note for NVIDIA GTX 970 with 4 GB ram:
            // 20 mio points: CompleteRenderTime takes around 10 ms
            // 10 mio points: CompleteRenderTime is less than 0.1 ms
            //
            // On NVIDIA 1080 GTX with 8 GB ram the big performance drop happens around 40 mio points.


            int overallPointCount = (int)PointsCountComboBox.SelectedItem;
            //int overallPointCount = 100000;
            int sliceCount = 500; // 500 points in one horizontal circle

            if ((long)overallPointCount * (long)PositionNormal.SizeInBytes > (long)Int32.MaxValue)
            {
                throw new Exception("shadedPoints array too big. Split data into multiple arrays.");
            }


            var shadedPoints = new PositionNormal[overallPointCount];

            //for (int i = 0; i < overallPointCount / sliceCount; i++)

            // Parallel improves performance of 50 mio points from 4378ms to 821ms
            Parallel.For(0, overallPointCount / sliceCount, (i) =>
            {
                for (int j = 0; j < sliceCount; j++)
                {
                    int index = sliceCount * i + j;

                    float x = 30.0f * (float)Math.Cos(2 * Math.PI * (double)j / sliceCount);
                    float y = 0.02f * i;
                    float z = 30.0f * (float)Math.Sin(2 * Math.PI * (double)j / sliceCount);

                    var normal = new Vector3(x, 0, z);
                    normal.Normalize();

                    shadedPoints[index] = new PositionNormal()
                    {
                        Position = new Vector3(x, y, z),
                        Normal   = normal
                    };
                }
            });

            return(shadedPoints);
        }
Exemple #6
0
        // Load position and normal data from a text file.
        // The first line in the file must be number of points.
        // Then each line represents one point with tab separated values (floats are in InvariantCulture with . as decimal separator).
        private PositionNormal[] LoadPointCloudData(string fileName)
        {
            PositionNormal[] shadedPoints = null;

            using (var fs = System.IO.File.OpenText(fileName))
            {
                int index = -1;

                try
                {
                    string oneLine = fs.ReadLine();

                    // First line should have number of rows
                    int rowsCount = Int32.Parse(oneLine);
                    index++;

                    shadedPoints = new PositionNormal[rowsCount];

                    for (int i = 0; i < rowsCount; i++)
                    {
                        oneLine = fs.ReadLine();
                        var oneLineParts = oneLine.Split('\t');

                        // IMPORTANT: In WPF and DXEngine y is up so we need to swap y and z values

                        shadedPoints[index].Position = new Vector3(float.Parse(oneLineParts[0], System.Globalization.CultureInfo.InvariantCulture),
                                                                   float.Parse(oneLineParts[2], System.Globalization.CultureInfo.InvariantCulture),
                                                                   float.Parse(oneLineParts[1], System.Globalization.CultureInfo.InvariantCulture));

                        shadedPoints[index].Normal = new Vector3(float.Parse(oneLineParts[3], System.Globalization.CultureInfo.InvariantCulture),
                                                                 float.Parse(oneLineParts[5], System.Globalization.CultureInfo.InvariantCulture),
                                                                 float.Parse(oneLineParts[4], System.Globalization.CultureInfo.InvariantCulture));
                        index++;
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(string.Format("Error reading point cloud data in line {0} of file:\r\n{1}\r\n\r\nError message:\r\n{2}",
                                                  index + 1, fileName, ex.Message));

                    return(shadedPoints);
                }
            }

            return(shadedPoints);
        }
Exemple #7
0
        private MeshBase CreateTubePathMesh(Vector3[] pathPositions, float radius, int segmentsCount, bool isTubeClosed, Color4 tubeColor)
        {
            int pathPositionsCount = pathPositions.Length;


            // Preallocate the positions, indices, normals and textures collections - this prevents resizing the collection when the elements are added to them
            int totalPositionsCount = segmentsCount * pathPositionsCount;

            int shownSegmentsCount        = pathPositionsCount - 1;
            int totalTriangleIndicesCount = shownSegmentsCount * segmentsCount * 2 * 3; // 2 triangles for each segment * No. of shown segments * 3 indices per triangle

            if (isTubeClosed)
            {
                totalTriangleIndicesCount += (segmentsCount - 2) * 2 * 3; // Add closing triangles (for triangle strip)
            }
            var vertexBuffer = new PositionNormal[totalPositionsCount];
            var indexBuffer  = new int[totalTriangleIndicesCount];

            AddTubePathMesh(pathPositions, radius, segmentsCount, isTubeClosed, vertexBuffer, indexBuffer, vertexBufferStartIndex: 0, indexBufferStartIndex: 0);

            var simpleMesh = new SimpleMesh <PositionNormal>(vertexBuffer,
                                                             indexBuffer,
                                                             inputLayoutType: InputLayoutType.Position | InputLayoutType.Normal);

            // Quickly calculate mesh BoundingBox
            // If this is not done here, then BoundingBox is calculated in SimpleMesh with checking all the tube path's positions.
            // To prevent checking all the positions, we can simplify the calculation of bounding box with using
            // all path positions and then extending this for radius into all directions.
            // This will create slightly bigger bounding box but this is not a problem.
            var positionsBoundingBox = BoundingBox.FromPoints(pathPositions);

            simpleMesh.Bounds = new Bounds(new Vector3(positionsBoundingBox.Minimum.X - radius, positionsBoundingBox.Minimum.Y - radius, positionsBoundingBox.Minimum.Z - radius),
                                           new Vector3(positionsBoundingBox.Maximum.X + radius, positionsBoundingBox.Maximum.Y + radius, positionsBoundingBox.Maximum.Z + radius));

            _disposables.Add(simpleMesh);

            return(simpleMesh);
        }
Exemple #8
0
        private void AddTubePathMesh(Vector3[] pathPositions, float radius, int segmentsCount, bool isTubeClosed, PositionNormal[] vertexBuffer, int[] indexBuffer, int vertexBufferStartIndex, int indexBufferStartIndex)
        {
            if (_lastSegmentsCount != segmentsCount)
            {
                _sinuses = new float[segmentsCount];
                _cosines = new float[segmentsCount];

                double angle     = 0;
                double angleStep = 2 * Math.PI / segmentsCount;

                for (int i = 0; i < segmentsCount; i++)
                {
                    _sinuses[i] = (float)Math.Sin(angle) * radius;
                    _cosines[i] = (float)Math.Cos(angle) * radius;

                    angle += angleStep;
                }

                _lastSegmentsCount = segmentsCount;
            }


            int pathPositionsCount  = pathPositions.Length;
            int totalPositionsCount = segmentsCount * pathPositionsCount;

            Vector3 pathPosition1 = pathPositions[0];
            Vector3 pathPosition2 = pathPositions[1];

            Vector3 lastDirection = new Vector3();


            // Calculate the perpendicular vectors for the first segment
            // First get the direction of the
            Vector3 pathSegmentDirection = pathPositions[1] - pathPosition1;

            pathSegmentDirection.Normalize();

            // Now we calculate the vectors that are perpendicular (90 degrees) to the averageSegmentDirection
            // For heightDirection = (0, 1, 0) the values are:
            // p1 = (1, 0, 0) - right
            // p2 = (0, 0, -1) - into the screen
            Vector3 p1, p2; // two perpendicular vectors

            GetPerpendicularVectors(pathSegmentDirection, out p1, out p2);


            int vertexBufferIndex = vertexBufferStartIndex;
            int indexBufferIndex  = indexBufferStartIndex;

            for (int i = 0; i < pathPositionsCount; i++)
            {
                // Get the used direction for segment - this is the average of directions of the previous and the next segment (except for first and last segment)
                Vector3 averageSegmentDirection;

                if (i == 0)
                {
                    // first segment: use the direction of the first segment except when the path is closed - the we need to average the first and last segment
                    averageSegmentDirection = pathSegmentDirection;
                }
                else if (i == pathPositionsCount - 1)
                {
                    averageSegmentDirection = lastDirection;
                }
                else
                {
                    // inner segments: average the direction of the previous and the next segment
                    pathPosition2 = pathPositions[i + 1];

                    pathSegmentDirection = pathPosition2 - pathPosition1;
                    pathSegmentDirection.Normalize();

                    // The direction of the inter-section circle is the average direction of the previous and next segment
                    averageSegmentDirection = (lastDirection + pathSegmentDirection) * 0.5f;
                }


                // Calculate the new perpendicular vectors (p1 and p2)
                // We should not use the MathUtils.GetPerpendicularVectors because this could lead to sudden "flip" of a vector
                // Therefore we reuse the previous p1 and p2 vectors and use the new averageSegmentDirection to update the p1 and p2 values
                p1 = Vector3.Cross(p2, averageSegmentDirection);

                var p1LengthSquared = p1.X * p1.X + p1.Y * p1.Y + p1.Z * p1.Z;

                if (p1LengthSquared > 1e-6)
                {
                    p2 = Vector3.Cross(averageSegmentDirection, p1);
                }
                else if (p1LengthSquared <= 1e-6)
                {
                    // This could happen for the following data:
                    //pathPositions = new Point3DCollection(new Point3D[]
                    //{
                    //    new Point3D(0, 0, 0),
                    //    new Point3D(10, 0, 0),
                    //    new Point3D(10, 0, 10),
                    //    new Point3D(-10, 0, 10)
                    //});

                    GetPerpendicularVectors(averageSegmentDirection, out p1, out p2);
                }

                p1.Normalize();
                p2.Normalize();


                for (int j = 0; j < segmentsCount; j++)
                {
                    float sin = _sinuses[j];
                    float cos = _cosines[j];

                    float x = sin * p1.X - cos * p2.X;
                    float y = sin * p1.Y - cos * p2.Y;
                    float z = sin * p1.Z - cos * p2.Z;

                    var onePosition = new Vector3(pathPosition1.X + x, pathPosition1.Y + y, pathPosition1.Z + z);

                    var oneNormal = new Vector3(x, y, z);
                    oneNormal.Normalize();

                    vertexBuffer[vertexBufferIndex] = new PositionNormal(onePosition, oneNormal);
                    vertexBufferIndex++;
                }

                pathPosition1 = pathPosition2;
                lastDirection = pathSegmentDirection;
            }

            if (isTubeClosed)
            {
                // Fill the start circle with simple triangle strip
                for (int i = 1; i < segmentsCount - 1; i++)
                {
                    indexBuffer[indexBufferIndex]     = 0;
                    indexBuffer[indexBufferIndex + 1] = i + 1;
                    indexBuffer[indexBufferIndex + 2] = i;

                    indexBufferIndex += 3;
                }
            }

            // Setup triangle indices
            int startPos1 = 0;             // Start position on the previous circle
            int startPos2 = segmentsCount; // Start position on this circle

            // Code for no texture coordinates
            for (int i = 0; i < pathPositionsCount - 1; i++)
            {
                int pos1 = startPos1;
                int pos2 = startPos2;

                for (int j = 1; j < segmentsCount; j++)
                {
                    indexBuffer[indexBufferIndex]     = pos1;
                    indexBuffer[indexBufferIndex + 1] = pos1 + 1;
                    indexBuffer[indexBufferIndex + 2] = pos2;

                    indexBuffer[indexBufferIndex + 3] = pos1 + 1;
                    indexBuffer[indexBufferIndex + 4] = pos2 + 1;
                    indexBuffer[indexBufferIndex + 5] = pos2;

                    pos1++;
                    pos2++;
                    indexBufferIndex += 6;
                }

                // No texture coordinates
                indexBuffer[indexBufferIndex]     = pos1;
                indexBuffer[indexBufferIndex + 1] = startPos1;
                indexBuffer[indexBufferIndex + 2] = pos2;

                indexBuffer[indexBufferIndex + 3] = pos2;
                indexBuffer[indexBufferIndex + 4] = startPos1;
                indexBuffer[indexBufferIndex + 5] = startPos2;

                startPos1        += segmentsCount;
                startPos2        += segmentsCount;
                indexBufferIndex += 6;
            }

            if (isTubeClosed)
            {
                // Fill the end circle with simple triangle strip
                int lastCircleIndex = totalPositionsCount - segmentsCount;
                for (int i = 1; i < segmentsCount - 1; i++)
                {
                    indexBuffer[indexBufferIndex]     = lastCircleIndex;
                    indexBuffer[indexBufferIndex + 1] = lastCircleIndex + i;
                    indexBuffer[indexBufferIndex + 2] = lastCircleIndex + i + 1;

                    indexBufferIndex += 3;
                }
            }
        }
Exemple #9
0
        private void CreateMorphedMesh()
        {
            if (_simpleMesh == null)
            {
                return;
            }


            var meshPositions = _meshGeometry3D.Positions;
            var meshNormals   = _meshGeometry3D.Normals;

            var positionsCount = meshPositions.Count;

            // First store original positions into _originalMesh
            // This array will provide much faster access to morphed positions then if we would access the data from MeshGeometry3D object.
            var originalMesh = new PositionNormal[positionsCount];

            for (int i = 0; i < positionsCount; i++)
            {
                originalMesh[i].Position = meshPositions[i].ToVector3();
                originalMesh[i].Normal   = meshNormals[i].ToVector3();
            }

            _originalMesh = originalMesh;


            // Now create a copy of the original MeshGeometry3D (this is needed because after adjusting positions we also need to re-calculate normals)
            var morphedMeshGeometry3D = new MeshGeometry3D();

            // Copy positions from original MeshGeometry3D - we also adjust the y position of all positions that are above the center of the mesh

            double yOffset = _originalMeshSizeY;
            double yMiddle = _meshGeometry3D.Bounds.Y + _originalMeshSizeY / 2.0f; // get mesh center y value

            morphedMeshGeometry3D.Positions = null;                                // Disconnect positions before changing (to prevent change notifications from slowing things down)
            for (int i = 0; i < positionsCount; i++)
            {
                var onePosition = meshPositions[i];

                if (onePosition.Y > yMiddle)
                {
                    onePosition.Y += yOffset;
                }

                meshPositions[i] = onePosition;
            }

            morphedMeshGeometry3D.Positions = meshPositions;

            // Because we have changed the positions, this also changed the normal vectors.
            // We need to calculate normals again
            meshNormals = Ab3d.Utilities.MeshUtils.CalculateNormals(morphedMeshGeometry3D);
            morphedMeshGeometry3D.Normals = meshNormals;


            // After we have a morphed MeshGeometry, we can prepared an optimized list of positions and normals.
            _morphedMesh = new PositionNormal[positionsCount];

            for (int i = 0; i < positionsCount; i++)
            {
                _morphedMesh[i] = new PositionNormal(meshPositions[i].ToVector3(), meshNormals[i].ToVector3());
            }


            // We also need to store original and morphed bounding box (bounds)
            _originalBoundingBox = _meshGeometry3D.Bounds.ToBoundingBox();

            _morphedBoundingBox = new BoundingBox(_originalBoundingBox.Minimum,
                                                  new Vector3(_originalBoundingBox.Maximum.X, _originalBoundingBox.Maximum.Y + (float)yOffset, _originalBoundingBox.Maximum.Z));
        }