예제 #1
0
        /// <summary>
        /// Create visual game object and adds it as child to shape game object.
        /// </summary>
        /// <param name="shape">Shape instance.</param>
        /// <param name="isRenderData">If true we wont try to load predefined mesh from resources.</param>
        /// <returns>Visual game object if successful - otherwise null.</returns>
        protected static GameObject CreateGameObject(Collide.Shape shape, bool isRenderData)
        {
            GameObject go = null;

            try {
                go = isRenderData || shape is Collide.Mesh || shape is Collide.HollowCylinder || shape is Collide.Cone || shape is Collide.HollowCone ?
                     new GameObject("") :
                     PrefabLoader.Instantiate <GameObject>(@"Debug/" + shape.GetType().Name + "Renderer");

                if (go == null)
                {
                    Debug.LogWarning("Unable to find shape visual resource: " + @"Debug/" + shape.GetType().Name + "Renderer", shape);
                    return(null);
                }

                go.name = shape.name + "_Visual";
                go.transform.hideFlags = HideFlags.NotEditable;

                shape.gameObject.AddChild(go);
                go.transform.localPosition = Vector3.zero;
                go.transform.localRotation = Quaternion.identity;
            }
            catch (System.Exception e) {
                Debug.LogException(e);
                if (go != null)
                {
                    GameObject.DestroyImmediate(go);
                }
            }

            return(go);
        }
예제 #2
0
        /// <summary>
        /// Creates instance with one or more render meshes. Each mesh will
        /// be child to parent ShapeVisualRenderData object if number of
        /// meshes > 1. If meshes.Length == 1 the mesh renderer and filter
        /// will be added directly in the returned game object.
        /// </summary>
        /// <param name="shape">Shape to add render data for.</param>
        /// <param name="meshes">Array of meshes.</param>
        /// <param name="material">Material.</param>
        /// <param name="isRenderData">True if render data, i.e., decoupled from Collide.Mesh source objects.</param>
        /// <returns>Visual game object as child to shape game object if successful - otherwise null.</returns>
        protected static GameObject CreateInstance(Collide.Shape shape, Mesh[] meshes, Material material, bool isRenderData)
        {
            if (shape == null || meshes.Length == 0)
            {
                return(null);
            }

            var parent = CreateGameObject(shape, isRenderData);

            if (parent == null)
            {
                return(null);
            }

            CreateOnSelectionProxy(parent, shape);

            var visual = AddVisualComponent(parent, shape, isRenderData);

            if (visual == null)
            {
                return(null);
            }

            for (int i = 0; i < meshes.Length; ++i)
            {
                AddChildMesh(shape,
                             parent,
                             meshes[i],
                             parent.name + "_" + (i + 1).ToString(),
                             material,
                             i > 0);
            }

            return(parent);
        }
예제 #3
0
        /// <summary>
        /// Adds child game object to visual parent (the one with ShapeVisual component).
        /// </summary>
        /// <param name="shape">Parent shape this visual belongs to.</param>
        /// <param name="shapeVisualParent">Parent game object (the one with ShapeVisual component).</param>
        /// <param name="mesh">Visual mesh.</param>
        /// <param name="name">Name of the child.</param>
        /// <param name="material">Material.</param>
        /// <returns>Created child game object.</returns>
        protected static GameObject AddChildMesh(Collide.Shape shape,
                                                 GameObject shapeVisualParent,
                                                 Mesh mesh,
                                                 string name,
                                                 Material material,
                                                 bool createNewGameObject)
        {
            GameObject child = shapeVisualParent;

            if (createNewGameObject)
            {
                child      = new GameObject("");
                child.name = name;

                shapeVisualParent.AddChild(child);
                child.transform.localPosition = Vector3.zero;
                child.transform.localRotation = Quaternion.identity;
                child.transform.hideFlags     = HideFlags.NotEditable;

                child.AddComponent <MeshFilter>();
                child.AddComponent <MeshRenderer>();
            }

            var filter   = child.GetComponent <MeshFilter>();
            var renderer = child.GetComponent <MeshRenderer>();

            filter.sharedMesh = mesh;

            SetMaterial(filter, renderer, material);

            CreateOnSelectionProxy(child, shape);

            return(child);
        }
