2017-09-12 7 views
0

C#でコピーを作成せずに配列のサイズを変更する方法はありますか?私が特に探しているのは、配列のLengthプロパティを変更する方法です。配列の長さは固定されており、最大サイズ以下のサイズにリサイズされます(配列の再利用が可能です)。C#で配列が縮む

実際のユースケースはUnity3Dの手続きメッシュ生成です。これを行うビルトインの方法は、リスト(非常に遅い)を使用し、Vector3sの配列をmesh.verticesなどに割り当てることに限定されています。配列の割り当て方法は私が望むものですが、配列をmesh.verticesに割り当てるときにコピーする配列要素の数を指定する方法はありません(mesh.verticesは配列ではなく、割り当てられた配列をGPUにコピーします) 。

手順的に生成されたメッシュ内の頂点の数があらかじめ不明な場合、適切なサイズの配列を作成することは不可能であり、低速な配列のサイズ変更に頼る必要があります。

私はC#は通常、私は探している配列の種類の種類を許可していないが知っているが、半分まともな低レベルのhackish方法はまだそれを行うために尋ねる必要があります。

私が使用している方法は、最大数の頂点(生成された各メッシュに対して単純に再利用される)の配列を割り当て、それを塗りつぶしてから、適切なサイズの別の配列を割り当てて、新しい配列への配列要素の数(これはArray.Resizeよりも速く、リストを使用するものより確かに高速です)。

編集:要求されたとおり適切なコードで更新されました(十分に文書化されていない、注意してください)。

これは、各チャンク(テストコード)のマップジェネレータを呼び出し:

for (int z = 0; z < size; z++) 
{ 
    for (int x = 0; x < size; x++) 
    { 
     Vector3 position = new Vector3(x * 32, 0, z * 32); 

     GameObject a = Instantiate(baseObject); 
     a.transform.position = position; 

     map.GenMap(position, model); // procedural model generation 

     blockMesh.SetModel(model); // set the model to generate the mesh from 
     blockMesh.GenMesh(); // generate actual mesh 
     blockMesh.CopyMesh(a.GetComponent<MeshFilter>().mesh); // copy mesh data do the Unity mesh 
    } 
} 

簡単なテストマップ生成:

public void GenMap(Vector3 position, Model map) 
{ 
    map.Clear(); 

    double par1 = 1000; 
    double par2 = 600; 
    double par3 = 500; 

    double par4 = 1.0/50.0; 
    double par5 = 1.0/25.0; 
    double par6 = 1.0/12.5; 

    double factor = (par1 + par2 + par3)/16; 

    if (factor != 0.0) 
    { 
     par1 /= factor; 
     par2 /= factor; 
     par3 /= factor; 
    } 

    Color32 color150 = map.palette[150]; 

    for (int z = 0; z < map.realDepth; z++) 
    { 
     double zPos = position.z + z; 

     for (int x = 0; x < map.realWidth; x++) 
     { 
      double xPos = position.x + x; 

      int e = 16 + (int) 
      (
       (noise.Noise(xPos * par4, zPos * par4) * par1) + 
       (noise.Noise(xPos * par5, zPos * par5) * par2) + 
       (noise.Noise(xPos * par6, zPos * par6) * par3) 
      ); 

      for (int y = 0; y < map.realHeight; y++) 
      { 
       if (y <= e) 
       { 
        int a = (255 - (32 - y) * 9); 

        if (a < 1) 
         a = 1; 

        color150.a = (byte)(a | 1); 
        map.voxel[x][y][z] = color150; 
       } 
      } 
     } 
    } 
} 

これは実際のメッシュ生成コードである(モノ3.5に最適化しませんウェル)今、文書化:ずっと私はuのを偶然見つけグーグル後

using UnityEngine; 
using System; 

public class BlockMesh 
{ 
    public Vector3[] vertices = new Vector3[65532]; 
    public Vector3[] normals = new Vector3[65532]; 
    public Vector2[] uvs = new Vector2[65532]; 
    public Color32[] colors = new Color32[65532]; 
    public int[] triangles = new int[65532 * 6/4]; 
    public int index = 0; 
    public Model model; 

