Ejemplo n.º 1
0
 /**
  * Flip triangle normal orientation.
  * */
 public static void Flip(ITriangleMesh mesh)
 {
     for (int i = 0; i < mesh.GetNumberOfTriangles(); i++)
     {
         mesh.GetTriangle(i).Flip();
     }
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Gets the enclosed volume of a triangle mesh.
        /// </summary>
        /// <param name="triangleMesh">The triangle mesh.</param>
        /// <returns>
        /// The enclosed volume of the given triangle mesh.
        /// </returns>
        /// <remarks>
        /// <para>
        /// This method assumes that the given triangle mesh is a closed mesh without holes.
        /// </para>
        /// <para>
        /// Remember: To compute the volume of a scaled mesh, you can compute the volume of the
        /// unscaled mesh and multiply the result with the scaling factors:
        /// </para>
        /// <para>
        /// <i>volume<sub>scaled</sub> = volume<sub>unscaled</sub> * scale<sub>X</sub> * scale<sub>Y</sub> * scale<sub>Z</sub></i>
        /// </para>
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="triangleMesh"/> is <see langword="null"/>.
        /// </exception>
        public static float GetVolume(this ITriangleMesh triangleMesh)
        {
            if (triangleMesh == null)
            {
                throw new ArgumentNullException("triangleMesh");
            }

            int numberOfTriangles = triangleMesh.NumberOfTriangles;

            if (numberOfTriangles == 0)
            {
                return(0);
            }

            // The reference points is on the first triangle. So the first tetrahedron has no volume.
            var   p      = triangleMesh.GetTriangle(0).Vertex0;
            float volume = 0;

            for (int i = 1; i < numberOfTriangles; i++)
            {
                var   triangle          = triangleMesh.GetTriangle(i);
                float tetrahedronVolume = GetSignedTetrahedronVolume(p, ref triangle);
                volume += tetrahedronVolume;
            }

            return(volume);
        }
Ejemplo n.º 3
0
        /**
         * Create cube.
         * */
        public static void CreateCube(ITriangleMesh mesh, float sideLength)
        {
            mesh.Clear();
            mesh.AddVertex(new Vector3(-sideLength / 2.0f, -sideLength / 2.0f, -sideLength / 2.0f));
            mesh.AddVertex(new Vector3(sideLength / 2.0f, -sideLength / 2.0f, -sideLength / 2.0f));
            mesh.AddVertex(new Vector3(sideLength / 2.0f, sideLength / 2.0f, -sideLength / 2.0f));
            mesh.AddVertex(new Vector3(-sideLength / 2.0f, sideLength / 2.0f, -sideLength / 2.0f));
            mesh.AddVertex(new Vector3(-sideLength / 2.0f, -sideLength / 2.0f, sideLength / 2.0f));
            mesh.AddVertex(new Vector3(sideLength / 2.0f, -sideLength / 2.0f, sideLength / 2.0f));
            mesh.AddVertex(new Vector3(sideLength / 2.0f, sideLength / 2.0f, sideLength / 2.0f));
            mesh.AddVertex(new Vector3(-sideLength / 2.0f, sideLength / 2.0f, sideLength / 2.0f));

            mesh.AddTriangle(new Triangle(0, 2, 1));
            mesh.AddTriangle(new Triangle(0, 3, 2));
            mesh.AddTriangle(new Triangle(1, 2, 5));
            mesh.AddTriangle(new Triangle(2, 6, 5));
            mesh.AddTriangle(new Triangle(4, 5, 6));
            mesh.AddTriangle(new Triangle(4, 6, 7));
            mesh.AddTriangle(new Triangle(4, 7, 0));
            mesh.AddTriangle(new Triangle(0, 7, 3));
            mesh.AddTriangle(new Triangle(3, 7, 2));
            mesh.AddTriangle(new Triangle(2, 7, 6));
            mesh.AddTriangle(new Triangle(4, 0, 1));
            mesh.AddTriangle(new Triangle(1, 5, 4));
            mesh.ComputeTriangleNormals();
        }
Ejemplo n.º 4
0
 public static void Translate(ITriangleMesh mesh, Vector3 translation)
 {
     for (int i = 0; i < mesh.GetNumberOfVertices(); i++)
     {
         mesh.SetVertex(i, Vector3.Add(mesh.GetVertex(i), translation));
     }
 }
Ejemplo n.º 5
0
        /**
         * Read an OBJ file an create a mesh from the content.
         * */
        public void Read(string filename, ITriangleMesh mesh)
        {
            this.mesh = mesh;
            mesh.Clear();

            // Read input
            string objSource = System.IO.File.ReadAllText(AssetPath.GetPathToAsset(filename));

            string[] lines = objSource.Split('\n');
            foreach (String line in lines)
            {
                string[] tokens = line.Trim().Split(' ', '\t');
                if (tokens.Length > 0)
                {
                    if (tokens [0].CompareTo("v") == 0)
                    {
                        ParseVertex(tokens);
                    }
                    else if (tokens [0].CompareTo("f") == 0)
                    {
                        ParseFacet(tokens);
                    }
                    else if (tokens [0].CompareTo("vt") == 0)
                    {
                        ParseTextureCoordinate(tokens);
                    }
                }
            }

            mesh.ComputeTriangleNormals();
            Console.WriteLine("Read mesh from file " + filename + " with " + mesh.GetNumberOfTriangles() + " triangles and " + mesh.GetNumberOfVertices() + " vertices.");
        }
Ejemplo n.º 6
0
    // Copy members of the given effector.
    protected override void CloneCore(ParticleEffector source)
    {
      base.CloneCore(source);

      var sourceTyped = (StartOnMeshEffector)source;
      Parameter = sourceTyped.Parameter;
      Mesh = sourceTyped.Mesh;
    }
Ejemplo n.º 7
0
        // Copy members of the given effector.
        protected override void CloneCore(ParticleEffector source)
        {
            base.CloneCore(source);

            var sourceTyped = (StartOnMeshEffector)source;

            Parameter = sourceTyped.Parameter;
            Mesh      = sourceTyped.Mesh;
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Decomposes the specified mesh.
        /// </summary>
        /// <param name="mesh">The mesh.</param>
        /// <remarks>
        /// This method blocks until the decomposition has finished. The result is available
        /// in the property <see cref="Decomposition"/>.
        /// </remarks>
        public void Decompose(ITriangleMesh mesh)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            _mesh = mesh;
            DoWork();
        }
Ejemplo n.º 9
0
        /**
         * Compute the normal of the border edge.
         * */
        private Vector3 ComputeBorderEdgeNormal(TriangleEdge edge, ITriangleMesh mesh)
        {
            Vector3 v0 = mesh.GetVertex(edge.A);
            Vector3 v1 = mesh.GetVertex(edge.B);
            Vector3 e  = Vector3.Subtract(v1, v0);
            Vector3 n  = Vector3.Cross(e, Vector3.UnitZ);

            n.Normalize();
            return(n);
        }
Ejemplo n.º 10
0
 public static void CreateSquare(ITriangleMesh mesh, float extend)
 {
     mesh.Clear();
     mesh.AddVertex(new Vector3(-extend, 0, -extend));
     mesh.AddVertex(new Vector3(extend, 0, -extend));
     mesh.AddVertex(new Vector3(extend, 0, extend));
     mesh.AddVertex(new Vector3(-extend, 0, extend));
     mesh.AddTriangle(0, 2, 1);
     mesh.AddTriangle(0, 3, 2);
     mesh.ComputeTriangleNormals();
 }
Ejemplo n.º 11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TriangleMeshShape"/> class from the given
        /// triangle mesh.
        /// </summary>
        /// <param name="mesh">The mesh.</param>
        /// <param name="enableContactWelding">
        /// If set to <see langword="true"/> contact welding is enabled; otherwise, the shape will not
        /// use contact welding. See <see cref="EnableContactWelding"/> for more information.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        public TriangleMeshShape(ITriangleMesh mesh, bool enableContactWelding)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            _mesh = mesh;

            EnableContactWelding = enableContactWelding;
        }
Ejemplo n.º 12
0
    public static Submesh CreateSubmesh(GraphicsDevice graphicsDevice, ITriangleMesh mesh, float angleLimit)
    {
      var tm = mesh as TriangleMesh;
      if (tm == null)
      {
        tm = new TriangleMesh();
        tm.Add(mesh);
        tm.WeldVertices();
      }

      return CreateSubmesh(graphicsDevice, tm, angleLimit);
    }
Ejemplo n.º 13
0
        /// <summary>
        /// Initializes a new instance of the <see cref="TriangleMeshShape"/> class from the given
        /// triangle mesh.
        /// </summary>
        /// <param name="mesh">The mesh.</param>
        /// <param name="enableContactWelding">
        /// If set to <see langword="true"/> contact welding is enabled; otherwise, the shape will not
        /// use contact welding. See <see cref="EnableContactWelding"/> for more information.
        /// </param>
        /// <param name="partition">
        /// The spatial partition (see <see cref="Partition"/>). Can be <see langword="null"/> if no
        /// partition should be used.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        public TriangleMeshShape(ITriangleMesh mesh, bool enableContactWelding, ISpatialPartition <int> partition)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            _mesh     = mesh;
            Partition = partition;

            EnableContactWelding = enableContactWelding;
        }
