You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Shader Graph位移顶点读取及可平铺噪声位移实现求助

解决方案:GPU顶点位移回读 + C#可平铺噪声实现

一、GPU顶点位移数据回读(结合Shader Graph)

针对Shader Graph中GPU端的顶点位移,要把数据回读到CPU用于实例化,可按以下步骤实现:

  • 步骤1:在Shader Graph中添加数据输出Pass

    1. 打开你的地形Shader Graph,新增一个Unlit类型的Pass(专门用于输出位移数据,避免影响渲染Pass)。
    2. 在这个Pass中,计算位移后的顶点世界坐标(原顶点世界坐标 + 噪声位移量)。
    3. 将这个坐标的X/Y/Z分量分别赋值给输出的RGBA通道(比如R=X, G=Y, B=Z, A=1),或者使用ComputeBuffer存储顶点数据(更高效)。
    4. 关闭该Pass的深度测试、剔除和光照,确保所有顶点数据都能被正确输出。
  • 步骤2:CPU端读取GPU数据

    • 方案A:使用RenderTexture读取
      1. 创建一个与地形区块顶点分辨率匹配的RenderTexture(比如区块是32x32顶点,RT尺寸设为32x32)。
      2. 调用Graphics.Blit(null, renderTexture, yourShaderGraphMaterial),将Shader的输出渲染到RT。
      3. 创建临时Texture2D,调用texture2D.ReadPixels(new Rect(0,0,rt.width,rt.height), 0,0)读取像素数据,再通过GetPixel(x,y)解析每个顶点的世界坐标。
    • 方案B:使用ComputeBuffer读取
      1. 在C#中创建ComputeBuffer,设置好顶点数据的结构(比如Vector3)和数量。
      2. 在Shader Graph中绑定该Buffer,在顶点着色器中将位移后的世界坐标写入Buffer。
      3. CPU端调用computeBuffer.GetData(vertexDataArray)读取所有顶点的位移数据。
    • 注意:GPU回读有性能损耗,仅在地形生成/更新完成后执行一次即可,不要每帧调用。

二、C#端实现可平铺的噪声位移

你当前代码无法实现平铺的核心原因是直接使用世界坐标计算噪声,导致相邻区块的噪声采样不连续。以下是修正后的实现:

核心思路

使用顶点局部坐标 + 区块网格偏移计算噪声,确保相邻区块的噪声采样坐标连续,实现无缝平铺。

修正后的代码

// 区块配置参数
public float chunkSize = 10f; // 单个区块的边长(比如10米)
public int chunkGridX = 0; // 当前区块在全局网格中的X索引(比如第2个区块填2)
public int chunkGridZ = 0; // 当前区块在全局网格中的Z索引
public float noiseScale = 0.1f;
public float heightMultiplier = 5f;

private void GenerateDisplacedMesh()
{
    Mesh mesh = GetComponent<MeshFilter>().mesh;
    Vector3[] originalVertices = mesh.vertices;
    Vector3[] displacedVertices = new Vector3[originalVertices.Length];

    for (int i = 0; i < originalVertices.Length; i++)
    {
        Vector3 localVertex = originalVertices[i];
        // 计算平铺噪声的采样坐标:局部坐标 + 区块的全局偏移
        float sampleX = (localVertex.x + chunkGridX * chunkSize) * noiseScale;
        float sampleZ = (localVertex.z + chunkGridZ * chunkSize) * noiseScale;
        // 计算高度(PerlinNoise返回0-1范围,乘以高度系数)
        float vertexHeight = Mathf.PerlinNoise(sampleX, sampleZ) * heightMultiplier;
        // 生成位移后的局部顶点
        displacedVertices[i] = new Vector3(localVertex.x, vertexHeight, localVertex.z);
    }

    mesh.vertices = displacedVertices;
    mesh.RecalculateNormals();
}

关键说明

  • chunkGridX和chunkGridZ:标记当前区块在全局网格中的位置,比如相邻的区块X索引+1,这样采样坐标会延续前一个区块的噪声序列,实现无缝平铺。
  • 避免直接使用世界坐标:世界坐标会因区块位置不同导致噪声采样断裂,而局部坐标+区块偏移能保证噪声的连续性。
  • 如果需要更复杂的噪声(比如多层八度噪声),可以叠加多次Mathf.PerlinNoise,每次调整scale和height,提升地形细节。

内容的提问来源于stack exchange,提问作者Povst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 05:55:19