    // set model and init arrays 

    public void SetModel(Model model) 
    { 
     this.model = model; 
    } 

    // copy mesh data to mesh 

    public void CopyMesh(Mesh mesh) 
    { 
     Vector3[] a = new Vector3[index * 4]; 

     Array.Copy(vertices, a, index * 4); 
     mesh.vertices = a; 

     Array.Copy(normals, a, index * 4); 
     mesh.normals = a; 

     Color32[] b = new Color32[index * 4]; 
     Array.Copy(colors, b, index * 4); 
     mesh.colors32 = b; 

     int[] c = new int[index * 6]; 
     Array.Copy(triangles, c, index * 6); 
     mesh.triangles = c; 

     Vector2[] d = new Vector2[index * 4]; 

     Array.Copy(uvs, d, index * 4); 
     mesh.uv = d; 
    } 

    // ambient occlusion uv constants 

    private const float pixelSize = 1.0f/4096.0f; 
    private const float tileSize = pixelSize * 256; 
    private const float adjust1 = pixelSize * 64; 
    private const float adjust2 = tileSize - 2 * adjust1; 

    // cube faces 

    private Vector3[] faceVertices1 = { new Vector3(0, 1, 0), new Vector3(0, 0, 0), new Vector3(0, 0, 0), new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(1, 0, 1) }; 
    private Vector3[] faceVertices2 = { new Vector3(1, 1, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 1), new Vector3(0, 0, 0), new Vector3(1, 0, 0) }; 
    private Vector3[] faceVertices3 = { new Vector3(0, 1, 1), new Vector3(0, 0, 1), new Vector3(0, 1, 0), new Vector3(0, 1, 1), new Vector3(0, 1, 1), new Vector3(1, 1, 1) }; 
    private Vector3[] faceVertices4 = { new Vector3(1, 1, 1), new Vector3(1, 0, 1), new Vector3(1, 1, 0), new Vector3(1, 1, 1), new Vector3(0, 1, 0), new Vector3(1, 1, 0) }; 

    private Vector3[] faceNormals = { Vector3.up, Vector3.down, Vector3.back, Vector3.forward, Vector3.left, Vector3.right }; 

    private void AddFace(int side, Vector3 position, Color32 color, int aop) 
    { 
     // mesh array indices 

     int index4 = index * 4; 
     int index6 = index * 6; 

     // ambient occlusion uv cords 

     float x1 = tileSize * (aop & 15) + adjust1; 
     float y1 = tileSize * (aop >> 4) + adjust1; 

     float x2 = x1 + adjust2; 
     float y2 = y1 + adjust2; 

     // put face into mesh 

     vertices[index4 + 0] = position + faceVertices1[side]; 
     vertices[index4 + 1] = position + faceVertices2[side]; 
     vertices[index4 + 2] = position + faceVertices3[side]; 
     vertices[index4 + 3] = position + faceVertices4[side]; 

     uvs[index4 + 0].x = x1; 
     uvs[index4 + 0].y = y1; 
     uvs[index4 + 1].x = x2; 
     uvs[index4 + 1].y = y1; 
     uvs[index4 + 2].x = x1; 
     uvs[index4 + 2].y = y2; 
     uvs[index4 + 3].x = x2; 
     uvs[index4 + 3].y = y2; 

     normals[index4 + 0] = faceNormals[side]; 
     normals[index4 + 1] = faceNormals[side]; 
     normals[index4 + 2] = faceNormals[side]; 
     normals[index4 + 3] = faceNormals[side]; 

     colors[index4 + 0] = color; 
     colors[index4 + 1] = color; 
     colors[index4 + 2] = color; 
     colors[index4 + 3] = color; 

     int tri = 0x08790936 >> ((side & 1) << 4); 

     triangles[index6 + 0] = index4 + ((tri >> 10) & 3); 
     triangles[index6 + 1] = index4 + ((tri >> 08) & 3); 
     triangles[index6 + 2] = index4 + ((tri >> 06) & 3); 
     triangles[index6 + 3] = index4 + ((tri >> 04) & 3); 
     triangles[index6 + 4] = index4 + ((tri >> 02) & 3); 
     triangles[index6 + 5] = index4 + (tri & 3); 

     index += 1; 
    } 