Ejemplo n.º 14
0
        /// <overloads>
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// </overloads>
        /// 
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// <param name="mesh">The triangle mesh.</param>
        /// <returns>
        /// The <see cref="DcelMesh"/>.
        /// </returns>
        /// <remarks>
        /// Currently, creating <see cref="DcelMesh"/>es is not supported if the triangle mesh consists
        /// of unconnected sub-meshes or unconnected triangles. All parts of the triangle mesh must be
        /// connected via an edge. (But it is not required that the mesh is closed.)
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="mesh"/> has no vertices or vertex indices.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// <paramref name="mesh"/> consists of several unconnected components or sub-meshes.
        /// </exception>
        public static DcelMesh FromTriangleMesh(ITriangleMesh mesh)
        {
            if (mesh == null)
            throw new ArgumentNullException("mesh");

              // The simple way: Create a TriangleMesh first.
              var triangleMesh = new TriangleMesh();
              triangleMesh.Add(mesh, false);
              triangleMesh.WeldVertices();

              return FromTriangleMesh(triangleMesh);
        }
Ejemplo n.º 15
0
        private ITriangleMesh CreateMiddle(ITriangleMesh mesh, List <Hexagon> borderHexagons, float sideLength)
        {
            ITriangleMesh bottomMesh = new TriangleMesh();

            foreach (Hexagon hex in borderHexagons)
            {
                ITriangleMesh hexMesh = hex.GenerateMesh();
                TriangleMeshFactory.Flip(hexMesh);
                TriangleMeshFactory.Unite(bottomMesh, hexMesh);
            }
            TriangleMeshFactory.Translate(bottomMesh, new Vector3(0, 0, -sideLength));
            return(bottomMesh);
        }
Ejemplo n.º 16
0
        public override void InitContent()
        {
            GetRoot().LightPosition = new Vector3(0, -2, 2);
            GetRoot().Animated      = true;
            IslandGenerator  gen  = new IslandGenerator();
            ITriangleMesh    mesh = gen.GenerateIslandMesh();
            TriangleMeshNode node = new TriangleMeshNode(mesh);

            node.ShowBorder = true;
            node.SetColor(Color4.DarkGreen);
            node.ShowNormals = false;
            GetRoot().AddChild(node);
        }
Ejemplo n.º 17
0
        public ITriangleMesh GenerateIslandMesh()
        {
            HexagonField field = new HexagonField();

            field.GenerateField();

            ITriangleMesh mesh = new TriangleMesh();

            // Top
            ITriangleMesh topMesh = CreateTopSurface(field.GetAllHexagons());

            TriangleMeshFactory.Unite(mesh, topMesh);

            // Grass
            float grassBorderHeight = field.SideLength * 0.1f;

            Vector2[]     grassBoundaryTexCoords = { new Vector2(0.1f, 0.1f), new Vector2(0.1f, 0.2f), new Vector2(0.2f, 0.1f), new Vector2(0.2f, 0.2f) };
            ITriangleMesh grassBoundary          = CreateBoundary(mesh, field.SideLength, grassBorderHeight, grassBorderHeight, new Vector3(0, 0, 0), grassBoundaryTexCoords);

            TriangleMeshFactory.Unite(mesh, grassBoundary);

            // Middle-bottom
            ITriangleMesh middleMesh = CreateMiddle(mesh, field.GetBorderHexagons(), field.SideLength);

            TriangleMeshFactory.Unite(mesh, middleMesh);

            ITriangleMesh bottomMesh = CreateTopSurface(field.GetNonBorderHexagons());

            // Mud
            float mudHeight       = 2 * field.SideLength;
            float mudBorderHeight = field.SideLength * 0.3f;

            Vector2[]     mudBoundaryTexCoords = { new Vector2(0.7f, 0.1f), new Vector2(0.7f, 0.2f), new Vector2(0.8f, 0.1f), new Vector2(0.8f, 0.2f) };
            ITriangleMesh mudBoundary          = CreateBoundary(bottomMesh, mudHeight, 0, mudBorderHeight, new Vector3(0, 0, 0), mudBoundaryTexCoords);

            TriangleMeshFactory.Translate(mudBoundary, new Vector3(0, 0, -field.SideLength));
            TriangleMeshFactory.Unite(mesh, mudBoundary);

            // Bottom
            TriangleMeshFactory.Flip(bottomMesh);
            TriangleMeshFactory.Translate(bottomMesh, new Vector3(0, 0, -(mudHeight + field.SideLength)));
            TriangleMeshFactory.Unite(mesh, bottomMesh);

            mesh = TriangleMeshFactory.Snap(mesh, 1e-5f);

            mesh.ComputeTriangleNormals();
            mesh.SetTexture(new Texture("textures/island.png"));
            return(mesh);
        }
Ejemplo n.º 18
0
        /// <overloads>
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// </overloads>
        ///
        /// <summary>
        /// Converts the given <see cref="ITriangleMesh"/> to a <see cref="DcelMesh"/>.
        /// </summary>
        /// <param name="mesh">The triangle mesh.</param>
        /// <returns>
        /// The <see cref="DcelMesh"/>.
        /// </returns>
        /// <remarks>
        /// Currently, creating <see cref="DcelMesh"/>es is not supported if the triangle mesh consists
        /// of unconnected sub-meshes or unconnected triangles. All parts of the triangle mesh must be
        /// connected via an edge. (But it is not required that the mesh is closed.)
        /// </remarks>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="mesh"/> is <see langword="null"/>.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="mesh"/> has no vertices or vertex indices.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// <paramref name="mesh"/> consists of several unconnected components or sub-meshes.
        /// </exception>
        public static DcelMesh FromTriangleMesh(ITriangleMesh mesh)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            // The simple way: Create a TriangleMesh first.
            var triangleMesh = new TriangleMesh();

            triangleMesh.Add(mesh, false);
            triangleMesh.WeldVertices();

            return(FromTriangleMesh(triangleMesh));
        }
Ejemplo n.º 19
0
        // Handling of non-uniform scaling:
        // http://en.wikipedia.org/wiki/Scaling_(geometry) about non-uniform scaling:
        // "Such a scaling changes ... the volume by the product of all three [scale factors]."


        /// <summary>
        /// Gets the contact of ray with a triangle mesh.
        /// </summary>
        /// <param name="triangleMesh">The triangle mesh.</param>
        /// <param name="ray">The ray.</param>
        /// <param name="hitDistance">
        /// The hit distance. This is the distance on the ray from the ray origin to the contact.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the ray hits the front face of a triangle mesh triangle;
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// <remarks>
        /// This method returns any contact, not necessarily the first contact of the ray with the
        /// triangle mesh! The mesh triangles are treated as one-sided.
        /// </remarks>
        internal static bool GetContact(ITriangleMesh triangleMesh, Ray ray, out float hitDistance)
        {
            for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
            {
                var  triangle = triangleMesh.GetTriangle(i);
                bool hit      = GetContact(ray, triangle, false, out hitDistance);
                if (hit)
                {
                    return(true);
                }
            }

            hitDistance = float.NaN;
            return(false);
        }
Ejemplo n.º 20
0
        public void Add(ITriangleMesh mesh, bool weldVerticesBruteForce)
        {
            var triangleMesh = mesh as TriangleMesh;

            if (triangleMesh != null && !weldVerticesBruteForce)
            {
                // Special: mesh is TriangleMesh and no welding.

                if (triangleMesh.Vertices == null)
                {
                    return;
                }
                if (triangleMesh.Indices == null)
                {
                    return;
                }

                if (Vertices == null)
                {
                    Vertices = new List <Vector3>(triangleMesh.Vertices.Count);
                }

                int numberOfNewIndices = triangleMesh.Indices.Count;
                if (Indices == null)
                {
                    Indices = new List <int>(numberOfNewIndices);
                }

                // Add new vertices.
                int oldNumberOfVertices = Vertices.Count;
                Vertices.AddRange(triangleMesh.Vertices);

                // Add new indices. Add offset to all indices.
                for (int i = 0; i < numberOfNewIndices; i++)
                {
                    Indices.Add(triangleMesh.Indices[i] + oldNumberOfVertices);
                }

                return;
            }

            int numberOfTriangles = mesh.NumberOfTriangles;

            for (int i = 0; i < numberOfTriangles; i++)
            {
                Add(mesh.GetTriangle(i), weldVerticesBruteForce);
            }
        }
Ejemplo n.º 21
0
        /**
         * Create the mesh for the top.
         * */
        private ITriangleMesh CreateTopSurface(List <Hexagon> hexagons)
        {
            ITriangleMesh mesh = new TriangleMesh();

            foreach (Hexagon hex in hexagons)
            {
                if (!hex.ConsistencyCheck())
                {
                    Console.WriteLine("Inconsistency detected!");
                }
                ITriangleMesh hexMesh = hex.GenerateMesh();
                TriangleMeshFactory.Unite(mesh, hexMesh);
            }
            mesh = TriangleMeshFactory.Snap(mesh, 1e-5f);
            return(mesh);
        }
Ejemplo n.º 22
0
        /// <inheritdoc/>
        protected override void CloneCore(Shape sourceShape)
        {
            var source = (TriangleMeshShape)sourceShape;

            _mesh = source.Mesh;

            if (source.Partition != null)
            {
                Partition = source.Partition.Clone();
            }

            if (source.TriangleNeighbors != null)
            {
                TriangleNeighbors = new List <int>(source.TriangleNeighbors);
            }
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Decomposes the specified mesh (asynchronously).
        /// </summary>
        /// <param name="mesh">The mesh.</param>
        /// <remarks>
        /// <para>
        /// This method does not block. The flag <see cref="IsBusy"/> is set until the decomposition has
        /// finished. The event <see cref="ProgressChanged"/> informs you on the current progress. The
        /// event <see cref="Completed"/> is raised when the decomposition is finished. The current
        /// intermediate decomposition result is available in <see cref="Decomposition"/>. Retrieving
        /// the result while the decomposition is running is possible but will temporarily block the
        /// decomposition process.
        /// </para>
        /// <para>
        /// <strong>Thread-Safety:</strong><br/>
        /// The <paramref name="mesh"/> must not be modified while the decomposition is in progress.
        /// </para>
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        /// Convex decomposition is already in progress.
        /// </exception>
        public void DecomposeAsync(ITriangleMesh mesh)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }
            if (IsBusy)
            {
                throw new InvalidOperationException("Convex decomposition is already in progress.");
            }

            _mesh   = mesh;
            _cancel = false;
            IsBusy  = true;

            Parallel.Start(DoWork);
        }