예제 #4
0
        /// <summary>
        /// Creates game object and ShapeVisual component given shape and if this is
        /// pure render data or not.
        /// </summary>
        /// <param name="shape">Shape to create ShapeVisual for.</param>
        /// <returns>Game object with ShapeVisual component if successful, otherwise null.</returns>
        protected static GameObject CreateInstance(Collide.Shape shape)
        {
            if (shape == null)
            {
                return(null);
            }

            GameObject go = CreateGameObject(shape, false);

            if (go == null)
            {
                return(null);
            }

            var visual = AddVisualComponent(go, shape, false);

            if (visual == null)
            {
                Debug.LogWarning("Unsupported shape type for visual: " + shape.GetType().FullName);
                return(null);
            }

            CreateOnSelectionProxy(go, shape);

            visual.SetMaterial(DefaultMaterial);
            visual.OnSizeUpdated();

            return(go);
        }
예제 #5
0
        /// <summary>
        /// Generates custom shape mesh
        /// </summary>
        public static Mesh GenerateMesh(Collide.Shape shape)
        {
            Collide.HollowCylinder hollowCylinder = shape as Collide.HollowCylinder;
            Mesh mesh = new Mesh();

            float outerRadius = Mathf.Max(0, hollowCylinder.Radius);
            float innerRadius = Mathf.Max(0, hollowCylinder.Radius - hollowCylinder.Thickness);
            float halfHeight  = Mathf.Max(0, hollowCylinder.Height) / 2f;

            int triangleCount = m_resolution * 8;
            int vertexCount   = m_resolution * 8;

            //Vector2[] uvs = new Vector2[vertexCount];
            Vector3[] vertices  = new Vector3[vertexCount];
            Vector3[] normals   = new Vector3[vertexCount];
            int[]     triangles = new int[triangleCount * 3];

            // Loop over each "pie slice" of the hollow cylinder. Vertices two per point of the slice, triangles also arranged looping around the slice
            for (int i = 0; i < m_resolution; i++)
            {
                int currentVertex     = i * 8;
                int nextCurrentVertex = ((i + 1) % m_resolution) * 8;

                float angle = i * Mathf.PI * 2 / m_resolution;
                float sinI  = Mathf.Sin(angle);
                float cosI  = Mathf.Cos(angle);

                vertices[currentVertex]     = vertices[currentVertex + 7] = new Vector3(sinI * innerRadius, halfHeight, cosI * innerRadius);
                vertices[currentVertex + 1] = vertices[currentVertex + 2] = new Vector3(sinI * outerRadius, halfHeight, cosI * outerRadius);
                vertices[currentVertex + 3] = vertices[currentVertex + 4] = new Vector3(sinI * outerRadius, -halfHeight, cosI * outerRadius);
                vertices[currentVertex + 5] = vertices[currentVertex + 6] = new Vector3(sinI * innerRadius, -halfHeight, cosI * innerRadius);

                normals[currentVertex]     = normals[currentVertex + 1] = new Vector3(0, 1, 0);
                normals[currentVertex + 2] = normals[currentVertex + 3] = new Vector3(sinI, 0, cosI);
                normals[currentVertex + 4] = normals[currentVertex + 5] = new Vector3(0, -1, 0);
                normals[currentVertex + 6] = normals[currentVertex + 7] = new Vector3(-sinI, 0, -cosI);

                for (int j = 0; j < 8; j += 2)
                {
                    int currentTriangle = i * 4 * 6 + j * 3;
                    int nextJ           = (j + 1) % 8;

                    triangles[currentTriangle]     = currentVertex + j;
                    triangles[currentTriangle + 1] = currentVertex + nextJ;
                    triangles[currentTriangle + 2] = nextCurrentVertex + nextJ;

                    triangles[currentTriangle + 3] = currentVertex + j;
                    triangles[currentTriangle + 4] = nextCurrentVertex + nextJ;
                    triangles[currentTriangle + 5] = nextCurrentVertex + j;
                }
            }

            mesh.vertices = vertices;
            //m_mesh.uv = uvs; // TODO, possibly
            mesh.triangles = triangles;
            mesh.normals   = normals;

            return(mesh);
        }