    // build mesh 

    public void GenMesh() 
    { 
     index = 0; 

     for (int z = 1; z <= model.depth; z++) 
     { 
      for (int y = 1; y <= model.height; y++) 
      { 
       for (int x = 1; x <= model.width; x++) 
       { 
        Color32 voxelColor = model.voxel[x][y][z]; 

        if (voxelColor.a == 0) 
         continue; 

        if (model.voxel[x][y + 1][z].a == 0) // top 
        { 
         AddFace(0, new Vector3(x, y, z), voxelColor, 
          (((model.voxel[x - 1][y + 1][z - 1].a) & 1) << 7) | 
          (((model.voxel[x + 0][y + 1][z - 1].a) & 1) << 6) | 
          (((model.voxel[x + 1][y + 1][z - 1].a) & 1) << 5) | 
          (((model.voxel[x - 1][y + 1][z + 0].a) & 1) << 4) | 
          (((model.voxel[x + 1][y + 1][z + 0].a) & 1) << 3) | 
          (((model.voxel[x - 1][y + 1][z + 1].a) & 1) << 2) | 
          (((model.voxel[x + 0][y + 1][z + 1].a) & 1) << 1) | 
          (((model.voxel[x + 1][y + 1][z + 1].a) & 1))); 
        } 

        if (model.voxel[x][y - 1][z].a == 0) // bottom 
        { 
         AddFace(1, new Vector3(x, y, z), voxelColor, 
          (((model.voxel[x - 1][y - 1][z - 1].a) & 1) << 7) | 
          (((model.voxel[x + 0][y - 1][z - 1].a) & 1) << 6) | 
          (((model.voxel[x + 1][y - 1][z - 1].a) & 1) << 5) | 
          (((model.voxel[x - 1][y - 1][z + 0].a) & 1) << 4) | 
          (((model.voxel[x + 1][y - 1][z + 0].a) & 1) << 3) | 
          (((model.voxel[x - 1][y - 1][z + 1].a) & 1) << 2) | 
          (((model.voxel[x + 0][y - 1][z + 1].a) & 1) << 1) | 
          (((model.voxel[x + 1][y - 1][z + 1].a) & 1))); 
        } 

        if (model.voxel[x][y][z - 1].a == 0) // back 
        { 
         AddFace(2, new Vector3(x, y, z), voxelColor, 
          (((model.voxel[x - 1][y - 1][z - 1].a) & 1) << 7) | 
          (((model.voxel[x + 0][y - 1][z - 1].a) & 1) << 6) | 
          (((model.voxel[x + 1][y - 1][z - 1].a) & 1) << 5) | 
          (((model.voxel[x - 1][y + 0][z - 1].a) & 1) << 4) | 
          (((model.voxel[x + 1][y + 0][z - 1].a) & 1) << 3) | 
          (((model.voxel[x - 1][y + 1][z - 1].a) & 1) << 2) | 
          (((model.voxel[x + 0][y + 1][z - 1].a) & 1) << 1) | 
          (((model.voxel[x + 1][y + 1][z - 1].a) & 1))); 
        } 

        if (model.voxel[x][y][z + 1].a == 0) // front 
        { 
         AddFace(3, new Vector3(x, y, z), voxelColor, 
          (((model.voxel[x - 1][y - 1][z + 1].a) & 1) << 7) | 
          (((model.voxel[x + 0][y - 1][z + 1].a) & 1) << 6) | 
          (((model.voxel[x + 1][y - 1][z + 1].a) & 1) << 5) | 
          (((model.voxel[x - 1][y + 0][z + 1].a) & 1) << 4) | 
          (((model.voxel[x + 1][y + 0][z + 1].a) & 1) << 3) | 
          (((model.voxel[x - 1][y + 1][z + 1].a) & 1) << 2) | 
          (((model.voxel[x + 0][y + 1][z + 1].a) & 1) << 1) | 
          (((model.voxel[x + 1][y + 1][z + 1].a) & 1))); 
        } 

        if (model.voxel[x - 1][y][z].a == 0) // left 
        { 
         AddFace(4, new Vector3(x, y, z), voxelColor, 
          (((model.voxel[x - 1][y - 1][z + 1].a) & 1) << 7) | 
          (((model.voxel[x - 1][y - 1][z + 0].a) & 1) << 6) | 
          (((model.voxel[x - 1][y - 1][z - 1].a) & 1) << 5) | 
          (((model.voxel[x - 1][y + 0][z + 1].a) & 1) << 4) | 
          (((model.voxel[x - 1][y + 0][z - 1].a) & 1) << 3) | 
          (((model.voxel[x - 1][y + 1][z + 1].a) & 1) << 2) | 
          (((model.voxel[x - 1][y + 1][z + 0].a) & 1) << 1) | 
          (((model.voxel[x - 1][y + 1][z - 1].a) & 1))); 
        } 

        if (model.voxel[x + 1][y][z].a == 0) // right 
        { 
         AddFace(5, new Vector3(x, y, z), voxelColor, 
          (((model.voxel[x + 1][y - 1][z + 1].a) & 1) << 7) | 
          (((model.voxel[x + 1][y - 1][z + 0].a) & 1) << 6) | 
          (((model.voxel[x + 1][y - 1][z - 1].a) & 1) << 5) | 
          (((model.voxel[x + 1][y + 0][z + 1].a) & 1) << 4) | 
          (((model.voxel[x + 1][y + 0][z - 1].a) & 1) << 3) | 
          (((model.voxel[x + 1][y + 1][z + 1].a) & 1) << 2) | 
          (((model.voxel[x + 1][y + 1][z + 0].a) & 1) << 1) | 
          (((model.voxel[x + 1][y + 1][z - 1].a) & 1))); 
        } 
       } 
      } 
     } 
    } 
} 
+0

