在unity中,编程获取SpeedTree绘制的子物体

2023-04-17by@srjsrjhi--vCDn&@ChatGPT.Model: gpt-3.5
srjsrjhi--vCDn

在unity中,编程获取SpeedTree绘制的子物体

Avatar
Avatar

可以使用以下代码获取SpeedTree绘制的子物体:

using UnityEngine;

public class SpeedTreeChildFinder : MonoBehaviour
{
    void Start()
    {
        // 获取SpeedTree绘制的子物体
        GameObject[] childObjects = GetSpeedTreeChildren(transform);

        // 在控制台输出子物体名称
        foreach (GameObject child in childObjects)
        {
            Debug.Log(child.name);
        }
    }

    // 递归查找SpeedTree绘制的子物体
    private GameObject[] GetSpeedTreeChildren(Transform parent)
    {
        // 存储SpeedTree子物体的列表
        var speedTreeChildren = new System.Collections.Generic.List<GameObject>();

        // 遍历子物体
        foreach (Transform child in parent)
        {
            // 如果子物体的名称包含"LOD"和"$",则为SpeedTree绘制的子物体
            if (child.name.Contains("LOD") && child.name.Contains("$"))
            {
                speedTreeChildren.Add(child.gameObject);
            }
            // 如果不是SpeedTree子物体,则递归查找其子物体
            else
            {
                var grandChildren = GetSpeedTreeChildren(child);
                if (grandChildren != null)
                {
                    speedTreeChildren.AddRange(grandChildren);
                }
            }
        }

        return speedTreeChildren.ToArray();
    }
}

该代码会在Start函数中获取SpeedTree绘制的子物体,并在控制台输出它们的名称。可以将该代码添加到场景中的任意一个物体上,并将该物体作为SpeedTree的父物体。注意,该代码只能获取SpeedTree绘制的子物体,而不能获取SpeedTree的其他组件(例如材质、贴图等)。

srjsrjhi--vCDn

在unity中,SpeedTree绘制的植被由多个子物体组成,单个子对象是多维材质球组成的复合对象,如何拆分获取每个材质球所属的子对象Mesh

Avatar
Avatar

可以通过以下代码拆分SpeedTree绘制的植被,获取每个材质球所属的子对象Mesh:

using UnityEngine;

public class SpeedTreeMeshSplitter : MonoBehaviour
{
    void Start()
    {
        // 获取SpeedTree绘制的子物体
        GameObject[] childObjects = GetSpeedTreeChildren(transform);

        // 拆分每个子对象的Mesh
        foreach (GameObject childObject in childObjects)
        {
            // 获取子对象的所有Mesh
            MeshFilter[] meshFilters = childObject.GetComponentsInChildren<MeshFilter>();

            // 遍历所有Mesh
            foreach (MeshFilter meshFilter in meshFilters)
            {
                // 创建一个新的GameObject,用于存储拆分出来的Mesh
                GameObject newObject = new GameObject(meshFilter.name);
                newObject.transform.position = meshFilter.transform.position;
                newObject.transform.rotation = meshFilter.transform.rotation;
                newObject.transform.localScale = meshFilter.transform.localScale;
                newObject.transform.parent = transform;

                // 创建一个新的MeshFilter,用于存储拆分出来的Mesh
                MeshFilter newMeshFilter = newObject.AddComponent<MeshFilter>();

                // 创建一个新的MeshRenderer,用于显示拆分出来的Mesh
                MeshRenderer newMeshRenderer = newObject.AddComponent<MeshRenderer>();
                newMeshRenderer.sharedMaterials = meshFilter.GetComponent<Renderer>().sharedMaterials;

                // 拆分Mesh
                Mesh mesh = meshFilter.mesh;
                for (int submeshIndex = 0; submeshIndex < mesh.subMeshCount; submeshIndex++)
                {
                    int[] indices = mesh.GetTriangles(submeshIndex);
                    Vector3[] vertices = mesh.vertices;
                    Vector3[] normals = mesh.normals;
                    Vector2[] uv = mesh.uv;
                    Vector2[] uv2 = mesh.uv2;

                    // 创建一个新的Mesh,用于存储拆分出来的子Mesh
                    Mesh subMesh = new Mesh();
                    subMesh.name = mesh.name + " (Submesh " + submeshIndex + ")";

                    // 设置Mesh的顶点、法线、UV、UV2和索引
                    subMesh.vertices = GetSubArray(vertices, indices);
                    subMesh.normals = GetSubArray(normals, indices);
                    subMesh.uv = GetSubArray(uv, indices);
                    subMesh.uv2 = GetSubArray(uv2, indices);
                    subMesh.triangles = GetSubTriangles(indices);

                    // 将拆分出来的子Mesh添加到新的MeshFilter中
                    if (submeshIndex == 0)
                    {
                        newMeshFilter.mesh = subMesh;
                    }
                    else
                    {
                        newMeshFilter.mesh = CombineMeshes(newMeshFilter.mesh, subMesh);
                    }
                }

                // 清空原始子对象的Mesh
                meshFilter.mesh = null;
            }
        }
    }