예제 #6
0
 /// <summary>
 /// Adds OnSelectionProxy to <paramref name="visualParent"/> and all its children.
 /// </summary>
 /// <param name="visualParent">Visual parent game object.</param>
 /// <param name="shape">Shape reference.</param>
 private static void CreateOnSelectionProxy(GameObject visualParent, Collide.Shape shape)
 {
     visualParent.GetOrCreateComponent <OnSelectionProxy>().Component = shape;
     foreach (Transform child in visualParent.transform)
     {
         child.gameObject.GetOrCreateComponent <OnSelectionProxy>().Component = shape;
     }
 }
예제 #7
0
        private void SynchronizeScaleIfNodeExist(Collide.Shape shape)
        {
            var data = shape.gameObject.GetComponent <ShapeDebugRenderData>();

            if (data != null)
            {
                data.SynchronizeScale(shape);
            }
        }
예제 #8
0
        /// <summary>
        /// Callback from Collide.Shape when the size of a shape has been changed.
        /// </summary>
        /// <param name="shape"></param>
        public static void SynchronizeScale(Collide.Shape shape)
        {
            if (!IsActiveForSynchronize)
            {
                return;
            }

            Instance.SynchronizeScaleIfNodeExist(shape);
        }
예제 #9
0
        /// <summary>
        /// Called after Simulation.StepForward from shapes without rigid bodies.
        /// </summary>
        public static void OnPostSynchronizeTransforms(Collide.Shape shape)
        {
            if (!IsActiveForSynchronize)
            {
                return;
            }

            Instance.SynchronizeShape(shape);
        }
예제 #10
0
파일: Find.cs 프로젝트: Algoryx/AGXUnity
 private static Collide.Shape[] CollectShapes(GameObject parent,
                                              RigidBody rb,
                                              Collide.Shape shape,
                                              bool searchChildren)
 {
     return(shape != null && !searchChildren?parent.GetComponents <Collide.Shape>() :
                shape != null || rb != null?parent.GetComponentsInChildren <Collide.Shape>() :
                    // Both shape and rb == null and PropagateToChildren == true.
                    parent.GetComponentsInChildren <Collide.Shape>());
 }
예제 #11
0
        /// <summary>
        /// Adds shape visual type given shape type and <paramref name="isRenderData"/>.
        /// </summary>
        /// <param name="go">Game object to add ShapeVisual component to.</param>
        /// <param name="shape">Shape ShapeVisual is referring.</param>
        /// <param name="isRenderData">True if the component should be ShapeVisualRenderData regardless of shape type.</param>
        /// <returns></returns>
        private static ShapeVisual AddVisualComponent(GameObject go, Collide.Shape shape, bool isRenderData)
        {
            ShapeVisual instance = null;

            if (isRenderData)
            {
                instance = go.AddComponent <ShapeVisualRenderData>();
            }
            else if (shape is Collide.Box)
            {
                instance = go.AddComponent <ShapeVisualBox>();
            }
            else if (shape is Collide.Sphere)
            {
                instance = go.AddComponent <ShapeVisualSphere>();
            }
            else if (shape is Collide.Cylinder)
            {
                instance = go.AddComponent <ShapeVisualCylinder>();
            }
            else if (shape is Collide.HollowCylinder)
            {
                instance = go.AddComponent <ShapeVisualHollowCylinder>();
            }
            else if (shape is Collide.Cone)
            {
                instance = go.AddComponent <ShapeVisualCone>();
            }
            else if (shape is Collide.HollowCone)
            {
                instance = go.AddComponent <ShapeVisualHollowCone>();
            }
            else if (shape is Collide.Capsule)
            {
                instance = go.AddComponent <ShapeVisualCapsule>();
            }
            else if (shape is Collide.Plane)
            {
                instance = go.AddComponent <ShapeVisualPlane>();
            }
            else if (shape is Collide.Mesh)
            {
                instance = go.AddComponent <ShapeVisualMesh>();
            }

            if (instance != null)
            {
                instance.hideFlags = HideFlags.NotEditable;
                instance.Shape     = shape;

                instance.OnConstruct();
            }

            return(instance);
        }