Ejemplo n.º 24
0
        public static ITriangleMesh Snap(ITriangleMesh mesh, float epsilon)
        {
            Dictionary <int, int> vertexMapping = new Dictionary <int, int>();
            ITriangleMesh         result        = new TriangleMesh();

            for (int i = 0; i < mesh.GetNumberOfVertices(); i++)
            {
                Vector3 vi    = mesh.GetVertex(i);
                bool    found = false;
                for (int j = 0; j < result.GetNumberOfVertices(); j++)
                {
                    Vector3 vj = result.GetVertex(j);
                    if (Vector3.Subtract(vi, vj).Length < epsilon)
                    {
                        vertexMapping[i] = j;
                        found            = true;
                    }
                }
                if (!found)
                {
                    int idx = result.AddVertex(vi);
                    vertexMapping[i] = idx;
                }
            }

            for (int i = 0; i < mesh.GetNumberOfTexCoords(); i++)
            {
                result.AddTextureCoordinate(mesh.GetTextureCoordinate(i));
            }

            for (int i = 0; i < mesh.GetNumberOfTriangles(); i++)
            {
                Triangle t = mesh.GetTriangle(i).Clone();
                t.A = vertexMapping[t.A];
                t.B = vertexMapping[t.B];
                t.C = vertexMapping[t.C];
                result.AddTriangle(t);
            }

            Console.WriteLine("Mesh snapping: " + mesh.GetNumberOfVertices() + " -> " + result.GetNumberOfVertices() + " verts.");
            return(result);
        }
Ejemplo n.º 25
0
        /**
         * Generated the unification of two meshes. Attention: no new mesh is generated, in fact the
         * geometry of mesh2 is added to mesh1.
         */
        public static void Unite(ITriangleMesh mesh1, ITriangleMesh mesh2)
        {
            int numberOfVertsMesh1     = mesh1.GetNumberOfVertices();
            int numberOfTexCoordsMesh1 = mesh1.GetNumberOfTexCoords();

            for (int i = 0; i < mesh2.GetNumberOfVertices(); i++)
            {
                mesh1.AddVertex(mesh2.GetVertex(i));
            }
            for (int i = 0; i < mesh2.GetNumberOfTexCoords(); i++)
            {
                mesh1.AddTextureCoordinate(mesh2.GetTextureCoordinate(i));
            }
            for (int i = 0; i < mesh2.GetNumberOfTriangles(); i++)
            {
                Triangle t = mesh2.GetTriangle(i).Clone();
                t.VertexIndexOffset(numberOfVertsMesh1);
                t.TexCoordsIndexOffset(numberOfTexCoordsMesh1);
                mesh1.AddTriangle(t);
            }
            mesh1.ComputeTriangleNormals();
        }
Ejemplo n.º 26
0
        public TriangleLight(RayEngineScene sc, int triIndex, ITriangleMesh mesh, RgbSpectrum gain = new RgbSpectrum())
            : this(sc, string.Empty, gain)
        {
            Gain = (RgbSpectrumInfo)gain;

            triangleIndex = triIndex;

            this.Owner = mesh;


            //Configuration.Instance.Get("Integrator.ComputeNormals", false);
            //Configuration.Instance.Get("Integrator.InverseLightNormals", false);

            var multiplicator = normalInverse ? -1f : 1f;
            this.TriangleNormal = multiplicator * ((computeNormal || !mesh.HasNormals) ? scene.Triangles[triangleIndex].ComputeNormal(scene.Vertices)
                : (Normal)scene.SceneGeometry.Normals[Math.Min(scene.SceneGeometry.Normals.Length - 1, triIndex)]);
            this.area = Math.Max(scene.Triangles[triangleIndex].AreaV(scene.Vertices), 0.00001f);
            Assert.IsNotNaN(this.TriangleNormal.x);
            Assert.IsTrue(this.area > 0f);
            lightSpectra = GlobalConfiguration.Instance.SpectralRendering ? (ISpectrum)spectra : gain;

        }
Ejemplo n.º 27
0
        /**
         * Create sphere.
         * */
        public static void CreateSphere(ITriangleMesh mesh, float radius, int resolution)
        {
            mesh.Clear();
            float dTheta = (float)(Math.PI / (resolution + 1));
            float dPhi   = (float)(Math.PI * 2.0 / resolution);

            // Create vertices

            // 0-180 degrees: i, theta
            for (int i = 0; i < resolution; i++)
            {
                // 0-360 degres: j, phi
                for (int j = 0; j < resolution; j++)
                {
                    Vector3 p0 = EvaluateSpherePoint((i + 1) * dTheta, j * dPhi, radius);
                    mesh.AddVertex(p0);
                }
            }
            int leftIndex  = mesh.AddVertex(new Vector3(0, 0, radius));
            int rightIndex = mesh.AddVertex(new Vector3(0, 0, -radius));

            // Add triangles
            for (int i = 0; i < resolution - 1; i++)
            {
                for (int j = 0; j < resolution; j++)
                {
                    mesh.AddTriangle(GetSphereIndex(i, j, resolution), GetSphereIndex(i + 1, j, resolution), GetSphereIndex(i + 1, j + 1, resolution));
                    mesh.AddTriangle(GetSphereIndex(i, j, resolution), GetSphereIndex(i + 1, j + 1, resolution), GetSphereIndex(i, j + 1, resolution));
                }
            }
            for (int j = 0; j < resolution; j++)
            {
                mesh.AddTriangle(GetSphereIndex(0, j, resolution), GetSphereIndex(0, (j + 1) % resolution, resolution), leftIndex);
                mesh.AddTriangle(GetSphereIndex(resolution - 1, j, resolution), rightIndex, GetSphereIndex(resolution - 1, (j + 1) % resolution, resolution));
            }

            mesh.ComputeTriangleNormals();
        }
Ejemplo n.º 28
0
        public void CreateShadowPolygons(Vector3 lightPosition, float extend, ITriangleMesh shadowPolygonMesh)
        {
            shadowPolygonMesh.Clear();
            ArrayList silhouetteEdges = GetSilhouette(lightPosition);

            for (int i = 0; i < silhouetteEdges.Count; i++)
            {
                Edge    edge   = (Edge)silhouetteEdges[i];
                Vector3 v0     = GetVertex(edge.a);
                Vector3 v1     = GetVertex(edge.b);
                Vector3 dv0    = Vector3.Multiply(Vector3.Subtract(v0, lightPosition).Normalized(), extend);
                Vector3 dv1    = Vector3.Multiply(Vector3.Subtract(v1, lightPosition).Normalized(), extend);
                Vector3 v0Dash = Vector3.Add(v0, dv0);
                Vector3 v1Dash = Vector3.Add(v1, dv1);

                int v0Index     = shadowPolygonMesh.AddVertex(v0);
                int v1Index     = shadowPolygonMesh.AddVertex(v1);
                int v0DashIndex = shadowPolygonMesh.AddVertex(v0Dash);
                int v1DashIndex = shadowPolygonMesh.AddVertex(v1Dash);
                shadowPolygonMesh.AddTriangle(v0Index, v0DashIndex, v1DashIndex);
                shadowPolygonMesh.AddTriangle(v0Index, v1DashIndex, v1Index);
            }
            shadowPolygonMesh.ComputeTriangleNormals();
        }
Ejemplo n.º 29
0
        // Computes the surface covariance matrix for a convex hull of the given points.
        private static MatrixF ComputeCovarianceMatrixFromSurface(ITriangleMesh mesh)
        {
            // Compute covariance matrix for the surface of the triangle mesh.
              // See Physics-Based Animation for a derivation. Variable names are the same as in
              // the book.
              // ... Better look at Real-Time Collision Detection p. 108. The Physics-Based Animation
              // book has errors.

              MatrixF C = new MatrixF(3, 3);          // The covariance matrix.
              float A = 0;                            // Total surface area.
              Vector3F mS = Vector3F.Zero;            // Mean point of the entire surface.
              for (int k = 0; k < mesh.NumberOfTriangles; k++)
              {
            var triangle = mesh.GetTriangle(k);
            var pK = triangle.Vertex0;
            var qK = triangle.Vertex1;
            var rK = triangle.Vertex2;

            var mK = 1f / 3f * (pK + qK + rK);

            var uK = qK - pK;
            var vK = rK - pK;
            var Ak = 0.5f * Vector3F.Cross(uK, vK).Length;
            A += Ak;

            mS += Ak * mK;

            for (int i = 0; i < 3; i++)
              for (int j = i; j < 3; j++)
            C[i, j] += Ak / 12f * (9 * mK[i] * mK[j]
                                     + pK[i] * pK[j]
                                     + qK[i] * qK[j]
                                     + rK[i] * rK[j]);
              }

              mS /= A;

              for (int i = 0; i < 3; i++)
            for (int j = i; j < 3; j++)
              C[i, j] = 1 / A * C[i, j] - mS[i] * mS[j];

              // Set the other half of the symmetric matrix.
              for (int i = 0; i < 3; i++)
            for (int j = i + 1; j < 3; j++)
              C[j, i] = C[i, j];

              return C;
        }