配列を含むReducableArrayクラスと、配列のサイズまでのint長を実装し、長さまでの配列の最初の部分のみを使用する方法はありますか? –

+0

@YairHalberstadt yea、彼はそれを 'List 'と呼ぶことができました! –

+1

はい、しかし、リストが遅すぎると言いました@ScottChamberlain –

答えて

2

私が探していた安全なハッキリメソッド。私は完全性のために投稿していますが、誰もが実動コードで使用したいと思う解決策ではないようです。あなたが使用しない

非常に汚いハック:

using System; 
using UnityEngine; 

public unsafe class DirtyHack 
{ 
    public Vector3[] vertices = new Vector3[65532]; 
    public int index; 

    public void DirtyCopy(Mesh mesh) 
    { 
     fixed (void* ptr = vertices) 
     { 
      *((UIntPtr*)ptr - 1) = (UIntPtr)(index * 4); 
      mesh.vertices = vertices; 
      *((UIntPtr*)ptr - 1) = (UIntPtr)(65532); 
     } 
    } 
} 

編集:配列のサイズ変更中にGCによって移動されている配列を防ぐために、コードを変更しました。

+0

GCがコンストラクタとDirtyCopyの呼び出しの間で頂点配列を移動する場合はどうなりますか?次に、あなたは実際にランダムなメモリに書き込んでいます。これをしないでください。あなたは配列の長さを更新することはできません、それはあなたの質問に対する答えです。 – Asik

+0

@Asik - これは、私がこれを投稿したのは、完全なものであり、実際のプロダクションコードではないと書いた理由です。 – Thorham

+0

@Thorhamそれはかなり面白いハックですが、私はあなたの「汚れ」について同意します。したがって、配列のサイズはメモリ内の '&array [0] - 1'に格納されますか?それは理にかなっている。もしこれが安全にできるのだろうか?一時的なサイズ変更中に配列が移動されないようにする方法はありますか? – piojo