예제 #12
0
        /// <summary>
        /// Create given shape of supported type (SupportsShapeVisual == true).
        /// </summary>
        /// <param name="shape">Shape to create visual for.</param>
        /// <returns>Game object with ShapeVisual component if successful, otherwise null.</returns>
        public static GameObject Create(Collide.Shape shape)
        {
            if (!SupportsShapeVisual(shape))
            {
                return(null);
            }

            return(shape is Collide.Mesh ?
                   CreateInstance(shape, (shape as Collide.Mesh).SourceObjects, DefaultMaterial, false) :
                   CreateInstance(shape));
        }
예제 #13
0
 /// <summary>
 /// True if the given shape supports native creation of visual data, otherwise false.
 /// </summary>
 /// <param name="shape">Shape.</param>
 /// <returns>True if the given shape supports native creation of visual data.</returns>
 public static bool SupportsShapeVisual(Collide.Shape shape)
 {
     return(shape != null &&
            (
                shape is Collide.Box ||
                shape is Collide.Sphere ||
                shape is Collide.Cylinder ||
                shape is Collide.Capsule ||
                shape is Collide.Plane ||
                shape is Collide.Mesh
            ));
 }
예제 #14
0
        /// <summary>
        /// Callback from Shape.OnDisable to catch and find disabled shapes,
        /// disabling debug render node.
        /// </summary>
        public static void OnShapeDisable(Collide.Shape shape)
        {
            if (!IsActiveForSynchronize)
            {
                return;
            }

            var data = shape.GetComponent <ShapeDebugRenderData>();

            if (data.Node != null)
            {
                data.Node.SetActive(false);
            }
        }
예제 #15
0
        private MeshUtils.Edge[] FindPrincipalEdges(Collide.Shape shape, float principalEdgeExtension)
        {
            if (shape != null && shape.GetUtils() != null)
            {
                return(shape.GetUtils().GetPrincipalEdgesWorld(principalEdgeExtension));
            }

            Mesh mesh = shape is Collide.Mesh ?
                        (shape as Collide.Mesh).SourceObjects.FirstOrDefault() :
                        Target.GetComponent <MeshFilter>() != null?
                        Target.GetComponent <MeshFilter>().sharedMesh:
                        null;

            Vector3 halfExtents = 0.5f * Vector3.one;

            if (mesh != null)
            {
                halfExtents = mesh.bounds.extents;
            }

            MeshUtils.Edge[] edges = ShapeUtils.ExtendAndTransformEdgesToWorld(Target.transform,
                                                                               new MeshUtils.Edge[]
            {
                new MeshUtils.Edge(BoxShapeUtils.GetLocalFace(halfExtents, ShapeUtils.Direction.Negative_X),
                                   BoxShapeUtils.GetLocalFace(halfExtents, ShapeUtils.Direction.Positive_X),
                                   ShapeUtils.GetLocalFaceDirection(ShapeUtils.Direction.Positive_Y),
                                   MeshUtils.Edge.EdgeType.Principal),
                new MeshUtils.Edge(BoxShapeUtils.GetLocalFace(halfExtents, ShapeUtils.Direction.Negative_Y),
                                   BoxShapeUtils.GetLocalFace(halfExtents, ShapeUtils.Direction.Positive_Y),
                                   ShapeUtils.GetLocalFaceDirection(ShapeUtils.Direction.Positive_Z),
                                   MeshUtils.Edge.EdgeType.Principal),
                new MeshUtils.Edge(BoxShapeUtils.GetLocalFace(halfExtents, ShapeUtils.Direction.Negative_Z),
                                   BoxShapeUtils.GetLocalFace(halfExtents, ShapeUtils.Direction.Positive_Z),
                                   ShapeUtils.GetLocalFaceDirection(ShapeUtils.Direction.Positive_X),
                                   MeshUtils.Edge.EdgeType.Principal)
            },
                                                                               principalEdgeExtension);

            return(edges);
        }