Ejemplo n.º 30
0
        public static Submesh CreateSubmesh(GraphicsDevice graphicsDevice, ITriangleMesh mesh, float angleLimit)
        {
            var tm = mesh as TriangleMesh;
              if (tm == null)
              {
            tm = new TriangleMesh();
            tm.Add(mesh);
            tm.WeldVertices();
              }

              return CreateSubmesh(graphicsDevice, tm, angleLimit);
        }
        //--------------------------------------------------------------
        #region Methods
        //--------------------------------------------------------------

        protected override void OnLoad()
        {
            // Add rigid bodies to simulation.
            var simulation = _services.GetInstance <Simulation>();

            // We use a random number generator with a custom seed.
            RandomHelper.Random = new Random(123);

            // ----- Add a ground plane.
            AddBody(simulation, "GroundPlane", Pose.Identity, new PlaneShape(Vector3F.UnitY, 0), MotionType.Static);

            // ----- Create a small flying sphere.
            AddBody(simulation, "Sphere", new Pose(new Vector3F(0, 1f, 0)), new SphereShape(0.2f), MotionType.Static);

            // ----- Create small walls at the level boundary.
            AddBody(simulation, "WallLeft", new Pose(new Vector3F(-30, 1, 0)), new BoxShape(0.3f, 2, 60), MotionType.Static);
            AddBody(simulation, "WallRight", new Pose(new Vector3F(30, 1, 0)), new BoxShape(0.3f, 2, 60), MotionType.Static);
            AddBody(simulation, "WallFront", new Pose(new Vector3F(0, 1, -30)), new BoxShape(60, 2, 0.3f), MotionType.Static);
            AddBody(simulation, "WallBack", new Pose(new Vector3F(0, 1, 30)), new BoxShape(60, 2, 0.3f), MotionType.Static);

            // ----- Create a few bigger objects.
            // We position the boxes so that we have a few corners we can run into. Character controllers
            // should be stable when the user runs into corners.
            AddBody(simulation, "House0", new Pose(new Vector3F(10, 1, -10)), new BoxShape(8, 2, 8f), MotionType.Static);
            AddBody(simulation, "House1", new Pose(new Vector3F(13, 1, -4)), new BoxShape(2, 2, 4), MotionType.Static);
            AddBody(simulation, "House2", new Pose(new Vector3F(10, 2, -15), Matrix33F.CreateRotationY(-0.3f)), new BoxShape(8, 4, 2), MotionType.Static);

            // ----- Create stairs with increasing step height.
            // Each step is a box. With this object we can test if our character can climb up
            // stairs. The character controller has a step height limit. Increasing step heights
            // let us test if the step height limit works.
            float       startHeight = 0;
            const float stepDepth   = 1f;

            for (int i = 0; i < 10; i++)
            {
                float    stepHeight = 0.1f + i * 0.05f;
                Vector3F position   = new Vector3F(0, startHeight + stepHeight / 2, -2 - i * stepDepth);
                AddBody(simulation, "Step" + i, new Pose(position), new BoxShape(2, stepHeight, stepDepth), MotionType.Static);

                startHeight += stepHeight;
            }

            // ----- V obstacle to test if we get stuck.
            AddBody(simulation, "V0", new Pose(new Vector3F(-5.5f, 0, 10), QuaternionF.CreateRotationZ(0.2f)), new BoxShape(1f, 2f, 2), MotionType.Static);
            AddBody(simulation, "V1", new Pose(new Vector3F(-4, 0, 10), QuaternionF.CreateRotationZ(-0.2f)), new BoxShape(1f, 2f, 2), MotionType.Static);

            // ----- Create a height field.
            // Terrain that is uneven is best modeled with a height field. Height fields are faster
            // than general triangle meshes.
            // The height direction is the y direction.
            // The height field lies in the x/z plane.
            var numberOfSamplesX = 20;
            var numberOfSamplesZ = 20;
            var samples          = new float[numberOfSamplesX * numberOfSamplesZ];

            // Create arbitrary height values.
            for (int z = 0; z < numberOfSamplesZ; z++)
            {
                for (int x = 0; x < numberOfSamplesX; x++)
                {
                    if (x == 0 || z == 0 || x == 19 || z == 19)
                    {
                        // Set this boundary elements to a low height, so that the height field is connected
                        // to the ground.
                        samples[z * numberOfSamplesX + x] = -1;
                    }
                    else
                    {
                        // A sine/cosine function that creates some interesting waves.
                        samples[z * numberOfSamplesX + x] = 1.0f + (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 1.0f);
                    }
                }
            }
            var heightField = new HeightField(0, 0, 20, 20, samples, numberOfSamplesX, numberOfSamplesZ);

            AddBody(simulation, "HeightField", new Pose(new Vector3F(10, 0, 10)), heightField, MotionType.Static);

            // ----- Create rubble on the floor (small random objects on the floor).
            // Our character should be able to move over small bumps on the ground.
            for (int i = 0; i < 50; i++)
            {
                Vector3F    position    = new Vector3F(RandomHelper.Random.NextFloat(-5, 5), 0, RandomHelper.Random.NextFloat(10, 20));
                QuaternionF orientation = RandomHelper.Random.NextQuaternionF();
                Vector3F    size        = RandomHelper.Random.NextVector3F(0.05f, 0.8f);
                AddBody(simulation, "Stone" + i, new Pose(position, orientation), new BoxShape(size), MotionType.Static);
            }

            // ----- Create some slopes to see how our character performs on/under sloped surfaces.
            // Here we can test how the character controller behaves if the head touches an inclined
            // ceiling.
            AddBody(simulation, "SlopeGround", new Pose(new Vector3F(-2, 1.8f, -12), QuaternionF.CreateRotationX(0.4f)), new BoxShape(2, 0.5f, 10), MotionType.Static);
            AddBody(simulation, "SlopeRoof", new Pose(new Vector3F(-2, 5.6f, -12), QuaternionF.CreateRotationX(-0.4f)), new BoxShape(2, 0.5f, 10), MotionType.Static);

            // Create slopes with increasing tilt angles.
            // The character controller has a slope limit. Only flat slopes should be climbable.
            // Movement between slopes should be smooth.
            Vector3F slopePosition = new Vector3F(-17, -0.25f, 6);
            BoxShape slopeShape    = new BoxShape(8, 0.5f, 5);

            for (int i = 1; i < 8; i++)
            {
                Matrix33F oldRotation = Matrix33F.CreateRotationX((i - 1) * MathHelper.ToRadians(10));
                Matrix33F rotation    = Matrix33F.CreateRotationX(i * MathHelper.ToRadians(10));

                slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2
                                 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2;

                AddBody(simulation, "Slope" + i, new Pose(slopePosition, rotation), slopeShape, MotionType.Static);
            }

            // Create slopes with decreasing tilt angles.
            slopePosition = new Vector3F(-8, -2, 5);
            slopeShape    = new BoxShape(8f, 0.5f, 5);
            for (int i = 1; i < 8; i++)
            {
                Matrix33F oldRotation = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - (i - 1) * MathHelper.ToRadians(10));
                Matrix33F rotation    = Matrix33F.CreateRotationX(MathHelper.ToRadians(40) - i * MathHelper.ToRadians(10));

                slopePosition += (oldRotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2
                                 + (rotation * new Vector3F(0, 0, -slopeShape.WidthZ)) / 2;
                Vector3F position = slopePosition - rotation * new Vector3F(0, slopeShape.WidthY / 2, 0);

                AddBody(simulation, "Slope2" + i, new Pose(position, rotation), slopeShape, MotionType.Static);
            }

            // ----- Create a slope with a wall on one side.
            // This objects let's us test how the character controller behaves while falling and
            // sliding along a vertical wall. (Run up the slope and then jump down while moving into
            // the wall.)
            AddBody(simulation, "LongSlope", new Pose(new Vector3F(-24, 3, -10), Matrix33F.CreateRotationX(0.4f)), new BoxShape(4, 5f, 30), MotionType.Static);
            AddBody(simulation, "LongSlopeWall", new Pose(new Vector3F(-26, 5, -10)), new BoxShape(0.5f, 10f, 25), MotionType.Static);

            // ----- Create a trigger object that represents a ladder.
            var ladder = AddBody(simulation, "Ladder", new Pose(new Vector3F(-25.7f, 5, 0)), new BoxShape(0.5f, 10f, 1), MotionType.Static);

            ladder.CollisionObject.Type = CollisionObjectType.Trigger;

            // ----- Create a mesh object to test walking on triangle meshes.
            // Normally, the mesh would be loaded from a file. Here, we make a composite shape and
            // let DigitalRune Geometry compute a mesh for it. Then we throw away the composite
            // shape and use only the mesh. (We do this to test triangle meshes. Using the composite
            // shape instead of the triangle mesh would be a lot faster.)
            CompositeShape compositeShape = new CompositeShape();

            compositeShape.Children.Add(new GeometricObject(heightField, Pose.Identity));
            compositeShape.Children.Add(new GeometricObject(new CylinderShape(1, 2), new Pose(new Vector3F(10, 1, 10))));
            compositeShape.Children.Add(new GeometricObject(new SphereShape(3), new Pose(new Vector3F(15, 0, 15))));
            compositeShape.Children.Add(new GeometricObject(new BoxShape(4, 4, 3), new Pose(new Vector3F(15, 1.5f, 5))));
            compositeShape.Children.Add(new GeometricObject(new BoxShape(4, 4, 3), new Pose(new Vector3F(15, 1.5f, 0))));
            ITriangleMesh     mesh      = compositeShape.GetMesh(0.01f, 3);
            TriangleMeshShape meshShape = new TriangleMeshShape(mesh);

            // Collision detection speed for triangle meshes can be improved by using a spatial
            // partition. Here, we assign an AabbTree to the triangle mesh shape. The tree is
            // built automatically when needed and it stores triangle indices (therefore the generic
            // parameter of the AabbTree is int).
            meshShape.Partition = new AabbTree <int>()
            {
                // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up
                // building is slower but produces better trees. If the tree building takes too long,
                // we can lower the BottomUpBuildThreshold (default is 128).
                BottomUpBuildThreshold = 0,
            };

            // Contact welding creates smoother contact normals - but it costs a bit of performance.
            meshShape.EnableContactWelding = true;

            AddBody(simulation, "Mesh", new Pose(new Vector3F(-30, 0, 10)), meshShape, MotionType.Static);

            // ----- Create a seesaw.
            var seesawBase = AddBody(simulation, "SeesawBase", new Pose(new Vector3F(5, 0.5f, 0)), new BoxShape(0.2f, 1, 1), MotionType.Static);
            var seesaw     = AddBody(simulation, "Seesaw", new Pose(new Vector3F(5, 1.05f, 0)), new BoxShape(5, 0.1f, 1), MotionType.Dynamic);

            // Attach the seesaw to the base using a hinge joint.
            simulation.Constraints.Add(new HingeJoint
            {
                BodyA            = seesaw,
                BodyB            = seesawBase,
                AnchorPoseALocal = new Pose(new Vector3F(0, 0, 0),
                                            new Matrix33F(0, 0, -1,
                                                          0, 1, 0,
                                                          1, 0, 0)),
                AnchorPoseBLocal = new Pose(new Vector3F(0, 0.5f, 0),
                                            new Matrix33F(0, 0, -1,
                                                          0, 1, 0,
                                                          1, 0, 0)),
                CollisionEnabled = false,
            });

            // ----- A platform that is moving up/down.
            _elevator = AddBody(simulation, "Elevator", new Pose(new Vector3F(5, -1f, 5)), new BoxShape(3, 1f, 3), MotionType.Kinematic);
            _elevator.LinearVelocity = new Vector3F(2, 2, 0);

            // ----- A platform that is moving sideways.
            _pusher = AddBody(simulation, "Pusher", new Pose(new Vector3F(15, 0.5f, 0)), new BoxShape(3, 1f, 3), MotionType.Kinematic);
            _pusher.LinearVelocity = new Vector3F(0, 0, 2);

            // ----- Create conveyor belt with two static boxes on the sides.
            AddBody(simulation, "ConveyorSide0", new Pose(new Vector3F(19, 0.25f, 0)), new BoxShape(0.8f, 0.5f, 8f), MotionType.Static);
            AddBody(simulation, "ConveyorSide1", new Pose(new Vector3F(21, 0.25f, 0)), new BoxShape(0.8f, 0.5f, 8f), MotionType.Static);

            // The conveyor belt is a simple box with a special material.
            var             conveyorBelt = AddBody(simulation, "ConveyorBelt", new Pose(new Vector3F(20, 0.25f, 0)), new BoxShape(1f, 0.51f, 8f), MotionType.Static);
            UniformMaterial materialWithSurfaceMotion = new UniformMaterial("ConveyorBelt", true) // Important: The second parameter enables the surface
            {                                                                                     // motion. It has to be set to true in the constructor!
                SurfaceMotion = new Vector3F(0, 0, 1),                                            // The surface motion relative to the object.
            };

            conveyorBelt.Material = materialWithSurfaceMotion;

            // ----- Distribute a few dynamic spheres and boxes across the landscape.
            SphereShape sphereShape = new SphereShape(0.5f);

            for (int i = 0; i < 10; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-15, 15);
                position.Y = 20;

                AddBody(simulation, "Sphere" + i, new Pose(position), sphereShape, MotionType.Dynamic);
            }

            BoxShape boxShape = new BoxShape(1, 1, 1);

            for (int i = 0; i < 10; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-15, 15);
                position.Y = 20;

                AddBody(simulation, "Box" + i, new Pose(position), boxShape, MotionType.Dynamic);
            }
        }
