Unity - материалы, заданные в скрипте, пропадают при перемещении любой камеры на некоторое расстояние от игрового объекта. - PullRequest
0 голосов
/ 08 мая 2020

Мой скрипт случайным образом генерирует воксельный ландшафт из трехмерного шума Перлина. Затем он устанавливает случайный материал для каждого куба. Я начал с существующего скрипта и переместил все вокруг, чтобы заставить его делать то, что я хочу, так что это не очень хорошо. (камера сцены или игровая камера) перемещается на некоторое расстояние от куба, материал кажется отсутствующим. Это недалеко / далеко, материалы исчезают через определенные промежутки времени. Если в одной камере отсутствует материал, в других камерах он выглядит нормально. Сначала это происходит в радиусе вокруг камеры, затем все расстояния после этого несовместимы. При каждом удалении приращения расстояние между приращениями увеличивается.

Это касается любого куба, созданного в первом поколении (из Start ()). Любой другой куб, созданный (из Update ()), не изменяется. Не имеет значения, сколько кубиков сгенерировано.

Ошибка в представлении игры

Ошибка в представлении сцены

void Start()
{
    Destroy(GameObject.Find("Meshys"));//destroy parent gameobject as well as children.
    foreach (Mesh m in meshes)//meshes still exist even though they aren't in the scene anymore. destroy them so they don't take up memory.
        Destroy(m); //I don't know if this even works anymore
    Generate();
}

[SerializeField]
private GameObject blockPrefab;//use a unit cube (1x1x1 like unity's default cube)

[SerializeField]
private int chunkSize = 50;//Size of area to generate

[SerializeField]
private float noiseScale = .05f;

[SerializeField, Range(0, 1)]
private float threshold = .5f;//Perlin noise threshold to generate a cube

[SerializeField]
private Material material_1;

[SerializeField]
private Material material_2;

[SerializeField]
private Material material_3;

[SerializeField]
private Material material_4;

[SerializeField]
private Material material_5;

[SerializeField]
private float chooseMesh;


[SerializeField]
private bool sphere = false;

float timeStuff = 0f;
float timeStuff_2 = 0f;
int startupTime;
float startupTime_2;

private List<Mesh> meshes = new List<Mesh>();//used to avoid memory issues

public float offsetX = 100f;
public float offsetY = 100f;
public float offsetZ = 100f;

public float scale = 20f;