예제 #16
0
        private void SynchronizeShape(Collide.Shape shape)
        {
            var  data         = shape.gameObject.GetOrCreateComponent <ShapeDebugRenderData>();
            bool shapeEnabled = shape.IsEnabledInHierarchy;

            if (data.hideFlags != HideFlags.HideInInspector)
            {
                data.hideFlags = HideFlags.HideInInspector;
            }

            // Do not create debug render data if the shape is inactive.
            if (!shapeEnabled && data.Node == null)
            {
                return;
            }

            data.Synchronize(this);
            if (data.Node != null && (RenderShapes && shapeEnabled) != data.Node.activeSelf)
            {
                data.Node.SetActive(RenderShapes && shapeEnabled);
            }
        }
예제 #17
0
 /// <summary>
 /// Find ShapeVisual instance given shape.
 /// </summary>
 /// <param name="shape">Shape.</param>
 /// <returns>ShapeVisual instance if present, otherwise null.</returns>
 public static ShapeVisual Find(Collide.Shape shape)
 {
     return(shape != null?
            shape.GetComponentsInChildren <ShapeVisual>().FirstOrDefault(instance => instance.Shape == shape) :
                null);
 }
예제 #18
0
 /// <summary>
 /// Create render data for given shape. Render data is when you have
 /// your own representation of the mesh and material.
 ///
 /// The component added will be ShapeVisualRenderData regardless of the
 /// type of the shape.
 ///
 /// If meshes.Length == 1 the MeshFilter and MeshRenderer will be added
 /// to the returned game object. If meshes.Length > 1 the filters and
 /// renderer will be added as children.
 /// </summary>
 /// <param name="shape">Shape to create render data for.</param>
 /// <param name="meshes">Render meshes for the shape.</param>
 /// <param name="material">Material.</param>
 /// <returns>Game object with ShapeVisual component if successful, otherwise null.</returns>
 public static GameObject CreateRenderData(Collide.Shape shape, Mesh[] meshes, Material material)
 {
     return(CreateInstance(shape, meshes, material, true));
 }
예제 #19
0
        public Hit Test(Ray ray, float rayLength = 500.0f)
        {
            LastHit = Hit.Invalid;

            if (Target == null)
            {
                return(Hit.Invalid);
            }

            Hit hit = new Hit();

            Collide.Shape shape = Target.GetComponent <Collide.Shape>();
            if (shape != null)
            {
                if (shape is Collide.Mesh)
                {
                    hit.Triangle = MeshUtils.FindClosestTriangle((shape as Collide.Mesh).SourceObjects, shape.gameObject, ray, rayLength);
                }
                else if (shape is Collide.HeightField)
                {
                    hit.Triangle = TriangleHit.Invalid;
                }
                else
                {
                    GameObject tmp = PrefabLoader.Instantiate <GameObject>(Rendering.DebugRenderData.GetPrefabName(shape.GetType().Name));

                    if (tmp != null)
                    {
                        tmp.hideFlags            = HideFlags.HideAndDontSave;
                        tmp.transform.position   = shape.transform.position;
                        tmp.transform.rotation   = shape.transform.rotation;
                        tmp.transform.localScale = shape.GetScale();

                        hit.Triangle        = MeshUtils.FindClosestTriangle(tmp, ray, rayLength);
                        hit.Triangle.Target = shape.gameObject;

                        GameObject.DestroyImmediate(tmp);
                    }
                }
            }
            else
            {
                MeshFilter filter = Target.GetComponent <MeshFilter>();
                hit.Triangle = filter != null?MeshUtils.FindClosestTriangle(filter.sharedMesh, Target, ray, rayLength) : TriangleHit.Invalid;
            }

            if (hit.Triangle.Valid)
            {
                hit.Triangle.ClosestEdge = ShapeUtils.FindClosestEdgeToSegment(ray.GetPoint(0), ray.GetPoint(rayLength), hit.Triangle.Edges).Edge;
            }

            List <MeshUtils.Edge> allEdges = FindPrincipalEdges(shape, 10.0f).ToList();

            if (hit.Triangle.Valid)
            {
                allEdges.Add(hit.Triangle.ClosestEdge);
            }

            var closestEdgeToSegmentResult = ShapeUtils.FindClosestEdgeToSegment(ray.GetPoint(0), ray.GetPoint(rayLength), allEdges.ToArray());

            hit.ClosestEdge.Target   = Target;
            hit.ClosestEdge.Edge     = closestEdgeToSegmentResult.Edge;
            hit.ClosestEdge.Distance = closestEdgeToSegmentResult.Distance;

            return(LastHit = hit);
        }