Ejemplo n.º 32
0
    //--------------------------------------------------------------
    #region Methods
    //--------------------------------------------------------------

#if XNA || MONOGAME
    /// <summary>
    /// Sets the triangle mesh. (For use by the content pipeline only.)
    /// </summary>
    /// <param name="mesh">The triangle mesh.</param>
    internal void SetMesh(ITriangleMesh mesh)
    {
      _mesh = mesh;
    }
Ejemplo n.º 33
0
        public static void GetMass(ITriangleMesh mesh, out float mass, out Vector3F centerOfMass, out Matrix33F inertia)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            // Integral variables.
            float i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;

            int numberOfTriangles = mesh.NumberOfTriangles;

            for (int triangleIndex = 0; triangleIndex < numberOfTriangles; triangleIndex++)
            {
                var triangle = mesh.GetTriangle(triangleIndex);

                // Vertex coordinates.
                Vector3F v0 = triangle.Vertex0;
                Vector3F v1 = triangle.Vertex1;
                Vector3F v2 = triangle.Vertex2;

                // Edges and cross products of edges
                Vector3F a = v1 - v0;
                Vector3F b = v2 - v0;
                Vector3F d = Vector3F.Cross(a, b);

                // Compute integral terms.
                float f1x, f2x, f3x, g0x, g1x, g2x;
                ComputePolyhedronMassSubExpressions(v0.X, v1.X, v2.X, out f1x, out f2x, out f3x, out g0x, out g1x, out g2x);
                float f1y, f2y, f3y, g0y, g1y, g2y;
                ComputePolyhedronMassSubExpressions(v0.Y, v1.Y, v2.Y, out f1y, out f2y, out f3y, out g0y, out g1y, out g2y);
                float f1z, f2z, f3z, g0z, g1z, g2z;
                ComputePolyhedronMassSubExpressions(v0.Z, v1.Z, v2.Z, out f1z, out f2z, out f3z, out g0z, out g1z, out g2z);

                // Update integrals.
                i0 += d.X * f1x;
                i1 += d.X * f2x;
                i2 += d.Y * f2y;
                i3 += d.Z * f2z;
                i4 += d.X * f3x;
                i5 += d.Y * f3y;
                i6 += d.Z * f3z;
                i7 += d.X * (v0.Y * g0x + v1.Y * g1x + v2.Y * g2x);
                i8 += d.Y * (v0.Z * g0y + v1.Z * g1y + v2.Z * g2y);
                i9 += d.Z * (v0.X * g0z + v1.X * g1z + v2.X * g2z);
            }

            i0 /= 6.0f;
            i1 /= 24.0f;
            i2 /= 24.0f;
            i3 /= 24.0f;
            i4 /= 60.0f;
            i5 /= 60.0f;
            i6 /= 60.0f;
            i7 /= 120.0f;
            i8 /= 120.0f;
            i9 /= 120.0f;

            mass = i0;

            centerOfMass = 1.0f / mass * new Vector3F(i1, i2, i3);
            // Clamp to zero.
            if (Numeric.IsZero(centerOfMass.X))
            {
                centerOfMass.X = 0;
            }
            if (Numeric.IsZero(centerOfMass.Y))
            {
                centerOfMass.Y = 0;
            }
            if (Numeric.IsZero(centerOfMass.Z))
            {
                centerOfMass.Z = 0;
            }

            // Inertia around the world origin.
            inertia.M00 = i5 + i6;
            inertia.M11 = i4 + i6;
            inertia.M22 = i4 + i5;
            inertia.M01 = inertia.M10 = Numeric.IsZero(i7) ? 0 : -i7;
            inertia.M12 = inertia.M21 = Numeric.IsZero(i8) ? 0 : -i8;
            inertia.M02 = inertia.M20 = Numeric.IsZero(i9) ? 0 : -i9;

            // Inertia around center of mass.
            inertia = GetUntranslatedMassInertia(mass, inertia, centerOfMass);
        }
