zoukankan      html  css  js  c++  java
  • (九)球体

    1.概述

    球体比较复杂,涉及到极点位置会出现聚集的问题,本文采用常规方法绘制球体,然后借鉴他人的方法,通过正八面体拆分的方法生成球体mesh。

    2.常规方法

    常规方法就是通过极坐标系,分别计算球体表面的坐标,然后依次生成三角形。问题在于当划分较细时,球体两端的网格会比较细,比较聚集。

    2.1 基类

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    [RequireComponent(typeof(MeshFilter),typeof(MeshRenderer))]
    public class CreateMeshBase : MonoBehaviour
    {
        MeshFilter meshFilter;
    
        protected Mesh mesh;
    
        protected virtual Vector3[] Vertices { get; }
        protected virtual int[] Triangles { get; }
        protected virtual Vector3[] Normals { get; }
        protected virtual Vector4[] Tangents { get; }
        protected virtual Vector2[] Uvs { get; }
        protected virtual string MeshName { get; }
    
        protected virtual void Start()
        {
            GetMeshFilter();
        }
    
        protected virtual void Reset()
        {
            GetMeshFilter();
        }
    
        protected virtual void OnValidate()
        {
            GetMeshFilter();
        }
    
        void GetMeshFilter()
        {
            if (meshFilter == null)
            {
                meshFilter = GetComponent<MeshFilter>();
                mesh = new Mesh();            
            }
    
            mesh.triangles = null;
            mesh.uv = null;
            mesh.vertices = null;
            mesh.tangents = null;
    
            mesh.name = MeshName;
            mesh.vertices = Vertices;
            mesh.triangles = Triangles;
            mesh.uv = Uvs;
            mesh.normals = Normals;
            mesh.tangents = Tangents;
    
            meshFilter.mesh = mesh;
        }
    
        private void OnDrawGizmos()
        {
            if (Vertices == null) return;
    
            Gizmos.color = Color.red;
            Gizmos.DrawSphere(Vector3.zero, 0.5f);
    
            Gizmos.color = Color.blue;
    
            for (int i = 0; i < Vertices.Length; i++)
            {
                Gizmos.DrawSphere(Vertices[i], 0.3f);
            }
        }
    }
    
    

    2.2 球体mesh

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class CreateSphere : CreateMeshBase
    {
        public float radius = 10;
        public int horizontalSize = 10;
        public int verticalSize = 10;
    
        protected override string MeshName
        {
            get
            {
                return "Sphere mesh";
            }
        }
    
        protected override Vector3[] Vertices
        {
            get
            {
                Vector3[] vertices = new Vector3[(horizontalSize + 1) * (verticalSize + 1)];
    
                float horizontalDelta = 2 * Mathf.PI / horizontalSize;
                float verticalDelta = 2 * Mathf.PI / verticalSize;
    
                for (int i = 0; i < verticalSize + 1; i++)
                {
                    float rad = i * verticalDelta;
                    float subRadius = radius * Mathf.Sin(rad);
                    float y = radius * Mathf.Cos(rad);
    
                    for (int j = 0; j < horizontalSize; j++)
                    {
                        int index = i * (horizontalSize + 1) + j;
                        float x = subRadius * Mathf.Cos(j * horizontalDelta);
                        float z = subRadius * Mathf.Sin(j * horizontalDelta);
    
                        vertices[index] = new Vector3(x, y, z);
                    }
                }
                return vertices;
            }
        }
    
        protected override int[] Triangles
        {
            get
            {
                int[] triangles = new int[horizontalSize * verticalSize * 2 * 3];
    
                for (int i = 0; i < verticalSize; i++)
                {
                    for (int j = 0; j < horizontalSize; j++)
                    {
                        int index = (i * horizontalSize + j) * 6;
    
                        triangles[index] = i * (horizontalSize + 1) + j + 1;
                        triangles[index + 2] = i * (horizontalSize + 1) + j;
                        triangles[index + 1] = (i + 1) * (horizontalSize + 1) + j;
    
                        triangles[index + 3] = i * (horizontalSize + 1) + j + 1;
                        triangles[index + 5] = (i + 1) * (horizontalSize + 1) + j;
                        triangles[index + 4] = (i + 1) * (horizontalSize + 1) + j + 1;
                    }
                }
                return triangles;
            }
        }
    }
    
    

    3.正八面细分法

    正八面体球则是通过正八面体,对边长进行划分,生成一系列的点,将这些点归一化即可得到单位球体,原文再此

    3.1 代码

    using UnityEngine;
    using System.Collections;
    
    [RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
    public class DrawOctahedronSphere : MonoBehaviour
    {
        public Material mat;
    
        public int subdivisions;
        public int radius;
    
        private static Vector3[] directions = {
            Vector3.left,
            Vector3.back,
            Vector3.right,
            Vector3.forward
        };
    
        void Start()
        {
            DrawSphere(subdivisions, radius);
        }
    
        private void OnValidate()
        {
            DrawSphere(subdivisions, radius);
        }
    
        public void DrawSphere(int subdivisions = 0, float radius = 1)
        {
            if (subdivisions > 4)
            {
                subdivisions = 4;
            }
    
            //gameObject.GetComponent<MeshRenderer>().material = mat;
    
            Mesh mesh = GetComponent<MeshFilter>().mesh;
            mesh.Clear();
    
            int resolution = 1 << subdivisions;
            Vector3[] vertices = new Vector3[(resolution + 1) * (resolution + 1) * 4 - 3 * (resolution * 2 + 1)];
            int[] triangles = new int[(1 << (subdivisions * 2 + 3)) * 3];
            CreateOctahedron(vertices, triangles, resolution);
    
            if (radius != 1f)
            {
                for (int i = 0; i < vertices.Length; i++)
                {
                    vertices[i] *= radius;
                }
            }
    
            Vector3[] normals = new Vector3[vertices.Length];
            Normalize(vertices, normals);
    
            mesh.vertices = vertices;
            mesh.triangles = triangles;
            mesh.normals = normals;
    
        }
    
        private static void CreateOctahedron(Vector3[] vertices, int[] triangles, int resolution)
        {
            int v = 0, vBottom = 0, t = 0;
    
            vertices[v++] = Vector3.down;
    
            for (int i = 1; i <= resolution; i++)
            {
                float progress = (float)i / resolution;
                Vector3 from, to;
                vertices[v++] = to = Vector3.Lerp(Vector3.down, Vector3.forward, progress);
                for (int d = 0; d < 4; d++)
                {
                    from = to;
                    to = Vector3.Lerp(Vector3.down, directions[d], progress);
                    t = CreateLowerStrip(i, v, vBottom, t, triangles);
                    v = CreateVertexLine(from, to, i, v, vertices);
                    vBottom += i > 1 ? (i - 1) : 0;
                }
                vBottom = v - 1 - i * 4;
            }
    
            for (int i = resolution - 1; i >= 1; i--)
            {
                float progress = (float)i / resolution;
                Vector3 from, to;
                vertices[v++] = to = Vector3.Lerp(Vector3.up, Vector3.forward, progress);
                for (int d = 0; d < 4; d++)
                {
                    from = to;
                    to = Vector3.Lerp(Vector3.up, directions[d], progress);
                    t = CreateUpperStrip(i, v, vBottom, t, triangles);
                    v = CreateVertexLine(from, to, i, v, vertices);
                    vBottom += i + 1;
                }
                vBottom = v - 1 - i * 4;
            }
    
            vertices[vertices.Length - 1] = Vector3.up;
    
            for (int i = 0; i < 4; i++)
            {
                triangles[t++] = vBottom;
                triangles[t++] = v;
                triangles[t++] = ++vBottom;
            }
        }
    
        private static int CreateVertexLine(Vector3 from, Vector3 to, int steps, int v, Vector3[] vertices)
        {
            for (int i = 1; i <= steps; i++)
            {
                vertices[v++] = Vector3.Lerp(from, to, (float)i / steps);
            }
            return v;
        }
    
        private static int CreateLowerStrip(int steps, int vTop, int vBottom, int t, int[] triangles)
        {
            for (int i = 1; i < steps; i++)
            {
                triangles[t++] = vBottom;
                triangles[t++] = vTop - 1;
                triangles[t++] = vTop;
    
                triangles[t++] = vBottom++;
                triangles[t++] = vTop++;
                triangles[t++] = vBottom;
            }
            triangles[t++] = vBottom;
            triangles[t++] = vTop - 1;
            triangles[t++] = vTop;
            return t;
        }
    
        private static int CreateUpperStrip(int steps, int vTop, int vBottom, int t, int[] triangles)
        {
            triangles[t++] = vBottom;
            triangles[t++] = vTop - 1;
            triangles[t++] = ++vBottom;
            for (int i = 1; i <= steps; i++)
            {
                triangles[t++] = vTop - 1;
                triangles[t++] = vTop;
                triangles[t++] = vBottom;
    
                triangles[t++] = vBottom;
                triangles[t++] = vTop++;
                triangles[t++] = ++vBottom;
            }
            return t;
        }
    
    
        private static void Normalize(Vector3[] vertices, Vector3[] normals)
        {
            for (int i = 0; i < vertices.Length; i++)
            {
                normals[i] = vertices[i] = vertices[i].normalized;
            }
        }
    
    }
    
  • 相关阅读:
    SQL函数 Convert,dateadd
    WebBrowser.ExecWB的完整说明
    GetShortPathName函数
    winmm.dll包含函数
    C# 操作Excel大全
    C#操作目录和文件
    File操作
    C#中对EXCEL保存的SAVEAS方法说明
    dataTable 、dataView、Dataset 区别
    System.Windows.Forms.Application.DoEvents();
  • 原文地址:https://www.cnblogs.com/llstart-new0201/p/12256189.html
Copyright © 2011-2022 走看看