FreshRSS

Normální zobrazení

Jsou dostupné nové články, klikněte pro obnovení stránky.
PředevčíremHlavní kanál

Height gradient generation from height map,using compute shader has weird artifacts

I am trying to generate the height gradient (the slope) for a heightmap of mine using a compute shader in Unity, and the result has weird ringing artifacts and I completely lost what could be wrong. I thought about it being a precision issue, but increasing the magnitudes of the height values or moving to doubles from floats didn't solve the issue... Height map: height map I want to use for gradient calculation Resulting gradient map, with values of the Y axis in the green channel pictured here:ringing artifacts in the resulting gradient

I also exported the texture to disk to check in Photoshop, and the artifacts are also there so this isn't a display issue...

My compute shader is super simple:

SamplerState samplerInput
{
    Filter = MIN_MAG_LINEAR_MIP_NEAREST;
    AddressU = Clamp;
    AddressV = Clamp;
};

float3 calcHeightandGrad(int posX, int posY)
{
    float x = posX;
    float y = posY;
    float res = 2048 - 1;
    double sample = Input.SampleLevel(samplerInput, (float2(x, y) / res), 0).x * 100;
    double topSample = Input.SampleLevel(samplerInput, (float2(x, y - 1) / res), 0).x * 100;
    double rightSample = Input.SampleLevel(samplerInput, (float2(x - 1, y) / res), 0).x * 100;
    
    double dx = rightSample - sample;
    double dy = topSample - sample;
    
    return float3(sample, dx, dy);
}
  • ✇Recent Questions - Game Development Stack Exchange
  • Marching cube terrain generated by compute shader gives strange errorLeo
    I'm creating my own terrain terrain system for Unity using marching cubes but I've run into a problem I'm stumped on. First I'll explain how it works: A compute shader creates an array of points placed in a 3D grid of sorts based on a given individual cube size, number of cubes per axis, and a number of chunks per axis in the terrain (right now it's working with only one chunk for simplicity). Each vertex also has a value property between 0 and 1, this is for the mesh generation next step and is
     

Marching cube terrain generated by compute shader gives strange error

I'm creating my own terrain terrain system for Unity using marching cubes but I've run into a problem I'm stumped on. First I'll explain how it works:

A compute shader creates an array of points placed in a 3D grid of sorts based on a given individual cube size, number of cubes per axis, and a number of chunks per axis in the terrain (right now it's working with only one chunk for simplicity). Each vertex also has a value property between 0 and 1, this is for the mesh generation next step and is set manually with an editor tool. This part works flawlessly.

Next, the mesh is generated one triangle at a time using the marching cube algorithm outlined here, and based a little on the project that's linked in the description here.

The code for the compute shader looks like this:

#pragma kernel CSMain
#include "MarchingTable.compute"

struct Vertex
{
    float3 position;
    float value;
};

struct Triangle
{
    float3 vertexC;
    float3 vertexB;
    float3 vertexA;
};

float surfaceLevel;
float3 chunkSize;

RWStructuredBuffer<Vertex> totalVertices;
AppendStructuredBuffer<Triangle> tBuffer;

float3 LerpVertex(float3 pointA, float3 pointB, float valueA, float valueB)
{
    float t = (surfaceLevel - valueA) / (valueB - valueA);
    return pointA + t * (pointB - pointA);
}

[numthreads(8, 1, 1)]
void CSMain(uint3 id : SV_DispatchThreadID, uint3 threadID: SV_DispatchThreadID)
{
  if (id.x >= chunkSize.y)
      return;

  uint chunkPower = (uint) ((chunkSize.x + 1) * (chunkSize.z + 1));
    
  uint componentY = threadID.x * (((uint) chunkSize.x + 1) * ((uint) chunkSize.z + 1));
    
  for (uint i = 0; i < chunkSize.x * chunkSize.z; i++)
  {   
      uint componentX = round(i % (uint) chunkSize.x);
      uint componentZ = round((i / (uint) chunkSize.x) * ((uint) chunkSize.x + 1));

      uint startPoint = componentX + componentZ + componentY;

      uint corners[8];

      corners[0] = startPoint;
      corners[1] = startPoint + 1;
      corners[2] = (uint) (startPoint + chunkSize.x + 2);
      corners[3] = (uint) (startPoint + chunkSize.x + 1);

      corners[4] = startPoint + chunkPower;
      corners[5] = startPoint + chunkPower + 1;
      corners[6] = (uint) (startPoint + chunkPower + chunkSize.x + 2);
      corners[7] = (uint) (startPoint + chunkPower + chunkSize.x + 1);

      int cubeIndex = 0;

      for (uint j = 0; j < 8; j++)
      {
          if (totalVertices[corners[j]].value < surfaceLevel)
              cubeIndex |= 1 << j;
      }
        
      int triangulation[16] = triangles[cubeIndex];
      
      for (uint k = 0; triangulation[k] != -1; k += 3)
      {
          int indexA1 = cornerIndexFromEdge[triangulation[k]][0];
          int indexB1 = cornerIndexFromEdge[triangulation[k]][1];

          int indexA2 = cornerIndexFromEdge[triangulation[k + 1]][0];
          int indexB2 = cornerIndexFromEdge[triangulation[k + 1]][1];
            
          int indexA3 = cornerIndexFromEdge[triangulation[k + 2]][0];
          int indexB3 = cornerIndexFromEdge[triangulation[k + 2]][1];
            
          float valueA1 = totalVertices[corners[indexA1]].value;
          float valueB1 = totalVertices[corners[indexB1]].value;

          float valueA2 = totalVertices[corners[indexA2]].value;
          float valueB2 = totalVertices[corners[indexB2]].value;
          float valueA3 = totalVertices[corners[indexA3]].value;
          float valueB3 = totalVertices[corners[indexB3]].value;
            
          Triangle tri;
            
          tri.vertexA = LerpVertex(totalVertices[corners[indexA1]].position, totalVertices[corners[indexB1]].position, valueA1, valueB1);
          tri.vertexB = LerpVertex(totalVertices[corners[indexA2]].position, totalVertices[corners[indexB2]].position, valueA2, valueB2);
          tri.vertexC = LerpVertex(totalVertices[corners[indexA3]].position, totalVertices[corners[indexB3]].position, valueA3, valueB3);
            
       tBuffer.Append(tri);
      }
   }
}

The C# code that dispatches it looks like this

void ConstructCube(ref TerrainDataObject.Chunk chunk, uint cIndex, uint chunkIndex)
{
    byte totalSize = sizeof(float) * 3 + sizeof(float);

    ComputeBuffer vertexBuffer = new ComputeBuffer(dataObject.vertices.Length, totalSize);
    vertexBuffer.SetData(dataObject.vertices);

    ComputeBuffer tBuffer = new ComputeBuffer((chunkSize.x * chunkSize.y * chunkSize.z) * 5, sizeof(float) * 3 * 3, ComputeBufferType.Append);
    ComputeBuffer tCountBuffer = new ComputeBuffer(1, sizeof(int), ComputeBufferType.Raw);

    vertexBuffer.SetCounterValue(0);
    meshGenerationShader.SetBuffer(0, "totalVertices", vertexBuffer);
    meshGenerationShader.SetBuffer(0, "tBuffer", tBuffer);
    meshGenerationShader.SetFloats("chunkSize", new float[3] { chunkSize.x, chunkSize.y, chunkSize.z });
    meshGenerationShader.SetFloat("surfaceLevel", surfaceLevel);

    meshGenerationShader.Dispatch(0, Mathf.CeilToInt(chunkSize.y/8f), 1, 1);

    ComputeBuffer.CopyCount(tBuffer, tCountBuffer, 0);
    int[] tCountArray = { 0 };
    tCountBuffer.GetData(tCountArray);
    int numTri = tCountArray[0];

    // Get tri data from shader
    Triangle[] tris = new Triangle[numTri];
    tBuffer.GetData(tris, 0, 0, tris.Length);

    vertexBuffer.Release();

    tBuffer.Release();
    tCountBuffer.Release();

    Vector3[] verts = new Vector3[numTri * 3];
    var meshTriangles = new int[numTri * 3];

    for (int i = 0; i < numTri; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            meshTriangles[i * 3 + j] = i * 3 + j;
            verts[i * 3 + j] = tris[i][j];
        }
    }

    chunk.vertices = verts;
    chunk.triangles = meshTriangles;
}

At first it appeared to work pretty well

But then at larger amounts of cubes, this happens

The triangles at the front of the chunk are not being generated and the triangles at the back are... well I'm not sure what they're doing.

Anyone know how to fix this? I figure it has something to do with the threads or thread groups but I'm not sure how. I'm also pretty new to compute shaders in general if that helps.

❌
❌