Ejemplo n.º 34
0
        //--------------------------------------------------------------
        /// <summary>
        /// Decomposes the specified mesh.
        /// </summary>
        /// <param name="mesh">The mesh.</param>
        /// <remarks>
        /// This method blocks until the decomposition has finished. The result is available
        /// in the property <see cref="Decomposition"/>.
        /// </remarks>
        public void Decompose(ITriangleMesh mesh)
        {
            if (mesh == null)
            throw new ArgumentNullException("mesh");

              _mesh = mesh;
              DoWork();
        }
        public RollingSphereSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            // To demonstrate the problems with triangle meshes we increase the gravity and let a
            // sphere roll over a curved surface.

            // Add basic force effects.
            Simulation.ForceEffects.Add(new Gravity {
                Acceleration = new Vector3(0, -30, 0)
            });                                                                             // Higher gravity to make the problem more visible.
            Simulation.ForceEffects.Add(new Damping());

            // Use the custom contact filter to improve sphere contacts.
            _sphereContactFilter = new SphereContactFilter();
            Simulation.CollisionDomain.CollisionDetection.ContactFilter = _sphereContactFilter;

            // The triangle mesh could be loaded from a file, such as an XNA Model.
            // In this example will create a height field and convert the height field into a triangle mesh.
            var numberOfSamplesX = 60;
            var numberOfSamplesZ = 10;
            var samples          = new float[numberOfSamplesX * numberOfSamplesZ];

            for (int z = 0; z < numberOfSamplesZ; z++)
            {
                for (int x = 0; x < numberOfSamplesX; x++)
                {
                    samples[z * numberOfSamplesX + x] = (float)(Math.Sin(x / 6f) * 10f + 5f);
                }
            }

            var heightField = new HeightField(0, 0, 70, 30, samples, numberOfSamplesX, numberOfSamplesZ);

            // Convert the height field to a triangle mesh.
            ITriangleMesh mesh = heightField.GetMesh(0.01f, 3);

            // Create a shape for the triangle mesh.
            _triangleMeshShape = new TriangleMeshShape(mesh);

            // Enable contact welding. And set the welding limit to 1 for maximal effect.
            _triangleMeshShape.EnableContactWelding = true;
            _originalWeldingLimit = TriangleMeshAlgorithm.WeldingLimit;
            TriangleMeshAlgorithm.WeldingLimit = 1;

            // Optional: Assign a spatial partitioning scheme to the triangle mesh. (A spatial partition
            // adds an additional memory overhead, but it improves collision detection speed tremendously!)
            _triangleMeshShape.Partition = new CompressedAabbTree()
            {
                BottomUpBuildThreshold = 0
            };

            // Create a static rigid body using the shape and add it to the simulation.
            // We explicitly specify a mass frame. We can use any mass frame for static bodies (because
            // static bodies are effectively treated as if they have infinite mass). If we do not specify
            // a mass frame in the rigid body constructor, the constructor will automatically compute an
            // approximate mass frame (which can take some time for large meshes).
            var ground = new RigidBody(_triangleMeshShape, new MassFrame(), null)
            {
                Pose       = new Pose(new Vector3(-34, 0, -40f)),
                MotionType = MotionType.Static,
            };

            Simulation.RigidBodies.Add(ground);

            SphereShape sphereShape = new SphereShape(0.5f);

            _sphere = new RigidBody(sphereShape);
            Simulation.RigidBodies.Add(_sphere);

            _enableSmoothMovement = true;
            _timeUntilReset       = TimeSpan.Zero;
        }
Ejemplo n.º 36
0
 /// <overloads>
 /// <summary>
 /// Adds triangles to the triangle mesh.
 /// </summary>
 /// </overloads>
 /// 
 /// <summary>
 /// Adds the triangles of the specified mesh (without vertex welding).
 /// </summary>
 /// <param name="mesh">The mesh.</param>
 /// <remarks>
 /// This method does not perform vertex welding and does not remove degenerate triangles. 
 /// </remarks>
 public void Add(ITriangleMesh mesh)
 {
   Add(mesh, false);
 }
Ejemplo n.º 37
0
        public void Initialize(IRayEngineScene scen, params object[] data)
        {
            zeroSpectra = GlobalConfiguration.Instance.SpectralRendering
                            ? (ISpectrum)ZeroCSpectrumArray
                            : this.RgbSpectrumZeroArray;
            var scn = (RayEngineScene)scen;
            if (mesh == null && !string.IsNullOrWhiteSpace(MeshName))
            {

                this.mesh =
                    scn.Meshes.FirstOrDefault(
                        item => item.MeshName.Equals(MeshName, StringComparison.CurrentCultureIgnoreCase));
                if (this.mesh != null)
                {
                    if (this.mesh.MeshProfile == null)
                    {
                        this.mesh.MeshProfile = new LightsourceProfile()
                        {
                            Light = this
                        };
                    }
                    else
                    {
                        var lightsourceProfile = this.mesh.MeshProfile as LightsourceProfile;
                        if (lightsourceProfile != null)
                            lightsourceProfile.Light = this;
                    }
                    meshMeshArea = 0;
                    for (int i = mesh.StartTriangle; i < mesh.EndTriangle; i++)
                    {
                        meshMeshArea += scn.Triangles[i].AreaV(scn.Vertices);
                    }
                }
            }


            if (mesh == null)
            {
                throw new ArgumentException("Cant find light mesh", this.LightName ?? this.MeshName);
            }

            triangleSampleData = new TriangleSample[this.mesh.TrianglesCount];
            this.scene = scn;

            for (int i = mesh.StartTriangle, j = 0; i < mesh.EndTriangle; i++, j++)
            {
                triangleSampleData[j] = new TriangleSample(scene.Triangles[i].AreaV(scene.Vertices), NormalModifier * scene.Triangles[i].ComputeNormal(scene.Vertices));
            }

            triangleSampleData.PartialSort((a, b) => a.Item1.CompareTo(a.Item1), 0, triangleSampleData.Length);

            if (gain.IsBlack() || infoGain == null)
            {
                gain = scn.DefaultLightGain;
                infoGain = new RgbSpectrumInfo(gain);
            }
            lightSpectra = GlobalConfiguration.Instance.SpectralRendering ? spectra.ToArray() : gain.ToArray();
        }
Ejemplo n.º 38
0
        private void DoWork()
        {
            // The locks are released regularly, so that the Decomposition property can be
              // accessed.

              Exception exception = null;
              try
              {
            if ((GlobalSettings.ValidationLevelInternal & GlobalSettings.ValidationLevelUserHighExpensive) != 0)
              ValidateInput();

            lock (_syncRoot)
            {
              _decomposition = null;

              // Create the Dual graph.
              CreateDualGraph();
            }

            // Partitioning process:
            MergeIslands(); // Each internal loop is locked.

            lock (_syncRoot)
            {
              if (!_cancel)
            CreateCompositeShape();
            }

            if (!_cancel)
              OnProgressChanged(100);
              }
              catch (Exception e)
              {
            exception = e;

            if (!IsBusy)  // Throw only when in synchronous decomposition.
              throw;
              }
              finally
              {
            _mesh = null;

            if (IsBusy) // IsBusy is only set for async operations.
            {
              IsBusy = false;

              // Raise completed event.
              var handler = Completed;
              if (handler != null)
            handler(this, new AsyncCompletedEventArgs(exception, _cancel, null));
            }
              }
        }
Ejemplo n.º 39
0
 public static bool IsVolume(ITriangleMesh mesh)
 {
     return mesh.MeshName.NameContains("volume","_volume","volume_");
 }
Ejemplo n.º 40
0
    /// <summary>
    /// Initializes a new instance of the <see cref="TriangleMeshShape"/> class from the given
    /// triangle mesh.
    /// </summary>
    /// <param name="mesh">The mesh.</param>
    /// <param name="enableContactWelding"> 
    /// If set to <see langword="true"/> contact welding is enabled; otherwise, the shape will not
    /// use contact welding. See <see cref="EnableContactWelding"/> for more information.
    /// </param>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="mesh"/> is <see langword="null"/>.
    /// </exception>
    public TriangleMeshShape(ITriangleMesh mesh, bool enableContactWelding)
    {
      if (mesh == null)
        throw new ArgumentNullException("mesh");

      _mesh = mesh;

      EnableContactWelding = enableContactWelding;
    }
Ejemplo n.º 41
0
        private void DoWork()
        {
            // The locks are released regularly, so that the Decomposition property can be
            // accessed.

            Exception exception = null;

            try
            {
                if ((GlobalSettings.ValidationLevelInternal & GlobalSettings.ValidationLevelUserHighExpensive) != 0)
                {
                    ValidateInput();
                }

                lock (_syncRoot)
                {
                    _decomposition = null;

                    // Create the Dual graph.
                    CreateDualGraph();
                }

                // Partitioning process:
                MergeIslands(); // Each internal loop is locked.

                lock (_syncRoot)
                {
                    if (!_cancel)
                    {
                        CreateCompositeShape();
                    }
                }

                if (!_cancel)
                {
                    OnProgressChanged(100);
                }
            }
            catch (Exception e)
            {
                exception = e;

                if (!IsBusy) // Throw only when in synchronous decomposition.
                {
                    throw;
                }
            }
            finally
            {
                _mesh = null;

                if (IsBusy) // IsBusy is only set for async operations.
                {
                    IsBusy = false;

                    // Raise completed event.
                    var handler = Completed;
                    if (handler != null)
                    {
                        handler(this, new AsyncCompletedEventArgs(exception, _cancel, null));
                    }
                }
            }
        }