    // 递归查找SpeedTree绘制的子物体
    private GameObject[] GetSpeedTreeChildren(Transform parent)
    {
        // 存储SpeedTree子物体的列表
        var speedTreeChildren = new System.Collections.Generic.List<GameObject>();

        // 遍历子物体
        foreach (Transform child in parent)
        {
            // 如果子物体的名称包含"LOD"和"$",则为SpeedTree绘制的子物体
            if (child.name.Contains("LOD") && child.name.Contains("$"))
            {
                speedTreeChildren.Add(child.gameObject);
            }
            // 如果不是SpeedTree子物体,则递归查找其子物体
            else
            {
                var grandChildren = GetSpeedTreeChildren(child);
                if (grandChildren != null)
                {
                    speedTreeChildren.AddRange(grandChildren);
                }
            }
        }

        return speedTreeChildren.ToArray();
    }

    // 获取Mesh的子数组
    private T[] GetSubArray<T>(T[] array, int[] indices)
    {
        T[] subArray = new T[indices.Length];
        for (int i = 0; i < indices.Length; i++)
        {
            subArray[i] = array[indices[i]];
        }
        return subArray;
    }

    // 获取拆分出来的子Mesh的索引
    private int[] GetSubTriangles(int[] indices)
    {
        int[] subTriangles = new int[indices.Length / 3];
        for (int i = 0, j = 0; i < indices.Length; i += 3, j++)
        {
            subTriangles[j]
srjsrjhi--vCDn

如何unity中,如何使用GPU instancing技术,批量绘制由SpeedTree制作的包含多维子材质的复合子对象组成的植被预制体

Avatar
Avatar

使用GPU Instancing技术,可以提高绘制效率,减少绘制调用,从而优化游戏性能。下面是实现GPU Instancing技术,批量绘制由SpeedTree制作的包含多维子材质的复合子对象组成的植被预制体的步骤:

  1. 将SpeedTree预制体的Mesh Renderer组件的Material属性设置为使用Instancing的材质(例如Standard Instanced)。

  2. 在SpeedTree预制体的Mesh Renderer组件中,为每个子材质都设置一个材质球,并将其保存在一个数组中(例如materials)。

  3. 在SpeedTree预制体的脚本中,使用Graphics.DrawMeshInstanced函数来批量绘制SpeedTree预制体。

以下是一个示例代码,用于批量绘制SpeedTree预制体:

using UnityEngine;

public class SpeedTreeInstancer : MonoBehaviour
{
    public GameObject speedTreePrefab;
    public int countX = 10;
    public int countZ = 10;
    public float spacing = 10f;

    private Matrix4x4[] matrices;
    private MaterialPropertyBlock[] propertyBlocks;

    void Start()
    {
        // 获取SpeedTree预制体的Mesh
        Mesh speedTreeMesh = speedTreePrefab.GetComponentInChildren<MeshFilter>().sharedMesh;

        // 获取SpeedTree预制体的所有子材质
        Material[] materials = speedTreePrefab.GetComponentInChildren<MeshRenderer>().sharedMaterials;

        // 创建Matrix4x4数组,用于存储每个SpeedTree的位置和旋转信息
        matrices = new Matrix4x4[countX * countZ];
        int index = 0;
        for (int i = 0; i < countX; i++)
        {
            for (int j = 0; j < countZ; j++)
            {
                Vector3 position = new Vector3(i * spacing, 0f, j * spacing);
                Quaternion rotation = Quaternion.identity;
                matrices[index++] = Matrix4x4.TRS(position, rotation, Vector3.one);
            }
        }

        // 创建MaterialPropertyBlock数组,用于存储每个SpeedTree的子材质信息
        propertyBlocks = new MaterialPropertyBlock[materials.Length];
        for (int i = 0; i < materials.Length; i++)
        {
            propertyBlocks[i] = new MaterialPropertyBlock();
            propertyBlocks[i].SetFloat("_Glossiness", materials[i].GetFloat("_Glossiness"));
            propertyBlocks[i].SetFloat("_Metallic", materials[i].GetFloat("_Metallic"));
            propertyBlocks[i].SetTexture("_MainTex", materials[i].GetTexture("_MainTex"));
        }

        // 批量绘制SpeedTree预制体
        Graphics.DrawMeshInstanced(speedTreeMesh, 0, materials[0], matrices, countX * countZ, propertyBlocks);
    }
}

在该代码中,首先获取SpeedTree预制体的Mesh和所有子材质。然后,创建一个Matrix4x4数组,用于存储每个SpeedTree的位置和旋转信息。接着,创建一个MaterialPropertyBlock数组,用于存储每个SpeedTree的子材质信息。最后,调用Graphics.DrawMeshInstanced函数来批量绘制SpeedTree预制体。

在执行该代码之前,需要将SpeedTree预制体的Mesh Renderer组件的Material属性设置为使用Instancing的材质,并且为每个子材质都设置一个材质球。

srjsrjhi--vCDn

SpeedTree绘制的植被预制体下有多个子对象,子对象上有多个材质球,如何在unity中使用GPU instancing技术批量绘制植被

Avatar
Avatar

使用GPU Instancing技术,可以提高绘制效率,减少绘制调用,从而优化游戏性能。下面是实现GPU Instancing技术,批量绘制SpeedTree制作的包含多个子对象和多个材质球的植被预制体的步骤:

  1. 在SpeedTree预制体的Mesh Renderer组件中,为每个子对象的每个材质球都设置一个材质球实例,并将其保存在一个数组中(例如materialInstances)。

  2. 在SpeedTree预制体的脚本中,使用Graphics.DrawMeshInstanced函数来批量绘制SpeedTree预制体。

  3. 在调用Graphics.DrawMeshInstanced函数之前,需要创建一个MaterialPropertyBlock实例,并将其传递给Graphics.DrawMeshInstanced函数。

以下是一个示例代码,用于批量绘制SpeedTree制作的植被预制体:

using UnityEngine;

public class SpeedTreeInstancer : MonoBehaviour
{
    public GameObject speedTreePrefab;
    public int countX = 10;
    public int countZ = 10;
    public float spacing = 10f;

    private Matrix4x4[] matrices;
    private MaterialInstance[] materialInstances;

    void Start()
    {
        // 获取SpeedTree预制体的Mesh
        Mesh speedTreeMesh = speedTreePrefab.GetComponentInChildren<MeshFilter>().sharedMesh;

        // 获取SpeedTree预制体的所有子对象和材质球实例
        Renderer[] renderers = speedTreePrefab.GetComponentsInChildren<Renderer>();
        MaterialInstance[] materialInstances = new MaterialInstance[renderers.Length];
        for (int i = 0; i < renderers.Length; i++)
        {
            Material[] materials = renderers[i].sharedMaterials;
            MaterialInstance[] instances = new MaterialInstance[materials.Length];
            for (int j = 0; j < materials.Length; j++)
            {
                instances[j] = new MaterialInstance(materials[j]);
            }
            materialInstances[i] = new MaterialInstance(renderers[i], instances);
        }

        // 创建Matrix4x4数组,用于存储每个SpeedTree的位置和旋转信息
        matrices = new Matrix4x4[countX * countZ];
        int index = 0;
        for (int i = 0; i < countX; i++)
        {
            for (int j = 0; j < countZ; j++)
            {
                Vector3 position = new Vector3(i * spacing, 0f, j * spacing);
                Quaternion rotation = Quaternion.identity;
                matrices[index++] = Matrix4x4.TRS(position, rotation, Vector3.one);
            }
        }

        // 创建MaterialPropertyBlock实例,用于存储每个SpeedTree的材质球实例信息
        MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
        for (int i = 0; i < materialInstances.Length; i++)
        {
            for (int j = 0; j < materialInstances[i].instances.Length; j++)
            {
                propertyBlock.SetColor("_Color" + j, materialInstances[i].instances[j].color);
                propertyBlock.SetTexture("_MainTex" + j, materialInstances[i].instances[j].mainTexture);
            }
            materialInstances[i].renderer.SetPropertyBlock(propertyBlock);
        }

        // 批量绘制SpeedTree预制体
        Graphics.DrawMeshInstanced(speedTreeMesh, 0, materialInstances[0].renderer.sharedMaterial, matrices, countX * countZ, propertyBlock);
    }

    private class MaterialInstance
    {
        public Renderer renderer;
        public MaterialInstance[] instances;

        public MaterialInstance(Renderer renderer, MaterialInstance[] instances)
        {
            this.renderer = renderer;
            this.instances = instances;
        }
    }

    private class MaterialInstance
    {
        public Color color;
        public Texture mainTexture;

        public MaterialInstance(Material material)
        {
            this.color = material.color;
            this.mainTexture = material.mainTexture;
        }
    }
}

在该代码中,首先获取SpeedTree预制体的Mesh和所有子对象的材质球实例。然后,创建一个Matrix4x4数组,用于存储每个SpeedTree的位置和旋转信息。接着,创建一个MaterialPropertyBlock实例,用于存储每个SpeedTree的材质球实例信息。在MaterialPropertyBlock实

srjsrjhi--vCDn

上诉代码中出现了两个同名的class MaterialInstance,显示报错

Avatar
Avatar

An error occurred with your deployment

EDGE_FUNCTION_INVOCATION_TIMEOUT

srjsrjhi--vCDn

SpeedTree绘制的植被预制体由多个Child子对象组成,Child子对象上有多个子材质球muti-Material,保留父物体LOD信息的同时在unity中使用GPU instancing技术批量绘制植被

Avatar
Avatar

A server error has occurred

INTERNAL_SERVER_ERROR

srjsrjhi--vCDn

SpeedTree绘制的植被预制体由多个Child子对象组成,Child子对象上有多个子材质球muti-Material,保留父物体LOD信息的同时在unity中使用GPU instancing技术批量绘制植被

Avatar
Avatar

An error occurred with your deployment

EDGE_FUNCTION_INVOCATION_TIMEOUT