private void Generate()
{
    float startTime = Time.realtimeSinceStartup;

    #region Create Mesh Data

    List<CombineInstance> blockData = new List<CombineInstance>();//this will contain the data for the final mesh

    Transform container = new GameObject("Meshys").transform;//create container object


    //go through each block position

    for (int x = 0; x < chunkSize; x++)
    {
        for (int y = 0; y < chunkSize; y++)
        {
            for (int z = 0; z < chunkSize; z++)
            {

                float noiseValue = Perlin3D(x * noiseScale, y * noiseScale, z * noiseScale);//get value of the noise at given x, y, and z.
                if (noiseValue >= threshold)
                {//is noise value above the threshold for placing a block?

                    //ignore this block if it's a sphere and it's outside of the radius (ex: in the corner of the chunk, outside of the sphere)
                    //distance between the current point with the center point. if it's larger than the radius, then it's not inside the sphere.
                    float raduis = chunkSize / 2;
                    if (sphere && Vector3.Distance(new Vector3(x, y, z), Vector3.one * raduis) > raduis)
                        continue;
                    GameObject blockMesh = Instantiate(blockPrefab, Vector3.zero, Quaternion.identity);//create a unit cube and store the mesh from it
                    MeshFilter blockMeshMesh = blockMesh.GetComponent<MeshFilter>();
                    MeshRenderer mr = blockMesh.GetComponent<MeshRenderer>();//Get mesh renderer component

                    blockMesh.transform.position = new Vector3(x, y, z);//move the unit cube to the intended position
                    chooseMesh = UnityEngine.Random.Range(0f, 1000f);
                    //Randomly decide a material for the cube - testing for different items with different rarities
                    if (chooseMesh >= 0f && chooseMesh < 500f)
                    {
                        mr.material = material_1;//set material to avoid evil pinkness of missing texture
                    }
                    else if (chooseMesh >= 500f && chooseMesh < 750f)
                    {
                        mr.material = material_2;
                    }
                    else if (chooseMesh >= 750f && chooseMesh < 875f)
                    {
                        mr.material = material_3;
                    }
                    else if (chooseMesh >= 875f && chooseMesh < 937.5f)
                    {
                        mr.material = material_4;
                    }
                    else
                    {
                        mr.material = material_5;
                    }

                    CombineInstance ci = new CombineInstance
                    {//copy the data off of the unit cube
                        mesh = blockMeshMesh.sharedMesh,
                        transform = blockMesh.transform.localToWorldMatrix,
                    };
                    blockData.Add(ci);//add the data to the list
                }

            }
        }
    }

    //Destroy(blockMesh.gameObject);//original unit cube is no longer needed. we copied all the data we need to the block list. - moved this elsewhere

    #endregion

    #region Separate Mesh Data

    //divide meshes into groups of 65536 vertices. Meshes can only have 65536 vertices so we need to divide them up into multiple block lists.

    List<List<CombineInstance>> blockDataLists = new List<List<CombineInstance>>();//we will store the meshes in a list of lists. each sub-list will contain the data for one mesh. same data as blockData, different format.
    int vertexCount = 0;
    blockDataLists.Add(new List<CombineInstance>());//initial list of mesh data
    for (int i = 0; i < blockData.Count; i++)
    {//go through each element in the previous list and add it to the new list.
        vertexCount += blockData[i].mesh.vertexCount;//keep track of total vertices
        if (vertexCount > 65536)
        {//if the list has reached it's capacity. if total vertex count is more then 65536, reset counter and start adding them to a new list.
            vertexCount = 0;
            blockDataLists.Add(new List<CombineInstance>());
            i--;
        }
        else
        {//if the list hasn't yet reached it's capacity. safe to add another block data to this list 
            blockDataLists.Last().Add(blockData[i]);//the newest list will always be the last one added

        }
    }

    #endregion

    #region Create Mesh



    //the creation of the final mesh from the data.


    foreach (List<CombineInstance> data in blockDataLists)
    {//for each list (of block data) in the list (of other lists)

        GameObject g2 = new GameObject("Meshy");//create gameobject for the mesh
        MeshFilter mf2 = g2.AddComponent<MeshFilter>();//add mesh component
        MeshRenderer mr2 = g2.AddComponent<MeshRenderer>();//add mesh renderer component
        g2.transform.parent = container;//set parent to the container we just made

        mf2.mesh.CombineMeshes(data.ToArray());//set mesh to the combination of all of the blocks in the list
        meshes.Add(mf2.mesh);//keep track of mesh so we can destroy it when it's no longer needed
        g2.AddComponent<MeshCollider>().sharedMesh = mf2.sharedMesh;//setting colliders takes more time




        /*
        mr.material = material;//set material to avoid evil pinkness of missing texture
        This is old but I kept it here in case I needed it again
        */


    }

    #endregion

    //Debug.Log("Loaded in " + (Time.realtimeSinceStartup - startTime) + " Seconds.");

}
void Update()
{
    int startupTime = Convert.ToInt32(Time.realtimeSinceStartup);
    float startupTime_2 = startupTime;
    float timeStuff = startupTime_2 / 60f;
    Debug.Log(startupTime);
    Debug.Log(timeStuff);
    float timeStuff_2 = timeStuff % 10;//Time in minutes to wait between generations.
    Debug.Log(timeStuff_2);
    //Regenerate terrain after time delay
    if (timeStuff_2 == 0)
    {
        Destroy(GameObject.Find("Meshys"));//destroy parent gameobject as well as children.
        Destroy(GameObject.Find("Cube(Clone)"));
        foreach (Mesh m in meshes)//meshes still exist even though they aren't in the scene anymore. destroy them so they don't take up memory.
            Destroy(m);
        Generate();
    }
}

//dunno how this works. copied it from somewhere.
float Perlin3D(float x, float y, float z)
{
    offsetX = UnityEngine.Random.Range(0f, 10f);
    offsetY = UnityEngine.Random.Range(0f, 10f);
    offsetZ = UnityEngine.Random.Range(0f, 10f);

    float xCoord = (float)x / 2048 + offsetX;
    float yCoord = (float)y / 2048 + offsetY;
    float zCoord = (float)z / 2048 + offsetZ;
    //Don't know what I did here but this makes it random and broken

    float ab = Mathf.PerlinNoise(xCoord, yCoord);
    float bc = Mathf.PerlinNoise(yCoord, zCoord);
    float ac = Mathf.PerlinNoise(xCoord, zCoord);

    float ba = Mathf.PerlinNoise(yCoord, xCoord);
    float cb = Mathf.PerlinNoise(zCoord, yCoord);
    float ca = Mathf.PerlinNoise(zCoord, xCoord);

    float abc = ab + bc + ac + ba + cb + ca;
    return abc / 6f;
}

Этот сценарий применяется к пустому объекту gameObject. Понятия не имею, что происходит. Будем признательны за любые указатели, где искать.

...