Ejemplo n.º 42
0
        public static void GetMass(ITriangleMesh mesh, out float mass, out Vector3F centerOfMass, out Matrix33F inertia)
        {
            if (mesh == null)
            throw new ArgumentNullException("mesh");

              // Integral variables.
              float i0 = 0, i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, i6 = 0, i7 = 0, i8 = 0, i9 = 0;

              int numberOfTriangles = mesh.NumberOfTriangles;
              for (int triangleIndex = 0; triangleIndex < numberOfTriangles; triangleIndex++)
              {
            var triangle = mesh.GetTriangle(triangleIndex);

            // Vertex coordinates.
            Vector3F v0 = triangle.Vertex0;
            Vector3F v1 = triangle.Vertex1;
            Vector3F v2 = triangle.Vertex2;

            // Edges and cross products of edges
            Vector3F a = v1 - v0;
            Vector3F b = v2 - v0;
            Vector3F d = Vector3F.Cross(a, b);

            // Compute integral terms.
            float f1x, f2x, f3x, g0x, g1x, g2x;
            ComputePolyhedronMassSubExpressions(v0.X, v1.X, v2.X, out f1x, out f2x, out f3x, out g0x, out g1x, out g2x);
            float f1y, f2y, f3y, g0y, g1y, g2y;
            ComputePolyhedronMassSubExpressions(v0.Y, v1.Y, v2.Y, out f1y, out f2y, out f3y, out g0y, out g1y, out g2y);
            float f1z, f2z, f3z, g0z, g1z, g2z;
            ComputePolyhedronMassSubExpressions(v0.Z, v1.Z, v2.Z, out f1z, out f2z, out f3z, out g0z, out g1z, out g2z);

            // Update integrals.
            i0 += d.X * f1x;
            i1 += d.X * f2x;
            i2 += d.Y * f2y;
            i3 += d.Z * f2z;
            i4 += d.X * f3x;
            i5 += d.Y * f3y;
            i6 += d.Z * f3z;
            i7 += d.X * (v0.Y * g0x + v1.Y * g1x + v2.Y * g2x);
            i8 += d.Y * (v0.Z * g0y + v1.Z * g1y + v2.Z * g2y);
            i9 += d.Z * (v0.X * g0z + v1.X * g1z + v2.X * g2z);
              }

              i0 /= 6.0f;
              i1 /= 24.0f;
              i2 /= 24.0f;
              i3 /= 24.0f;
              i4 /= 60.0f;
              i5 /= 60.0f;
              i6 /= 60.0f;
              i7 /= 120.0f;
              i8 /= 120.0f;
              i9 /= 120.0f;

              mass = i0;

              centerOfMass = 1.0f / mass * new Vector3F(i1, i2, i3);
              // Clamp to zero.
              if (Numeric.IsZero(centerOfMass.X))
            centerOfMass.X = 0;
              if (Numeric.IsZero(centerOfMass.Y))
            centerOfMass.Y = 0;
              if (Numeric.IsZero(centerOfMass.Z))
            centerOfMass.Z = 0;

              // Inertia around the world origin.
              inertia.M00 = i5 + i6;
              inertia.M11 = i4 + i6;
              inertia.M22 = i4 + i5;
              inertia.M01 = inertia.M10 = Numeric.IsZero(i7) ? 0 : -i7;
              inertia.M12 = inertia.M21 = Numeric.IsZero(i8) ? 0 : -i8;
              inertia.M02 = inertia.M20 = Numeric.IsZero(i9) ? 0 : -i9;

              // Inertia around center of mass.
              inertia = GetUntranslatedMassInertia(mass, inertia, centerOfMass);
        }
Ejemplo n.º 43
0
    /// <inheritdoc/>
    protected override void CloneCore(Shape sourceShape)
    {
      var source = (TriangleMeshShape)sourceShape;
      _mesh = source.Mesh;

      if (source.Partition != null)
        Partition = source.Partition.Clone();

      if (source.TriangleNeighbors != null)
        TriangleNeighbors = new List<int>(source.TriangleNeighbors);
    }
Ejemplo n.º 44
0
        public void Init(RayEngineScene scene, ITriangleMesh[] geometry)
        {
            var sceneModel = scene;
            meshes = new List<ITriangleMesh>();
            meshes.AddRange(geometry);
            this.sceneVertices = sceneModel.Vertices;
            var trianglesCache = scene.Triangles.ToList();
            Comparison<Triangle> tc = (t1, t2) => CompareTriangles(t1, t2);
            //trianglesCache.Sort(tc);
            this.triangles = trianglesCache;
            //this.BuildTree(trianglesCache, 0, trianglesCache.Count);
            AABB bound = trianglesCache.Select(prim => prim.WorldBound(sceneVertices)).Aggregate((b1, b2) => b1.Union(b2));
            var prims =
                trianglesCache.Select(
                    (item, index) =>
                    new BvhBuildNode()
                        {
                            Bound = item.WorldBound(sceneVertices),
                            PrimitiveCount = 1,
                            PrimitiveStart = index
                        }).ToList();
            this.RootNode = BuildQualityTree(prims, 0, trianglesCache.Count, bound);

            Tracer.TraceLine("Linearize BVH");
            this.LinearizeBVH();
            Tracer.TraceLine("Complete");

            Tracer.TraceLine("Tree is builded, {0} nodes total", bvhNodesCount);
        }
Ejemplo n.º 45
0
    public void Add(ITriangleMesh mesh, bool weldVerticesBruteForce)
    {
      var triangleMesh = mesh as TriangleMesh;
      if (triangleMesh != null && !weldVerticesBruteForce)
      {
        // Special: mesh is TriangleMesh and no welding.

        if (triangleMesh.Vertices == null)
          return;
        if (triangleMesh.Indices == null)
          return;

        if (Vertices == null)
          Vertices = new List<Vector3F>(triangleMesh.Vertices.Count);

        int numberOfNewIndices = triangleMesh.Indices.Count;
        if (Indices == null)
          Indices = new List<int>(numberOfNewIndices);
        
        // Add new vertices.
        int oldNumberOfVertices = Vertices.Count;
        Vertices.AddRange(triangleMesh.Vertices);
        
        // Add new indices. Add offset to all indices.
        for (int i = 0; i < numberOfNewIndices; i++)
          Indices.Add(triangleMesh.Indices[i] + oldNumberOfVertices);
        
        return;
      }

      int numberOfTriangles = mesh.NumberOfTriangles;
      for (int i = 0; i < numberOfTriangles; i++)
        Add(mesh.GetTriangle(i), weldVerticesBruteForce);
    }
Ejemplo n.º 46
0
        // Handling of non-uniform scaling:
        // http://en.wikipedia.org/wiki/Scaling_(geometry) about non-uniform scaling:
        // "Such a scaling changes ... the volume by the product of all three [scale factors]."
        /// <summary>
        /// Gets the contact of ray with a triangle mesh.
        /// </summary>
        /// <param name="triangleMesh">The triangle mesh.</param>
        /// <param name="ray">The ray.</param>
        /// <param name="hitDistance">
        /// The hit distance. This is the distance on the ray from the ray origin to the contact.
        /// </param>
        /// <returns>
        /// <see langword="true"/> if the ray hits the front face of a triangle mesh triangle; 
        /// otherwise, <see langword="false"/>.
        /// </returns>
        /// <remarks>
        /// This method returns any contact, not necessarily the first contact of the ray with the
        /// triangle mesh! The mesh triangles are treated as one-sided.
        /// </remarks>
        internal static bool GetContact(ITriangleMesh triangleMesh, Ray ray, out float hitDistance)
        {
            for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
              {
            var triangle = triangleMesh.GetTriangle(i);
            bool hit = GetContact(ray, triangle, false, out hitDistance);
            if (hit)
              return true;
              }

              hitDistance = float.NaN;
              return false;
        }
Ejemplo n.º 47
0
    /// <summary>
    /// Initializes a new instance of the <see cref="TriangleMeshShape"/> class from the given
    /// triangle mesh.
    /// </summary>
    /// <param name="mesh">The mesh.</param>
    /// <param name="enableContactWelding"> 
    /// If set to <see langword="true"/> contact welding is enabled; otherwise, the shape will not
    /// use contact welding. See <see cref="EnableContactWelding"/> for more information.
    /// </param>
    /// <param name="partition">
    /// The spatial partition (see <see cref="Partition"/>). Can be <see langword="null"/> if no 
    /// partition should be used.
    /// </param>
    /// <exception cref="ArgumentNullException">
    /// <paramref name="mesh"/> is <see langword="null"/>.
    /// </exception>
    public TriangleMeshShape(ITriangleMesh mesh, bool enableContactWelding, ISpatialPartition<int> partition)
    {
      if (mesh == null)
        throw new ArgumentNullException("mesh");

      _mesh = mesh;
      Partition = partition;

      EnableContactWelding = enableContactWelding;
    }
Ejemplo n.º 48
0
        /// <summary>
        /// Decomposes the specified mesh (asynchronously).
        /// </summary>
        /// <param name="mesh">The mesh.</param>
        /// <remarks>
        /// <para>
        /// This method does not block. The flag <see cref="IsBusy"/> is set until the decomposition has
        /// finished. The event <see cref="ProgressChanged"/> informs you on the current progress. The
        /// event <see cref="Completed"/> is raised when the decomposition is finished. The current
        /// intermediate decomposition result is available in <see cref="Decomposition"/>. Retrieving
        /// the result while the decomposition is running is possible but will temporarily block the
        /// decomposition process.
        /// </para>
        /// <para>
        /// <strong>Thread-Safety:</strong><br/>
        /// The <paramref name="mesh"/> must not be modified while the decomposition is in progress.
        /// </para>
        /// </remarks>
        /// <exception cref="InvalidOperationException">
        /// Convex decomposition is already in progress.
        /// </exception>
        public void DecomposeAsync(ITriangleMesh mesh)
        {
            if (mesh == null)
            throw new ArgumentNullException("mesh");
              if (IsBusy)
            throw new InvalidOperationException("Convex decomposition is already in progress.");

              _mesh = mesh;
              _cancel = false;
              IsBusy = true;

              Parallel.Start(DoWork);
        }