예제 #20
0
 /// <summary>
 /// True if the given shape has a visual instance.
 /// </summary>
 /// <param name="shape">Shape.</param>
 /// <returns>True if the given shape has a visual instance.</returns>
 public static bool HasShapeVisual(Collide.Shape shape)
 {
     return(Find(shape) != null);
 }
예제 #21
0
    /// <summary>
    /// Generates custom shape mesh
    /// </summary>
    public static Mesh GenerateMesh(Collide.Shape shape)
    {
      Collide.Cone cone = shape as Collide.Cone;
      Mesh mesh = new Mesh();

      mesh = new Mesh();

      float topRadius = Mathf.Max(0, cone.TopRadius);
      float bottomRadius = Mathf.Max(0, cone.BottomRadius);
      float height = Mathf.Max(0, cone.Height);

      int triangleCount = m_resolution * 4;
      int vertexCount = m_resolution * 6;

      //Vector2[] uvs = new Vector2[vertexCount];
      Vector3[] vertices = new Vector3[vertexCount];
      Vector3[] normals = new Vector3[vertexCount];
      int[] triangles = new int[triangleCount * 3];

      float externalNormalY = (bottomRadius - topRadius) / height;
      

      // Loop over each "pie slice" of the cone. Create vertices on one side, six per slice with two on each point where side meets top/bottom, triangles arranged looping around the slice
      for (int i = 0; i < m_resolution; i++)
      {
        int currentVertex = i * 6;
        int nextCurrentVertex = ((i + 1) % m_resolution) * 6;

        float angle = i * Mathf.PI * 2 / m_resolution;
        float sinI = Mathf.Sin(angle);
        float cosI = Mathf.Cos(angle);

        vertices[currentVertex]     = new Vector3(0, height, 0);
        vertices[currentVertex + 1] = vertices[currentVertex + 2] = new Vector3(sinI * topRadius, height, cosI * topRadius);
        vertices[currentVertex + 3] = vertices[currentVertex + 4] = new Vector3(sinI * bottomRadius, 0, cosI * bottomRadius);
        vertices[currentVertex + 5] = new Vector3(0, 0, 0);

        normals[currentVertex]     = normals[currentVertex + 1] = new Vector3(0, 1, 0);
        normals[currentVertex + 2] = normals[currentVertex + 3] = new Vector3(sinI, externalNormalY, cosI).normalized;
        normals[currentVertex + 4] = normals[currentVertex + 5] = new Vector3(0, -1, 0); ;

        int currentTriangle = i * 4 * 3;

        triangles[currentTriangle]      = currentVertex;
        triangles[currentTriangle + 1]  = currentVertex + 1;
        triangles[currentTriangle + 2]  = nextCurrentVertex + 1;

        triangles[currentTriangle + 3]  = currentVertex + 2;
        triangles[currentTriangle + 4]  = currentVertex + 3;
        triangles[currentTriangle + 5]  = nextCurrentVertex + 3;

        triangles[currentTriangle + 6]  = currentVertex + 2;
        triangles[currentTriangle + 7]  = nextCurrentVertex + 3;
        triangles[currentTriangle + 8]  = nextCurrentVertex + 2;

        triangles[currentTriangle + 9]  = currentVertex + 4;
        triangles[currentTriangle + 11] = nextCurrentVertex + 4;
        triangles[currentTriangle + 10] = currentVertex + 5;
      }

      mesh.vertices = vertices;
      //m_mesh.uv = uvs; // TODO, possibly
      mesh.triangles = triangles;
      mesh.normals = normals;

      return mesh;
    }
