【发布时间】:2017-09-12 21:49:38
【问题描述】:
在 C# 中有什么方法可以在不复制的情况下调整数组的大小?我特别要寻找的是一种更改数组的 Length 属性的方法。数组具有固定的最大长度,并且只会调整为小于或等于最大大小的大小(允许重复使用数组)。
实际用例是 Unity3D 中的程序网格生成。执行此操作的内置方法仅限于使用列表(非常慢)并将例如 Vector3 数组分配给 mesh.vertices。数组分配方法是我想要的,但是当您将数组分配给mesh.vertices时,无法指定要复制的数组元素的数量(mesh.vertices不是数组,并将分配的数组复制到GPU) .
如果事先不知道程序生成的网格中的顶点数,则无法制作正确大小的数组,您必须采用缓慢的数组调整大小。
我知道 C# 通常不允许我正在寻找的那种数组大小调整,但我不得不问是否有一些半体面的低级黑客方式仍然可以完成它。
我现在使用的方法是分配一个具有最大顶点数的数组(它只是为生成的每个网格重复使用),填充它,然后分配另一个正确大小的数组并复制正确的数字将数组元素添加到新数组中(这比 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;
}
}
}
}
}
这是实际的网格生成器代码(针对 Mono 3.5 进行了优化,目前没有很好的文档记录):
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)));
}
}
}
}
}
}
【问题讨论】:
-
如何实现一个包含数组的 ReducableArray 类,int 长度不超过数组的大小,并且只使用数组的第一部分不超过长度?
-
@YairHalberstadt 是的,他可以称之为
List<T>! (你所描述的正是 List 已经做的) -
是的,但他说列表太慢了@ScottChamberlain
-
所以,你的解决方案也太慢了,因为你描述了
List<T> -
@Thorham 你能否更新你的问题,展示一个你迄今为止尝试过的太慢的例子?