Ejemplo n.º 49
0
        public TriangleMeshSample(Microsoft.Xna.Framework.Game game)
            : base(game)
        {
            // Add basic force effects.
            Simulation.ForceEffects.Add(new Gravity());
            Simulation.ForceEffects.Add(new Damping());

            // The triangle mesh could be loaded from a file, such as an XNA Model.
            // In this example will use the same height field as in Sample11 and convert
            // the shape into a triangle mesh.
            var numberOfSamplesX = 20;
            var numberOfSamplesZ = 20;
            var heights          = new float[numberOfSamplesX * numberOfSamplesZ];

            for (int z = 0; z < numberOfSamplesZ; z++)
            {
                for (int x = 0; x < numberOfSamplesX; x++)
                {
                    heights[z * numberOfSamplesX + x] = (float)(Math.Cos(z / 2f) * Math.Sin(x / 2f) * 5f + 5f);
                }
            }
            HeightField heightField = new HeightField(0, 0, 100, 100, heights, numberOfSamplesX, numberOfSamplesZ);

            // Convert the height field to a triangle mesh.
            ITriangleMesh mesh = heightField.GetMesh(0.01f, 3);

            // Create a shape for the triangle mesh.
            TriangleMeshShape triangleMeshShape = new TriangleMeshShape(mesh);

            // Optional: We can enable "contact welding". When this flag is enabled, the triangle shape
            // precomputes additional internal information for the mesh. The collision detection will
            // be able to compute better contacts (e.g. better normal vectors at triangle edges).
            // Pro: Collision detection can compute better contact information.
            // Con: Contact welding information needs a bit of memory. And the collision detection is
            // a bit slower.
            triangleMeshShape.EnableContactWelding = true;

            // Optional: Assign a spatial partitioning scheme to the triangle mesh. (A spatial partition
            // adds an additional memory overhead, but it improves collision detection speed tremendously!)
            triangleMeshShape.Partition = new CompressedAabbTree
            {
                // The tree is automatically built using a mixed top-down/bottom-up approach. Bottom-up
                // building is slower but produces better trees. If the tree building takes too long,
                // we can lower the BottomUpBuildThreshold (default is 128).
                BottomUpBuildThreshold = 0,
            };

            // Optional: The partition will be automatically built when needed. For static meshes it is
            // built only once when it is needed for the first time. Building the AABB tree can take a
            // few seconds for very large meshes.
            // By calling Update() manually we can force the partition to be built right now:
            //triangleMeshShape.Partition.Update(false);
            // We could also call this method in a background thread while the level is loading. Or,
            // we can build the triangle mesh and the AABB tree in the XNA content pipeline and avoid the
            // building of the tree at runtime (see Sample 33).

            // Create a static rigid body using the shape and add it to the simulation.
            // We explicitly specify a mass frame. We can use any mass frame for static bodies (because
            // static bodies are effectively treated as if they have infinite mass). If we do not specify
            // a mass frame in the rigid body constructor, the constructor will automatically compute an
            // approximate mass frame (which can take some time for large meshes).
            var ground = new RigidBody(triangleMeshShape, new MassFrame(), null)
            {
                Pose       = new Pose(new Vector3F(-50, 0, -50f)),
                MotionType = MotionType.Static,
            };

            Simulation.RigidBodies.Add(ground);

            // Distribute a few spheres and boxes across the landscape.
            SphereShape sphereShape = new SphereShape(0.5f);

            for (int i = 0; i < 30; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-30, 30);
                position.Y = 20;

                RigidBody body = new RigidBody(sphereShape)
                {
                    Pose = new Pose(position),
                };
                Simulation.RigidBodies.Add(body);
            }

            BoxShape boxShape = new BoxShape(1, 1, 1);

            for (int i = 0; i < 30; i++)
            {
                Vector3F position = RandomHelper.Random.NextVector3F(-30, 30);
                position.Y = 20;

                RigidBody body = new RigidBody(boxShape)
                {
                    Pose = new Pose(position),
                };
                Simulation.RigidBodies.Add(body);
            }
        }
Ejemplo n.º 50
0
    public static ParticleSystem Create(ITriangleMesh mesh, ContentManager contentManager)
    {
      var ps = new ParticleSystem
      {
        Name = "GlowingMeshEffect",
        MaxNumberOfParticles = 100
      };

      ps.Parameters.AddUniform<float>(ParticleParameterNames.Lifetime).DefaultValue = 1.0f;

      ps.Effectors.Add(new StreamEmitter
      {
        DefaultEmissionRate = 100,
      });

      // The particles start on random positions on the surface of the given triangle mesh.
      ps.Parameters.AddVarying<Vector3F>(ParticleParameterNames.Position);
      ps.Effectors.Add(new StartOnMeshEffector
      {
        Parameter = ParticleParameterNames.Position,
        Mesh = mesh
      });

      // Just to demonstrate a new custom effector:
      // The size follows a user-defined curve using the FuncEffector.
      ps.Parameters.AddVarying<float>(ParticleParameterNames.Size);
      ps.Effectors.Add(new FuncEffector<float, float>
      {
        InputParameter = ParticleParameterNames.NormalizedAge,
        OutputParameter = ParticleParameterNames.Size,
        Func = age => 6.7f * age * (1 - age) * (1 - age) * 0.4f,
      });

      ps.Parameters.AddVarying<Vector3F>(ParticleParameterNames.Color);
      ps.Effectors.Add(new StartValueEffector<Vector3F>
      {
        Parameter = ParticleParameterNames.Color,
        Distribution = new BoxDistribution
        {
          MinValue = new Vector3F(0.5f, 0.5f, 0.5f),
          MaxValue = new Vector3F(1, 1, 1)
        }
      });

      ps.Parameters.AddVarying<float>(ParticleParameterNames.Alpha);
      ps.Effectors.Add(new FuncEffector<float, float>
      {
        InputParameter = ParticleParameterNames.NormalizedAge,
        OutputParameter = ParticleParameterNames.Alpha,
        Func = age => 6.7f * age * (1 - age) * (1 - age),
      });

      ps.Parameters.AddUniform<Texture2D>(ParticleParameterNames.Texture).DefaultValue =
        contentManager.Load<Texture2D>("Particles/Star");

      ps.Parameters.AddUniform<float>(ParticleParameterNames.BlendMode).DefaultValue = 0;


      ps.Parameters.AddUniform<BillboardOrientation>(ParticleParameterNames.BillboardOrientation).DefaultValue =
        BillboardOrientation.ScreenAligned;

      ParticleSystemValidator.Validate(ps);

      return ps;
    }
Ejemplo n.º 51
0
        /// <summary>
        /// Draws the triangles of the given mesh (with counter-clockwise winding for front faces).
        /// </summary>
        /// <param name="mesh">The triangle mesh.</param>
        /// <param name="pose">The pose.</param>
        /// <param name="scale">The scale.</param>
        /// <param name="color">The color.</param>
        /// <param name="drawWireFrame">
        /// If set to <see langword="true"/> the wire-frame is drawn; otherwise the object is drawn
        /// with solid faces.
        /// </param>
        /// <param name="drawOverScene">
        /// If set to <see langword="true"/> the object is drawn over the graphics scene (depth-test 
        /// disabled).
        /// </param>
        /// <remarks>
        /// Warning: Calling this method every frame to render the same triangle mesh is very 
        /// inefficient! If the triangle mesh does not change, call <see cref="DrawShape"/> with a 
        /// <see cref="TriangleMeshShape"/> instead!
        /// </remarks>
        /// <exception cref="NotSupportedException">
        /// Drawing solid objects with disabled depth test is not yet supported.
        /// </exception>
        public void DrawTriangles(ITriangleMesh mesh, Pose pose, Vector3F scale,
            Color color, bool drawWireFrame, bool drawOverScene)
        {
            if (!Enabled || mesh == null)
            return;

              if (!drawWireFrame && drawOverScene)
            throw new NotSupportedException("Drawing solid objects with disabled depth test is not yet supported.");

              TriangleBatch batch;
              if (drawOverScene)
            batch = OverSceneWireframeTriangleBatch;
              else if (drawWireFrame)
            batch = InSceneWireframeTriangleBatch;
              else if (color.A == 255)
            batch = OpaqueTriangleBatch;
              else
            batch = TransparentTriangleBatch;

              if (Vector3F.AreNumericallyEqual(scale, Vector3F.One) && !pose.HasRotation && !pose.HasTranslation)
              {
            int numberOfTriangles = mesh.NumberOfTriangles;
            for (int i = 0; i < numberOfTriangles; i++)
            {
              var triangle = mesh.GetTriangle(i);

              var normal = Vector3F.Cross(triangle.Vertex1 - triangle.Vertex0, triangle.Vertex2 - triangle.Vertex0);
              // (normal is normalized in the BasicEffect HLSL.)

              // Draw with swapped winding order!
              batch.Add(ref triangle.Vertex0, ref triangle.Vertex2, ref triangle.Vertex1, ref normal, ref color);
            }
              }
              else
              {
            var transform = pose * Matrix44F.CreateScale(scale);

            int numberOfTriangles = mesh.NumberOfTriangles;
            for (int i = 0; i < numberOfTriangles; i++)
            {
              var triangle = mesh.GetTriangle(i);

              // Transform to world space.
              triangle.Vertex0 = transform.TransformPosition(triangle.Vertex0);
              triangle.Vertex1 = transform.TransformPosition(triangle.Vertex1);
              triangle.Vertex2 = transform.TransformPosition(triangle.Vertex2);

              var normal = Vector3F.Cross(triangle.Vertex1 - triangle.Vertex0, triangle.Vertex2 - triangle.Vertex0);
              // (normal is normalized in the BasicEffect HLSL.)

              // Draw with swapped winding order!
              batch.Add(ref triangle.Vertex0, ref triangle.Vertex2, ref triangle.Vertex1, ref normal, ref color);
            }
              }
        }
Ejemplo n.º 52
0
 /// <summary>
 /// Initializes a new instance of the <see cref="TriangleMeshShape"/> class from the given 
 /// triangle mesh.
 /// </summary>
 /// <param name="mesh">The mesh.</param>
 /// <exception cref="ArgumentNullException">
 /// <paramref name="mesh"/> is <see langword="null"/>.
 /// </exception>
 public TriangleMeshShape(ITriangleMesh mesh) : this(mesh, false, null)
 {
 }