예제 #22
0
        /// <summary>
        /// Generates custom shape mesh
        /// </summary>
        public static Mesh GenerateMesh(Collide.Shape shape)
        {
            Collide.HollowCone hollowCone = shape as Collide.HollowCone;
            Mesh mesh = new Mesh();

            float outerRadiusTop    = Mathf.Max(0, hollowCone.TopRadius);
            float outerRadiusBottom = Mathf.Max(0, hollowCone.BottomRadius);
            float innerRadiusTop    = Mathf.Max(0, hollowCone.TopRadius - hollowCone.Thickness);
            float innerRadiusBottom = Mathf.Max(0, hollowCone.BottomRadius - hollowCone.Thickness);
            float height            = Mathf.Max(0, hollowCone.Height);
            float innerTopPosition  = (innerRadiusTop > 0) ? height : hollowCone.Height * ((hollowCone.BottomRadius - hollowCone.Thickness) / (hollowCone.BottomRadius - hollowCone.TopRadius) - 0.5f);

            int triangleCount = m_resolution * 8;
            int vertexCount   = m_resolution * 8;

            //Vector2[] uvs = new Vector2[vertexCount];
            Vector3[] vertices  = new Vector3[vertexCount];
            Vector3[] normals   = new Vector3[vertexCount];
            int[]     triangles = new int[triangleCount * 3];

            float externalNormalY = (outerRadiusBottom - outerRadiusTop) / (height * 2);


            // Loop over each "pie slice" of the hollow cone. Vertices two per point of the slice, triangles also arranged looping around the slice
            for (int i = 0; i < m_resolution; i++)
            {
                int currentVertex     = i * 8;
                int nextCurrentVertex = ((i + 1) % m_resolution) * 8;

                float angle = i * Mathf.PI * 2 / m_resolution;
                float sinI  = Mathf.Sin(angle);
                float cosI  = Mathf.Cos(angle);

                vertices[currentVertex]     = new Vector3(sinI * innerRadiusTop, height, cosI * innerRadiusTop);
                vertices[currentVertex + 7] = new Vector3(sinI * innerRadiusTop, innerTopPosition, cosI * innerRadiusTop);
                vertices[currentVertex + 1] = vertices[currentVertex + 2] = new Vector3(sinI * outerRadiusTop, height, cosI * outerRadiusTop);
                vertices[currentVertex + 3] = vertices[currentVertex + 4] = new Vector3(sinI * outerRadiusBottom, 0, cosI * outerRadiusBottom);
                vertices[currentVertex + 5] = vertices[currentVertex + 6] = new Vector3(sinI * innerRadiusBottom, 0, cosI * innerRadiusBottom);

                normals[currentVertex]     = normals[currentVertex + 1] = new Vector3(0, 1, 0);
                normals[currentVertex + 2] = normals[currentVertex + 3] = new Vector3(sinI, externalNormalY, cosI).normalized;
                normals[currentVertex + 4] = normals[currentVertex + 5] = new Vector3(0, -1, 0);
                normals[currentVertex + 6] = normals[currentVertex + 7] = new Vector3(sinI, -externalNormalY, cosI).normalized;

                for (int j = 0; j < 8; j += 2)
                {
                    int currentTriangle = i * 4 * 6 + j * 3;
                    int nextJ           = (j + 1) % 8;

                    triangles[currentTriangle]     = currentVertex + j;
                    triangles[currentTriangle + 1] = currentVertex + nextJ;
                    triangles[currentTriangle + 2] = nextCurrentVertex + nextJ;

                    triangles[currentTriangle + 3] = currentVertex + j;
                    triangles[currentTriangle + 4] = nextCurrentVertex + nextJ;
                    triangles[currentTriangle + 5] = nextCurrentVertex + j;
                }
            }

            mesh.vertices = vertices;
            //m_mesh.uv = uvs; // TODO, possibly
            mesh.triangles = triangles;
            mesh.normals   = normals;

            return(mesh);
        }