我帮你把这段话翻译成简体中文。
我是Reddit上的新手,呵呵所以如果我做错了什么请先谅解。
我正在尝试在我的游戏中添加草地,但是它得是性能很强的,查了一下好像是需要使用GPU实例化来实现高性能渲染,但是我不知道如何正确使用它。
我希望能将草地绘制到整个图像中的绿色区域。
目前我用一个空的游戏对象来检测各个绿色区域,使用射线检测来检测“草地区域”标记。
你能告诉我我在做什么错事吗?
以下是我的代码:
using UnityEngine;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
public class GrassBaker : MonoBehaviour
{
public GrassData dataAsset;//存储草地的数据
public float spacing = 0.5f;//射线距离
public float jitter = 0.2f;//随机位移值
public Vector2 areaSize = new Vector2(100, 100);//定义检测区域的大小
[ContextMenu("绘制草地")]
public void Bake()
{
dataAsset.matrices.Clear();
Vector3 origin = transform.position;
for (float x = -areaSize.x / 2; x < areaSize.x / 2; x += spacing)
{
for (float z = -areaSize.y / 2; z < areaSize.y / 2; z += spacing)
{
//添加一点随机值到射线起始点来避免正 grid 结构
float offsetX = Random.Range(-jitter, jitter);
float offsetZ = Random.Range(-jitter, jitter);
Vector3 rayStart = origin + new Vector3(x + offsetX, 10f, z + offsetZ);
if (Physics.Raycast(rayStart, Vector3.down, out RaycastHit hit, 20f))
{
if (hit.collider.CompareTag("Grass Area"))
{
//生成一个随机角度和轻微尺寸变化的矩阵
Quaternion rot = Quaternion.Euler(0, Random.Range(0, 360), 0);
Vector3 scale = Vector3.one * Random.Range(0.8f, 1.2f);
dataAsset.matrices.Add(Matrix4x4.TRS(hit.point, rot, scale));
}
}
}
}
#if UNITY_EDITOR
EditorUtility.SetDirty(dataAsset);
AssetDatabase.SaveAssets();
#endif
Debug.Log($"绘制完成! 储存 {dataAsset.matrices.Count} 个位置。");
}
}
以下是基于此脚本的数据资产类:
using UnityEngine;
using System.Collections.Generic;
[CreateAssetMenu(fileName = "NewGrassData", menuName = "Grass/Data Container")]
public class GrassData : ScriptableObject
{
public List<Matrix4x4> matrices = new List<Matrix4x4>();//储存草地的数据
}
这是用来渲染草地的脚本:
using UnityEngine;
public class GPUGrassRenderer : MonoBehaviour
{
public Mesh grassMesh;//草地的 mesh
public Material grassMaterial;//草地的材质
public GrassData dataAsset;//数据资产
private GraphicsBuffer meshPropertiesBuffer;//GPU Buffer
private RenderParams rp;//渲染参数
void Start()
{
if (dataAsset == null || dataAsset.matrices.Count == 0) return;
// 1. 初始化渲染参数
rp = new RenderParams(grassMaterial);
rp.worldBounds = new Bounds(Vector3.zero, Vector3.one * 10000); // 渲染范围
// 2. 创建GPU Buffer (Matrix4x4 是 64 字节)
meshPropertiesBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, dataAsset.matrices.Count, 64);
meshPropertiesBuffer.SetData(dataAsset.matrices.ToArray());
// 3. 链接buffer 到材质
grassMaterial.SetBuffer("_Properties", meshPropertiesBuffer);
}
void Update()
{
Debug.Log("我试图绘制 " + dataAsset.matrices.Count + " 个草地。");
if (meshPropertiesBuffer == null) return;
// 4. 渲染
Graphics.RenderMeshPrimitives(rp, grassMesh, 0, dataAsset.matrices.Count);
}
void OnDisable()
{
meshPropertiesBuffer?.Release();
}
}
以下是材质中自定义着色器的图表和自定义函数:
StructuredBufferfloat4x4> _Properties;
#if defined(UNITY_ANY_INSTANCING_ENABLED) || defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
// 取出这一实例的矩阵
float4x4 m = _Properties[unity_InstanceID];
// 手动转换到避免出错
float3 worldPos = float3(m._m03, m._m13, m._m23);
OutPos = InPos + worldPos;
#else
OutPos = InPos;
#endif
但是当我只测试了一个区域时,数据资产里有了大约 1300 个点,但是游戏中却只有在世界坐标 (0,0,0) Spawn 进入游戏。这是为什么呢?我知道 grasses 正确地加载进入游戏,因为我可以看到它们跳动的效果。而且我发现需要在自定义着色器中支持 GPU 实例化,但是我找不到这个设置。
如果你需要更多信息请告诉我,我的 Unity 知识非常有限。
评论 (0)