2013-12-22 6 views
2

У меня проблема с индексированием массива на GPU в Compute Shader, и я застрял с ним в течение нескольких недель.Unity Compute Shader, массив Индексирование через SV_DispatchThreadID

Я пытаюсь использовать значение x SV_DispatchThreadID как индекс моего массива частиц (как это показано в некотором примере в Интернете).

Он работает ... Но переменная типа threadID (в основной функции) всегда возвращается 0,3,6,9,12,15 ... не 0,1,2,3,4, ...

Мой диспетчерский вызов на стороне процессора: Отправка (64, 1, 1);

Я пробовал много конфигураций диспетчеризации (32,16,1), (128,1,1), ... со многими конфигурациями numards (1,1,1), (32,32,1), (16,16,1) ... но всегда тот же результат ... threadID НИКОГДА не упорядочен.

Как я могу получить упорядоченный индекс? : (... всегда получает индекс, как 0,3,6,9, ...

Любое предложение

Большое спасибо

Вот мой CS ядро ​​и мой источник C#:.

#pragma kernel CSMain 

float dt; 
float time; 
float pi; 

uint maxParticles = 1024; 
float maxAge; 

struct Particle 
{ 
    int   index; 
    float3  position; 
    float3  velocity; 
    float  size; 
    float  age; 
    float  normAge; 
    int   type;  
}; 

RWStructuredBuffer <Particle> particles; 

[numthreads(1, 1, 1)] 

void CSMain (uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex)   
{ 
    uint index = DTid.x; 

    if (index < maxParticles) 
    { 
     Particle p = particles[index]; 
     p.position.y = p.index; //just check if the index is correct by giving a Y position 
     particles[index] = p; 
    } 

} 

C# код для создания ComputeBuffer и другие вещи:

using UnityEngine; 
using System.Collections; 
using System.Runtime.InteropServices; 

public class SimpleEmitter : MonoBehaviour 
{ 
    struct Particle 
    { 
     public int   index; 
     public Vector3  position; 
     public Vector3  velocity; 
     public float  size; 
     public float  age; 
     public float  normAge; 
     public int   type; 
    } 

    public ComputeShader computeShader; 
    public Material material; 
    public int maxParticles = 1000000; 
    public float maxAge = 3.0f; 
    public float particleSize = 0.5f; 

    private ComputeBuffer particles; 
    private int particleSizeOf; 

    void Start() 
    { 
     Particle p = new Particle(); 
     particleSizeOf = Marshal.SizeOf(p); 

     Particle[] pInitBuffer = new Particle[maxParticles]; 

     for (int i = 0; i < maxParticles; i++) 
     { 
      p = new Particle(); 
      p.index = i; 
      p.type = 0;    
      p.age = 0; 
      p.normAge = 0.1f; 
      p.size = particleSize * 0.5f + Random.value * particleSize;      
      p.velocity = new Vector3(0, 0, 0); 

      pInitBuffer[i] = p; 
     } 

     particles = new ComputeBuffer(maxParticles, particleSizeOf, ComputeBufferType.Default); 
     particles.SetData(pInitBuffer); 

     computeShader.SetBuffer(0, "particles", particles); 
    } 

    void Update() 
    {  
     computeShader.SetFloat("dt", Time.deltaTime); 
     computeShader.SetFloat("time", Time.time); 
     computeShader.SetFloat("pi", Mathf.PI);  
     computeShader.SetInt("maxParticles", maxParticles);     
     computeShader.SetFloat("maxAge", maxAge); 

     computeShader.Dispatch(0, 64, 1, 1);    
    } 

    public void OnPostRender() 
    { 
     material.SetPass(0); 
     material.SetFloat("maxAge", maxAge); 
     material.SetBuffer("particles", particles); 

     Graphics.DrawProcedural(MeshTopology.Triangles, maxParticles, 0); 
    } 

    void OnDisable() 
    { 
     particles.Release(); 
    } 
} 

Здесь Vertex, геом и Pixel Shader :

Shader "Custom/SimpleRS" 
{ 
    Properties 
    { 
     _ParticleTexture ("Diffuse Tex", 2D) = "white" {} 
     _Ramp1Texture ("G_Ramp1", 2D) = "white" {} 
    } 

    SubShader 
    { 
     Pass 
     { 
      Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" } 
      Blend OneMinusDstColor One 
      Cull Off 
      Lighting Off 
      ZWrite Off 
      Fog { Color (0,0,0,0) } 


      CGPROGRAM 
      #pragma target 5.0 
      #pragma vertex VSMAIN 
      #pragma fragment PSMAIN 
      #pragma geometry GSMAIN 
      #include "UnityCG.cginc" 

      struct Particle 
      { 
       int index; 
       float3 position; 
       float3 velocity; 
       float size; 
       float age; 
       float normAge; 
       int type; 

      }; 

      StructuredBuffer<Particle> particles; 

      Texture2D     _ParticleTexture;   
      SamplerState    sampler_ParticleTexture; 

      Texture2D     _Ramp1Texture; 
      SamplerState    sampler_Ramp1Texture; 

      float maxAge; 
      float maxRad; 

      struct VS_INPUT 
      { 
       uint vertexid   : SV_VertexID; 
      }; 
      //-------------------------------------------------------------------------------- 
      struct GS_INPUT 
      { 
       float4 position   : SV_POSITION; 
       float size    : TEXCOORD0; 
       float age    : TEXCOORD1; 
       float type    : TEXCOORD2; 
      }; 
      //-------------------------------------------------------------------------------- 
      struct PS_INPUT 
      { 
       float4 position   : SV_POSITION; 
       float2 texcoords  : TEXCOORD0; 
       float size    : TEXCOORD1; 
       float age    : TEXCOORD2; 
       float type    : TEXCOORD3; 
      }; 
      //-------------------------------------------------------------------------------- 
      GS_INPUT VSMAIN(in VS_INPUT input) 
      { 
       GS_INPUT output; 

       output.position.xyz = particles[input.vertexid].position; 
       output.position.w = 1.0;     
       output.age = particles[input.vertexid].normAge; 
       output.size = particles[input.vertexid].size; 
       output.type = particles[input.vertexid].type; 
       return output; 
      } 
      //-------------------------------------------------------------------------------- 
      [maxvertexcount(4)] 
      void GSMAIN(point GS_INPUT p[1], inout TriangleStream<PS_INPUT> triStream) 
      {   
       float4 pos = mul(UNITY_MATRIX_MVP, p[0].position); 

       float halfS = p[0].size * 0.5f; 
       float4 offset = mul(UNITY_MATRIX_P, float4(halfS, halfS, 0, 1)); 

       float4 v[4]; 
       v[0] = pos + float4(offset.x, offset.y, 0, 1); 
       v[1] = pos + float4(offset.x, -offset.y, 0, 1); 
       v[2] = pos + float4(-offset.x, offset.y, 0, 1); 
       v[3] = pos + float4(-offset.x, -offset.y, 0, 1); 

       PS_INPUT pIn; 
       pIn.position = v[0]; 
       pIn.texcoords = float2(1.0f, 0.0f); 

        pIn.size = p[0].size; 
        pIn.age = p[0].age; 
        pIn.type = p[0].type;      

       triStream.Append(pIn); 

       pIn.position = v[1]; 
       pIn.texcoords = float2(1.0f, 1.0f); 
       triStream.Append(pIn); 

       pIn.position = v[2]; 
       pIn.texcoords = float2(0.0f, 0.0f); 
       triStream.Append(pIn); 

       pIn.position = v[3]; 
       pIn.texcoords = float2(0.0f, 1.0f); 
       triStream.Append(pIn);     
      } 
      //-------------------------------------------------------------------------------- 
      float4 PSMAIN(in PS_INPUT input) : COLOR 
      { 
       float4 color = _ParticleTexture.Sample(sampler_ParticleTexture, input.texcoords); 
       float4 tint = _Ramp1Texture.Sample(sampler_Ramp1Texture, float2(min(1.0, input.age),0)); 
       color *= tint; 

       if (input.age == 0) discard; 

       return color; 
      } 
      //-------------------------------------------------------------------------------- 
      ENDCG 
     } 
    } 
} 
+0

Тот факт, что это все три частицы, которые не кажутся правильными, заставляет меня думать, что, скорее всего, это материал, который рисует их неправильно. Я не знаком с Unity или Graphics.DrawProcedural, но похоже, что «каждый третий» больше связан с тем, что вы используете треугольники для их рисования. Могу ли я увидеть вершинный шейдер, используемый «материалом»? –

+0

Если вы еще не пытались использовать PIX для Windows, AMD GPUPerfStudio, NVIDIA Nsight, Intel GPA или графический отладчик, встроенный в Visual Studio 2012, то это также хорошие варианты. PIX Для Windows есть проблемы с Win 8. GPUPerfStudio работает как на картах AMD, так и на Nvidia для целей отладки, nSight - только NVIDIA, а GPA Intel работает на всех картах. В качестве альтернативы, если вы можете предоставить небольшой исполняемый файл, который воспроизводит проблему, я могу, возможно, использовать PIX и лучше понять, что не так. –

+0

Я только что добавил код для шейдеров Vertex, Geom и Pixel. –

ответ

4

Вы должны рисовать с помощью MeshTopology.Points not Triangles.

Поскольку геодезический шейдер передается только точкой, это ваша топология, GS затем обрабатывает это расширение в треугольники согласно вашему шейдерному коду.

Это объясняет, почему появляется только каждая третья частица. Они передаются GS по группам по 3 в соответствии с запрошенной топологией, затем вы отбрасываете 2-й и 3-й вход прозрачно, а следующая вершина, которую видит GS, - Vertex 3, затем 6, затем 9 и т. Д.

+0

WTF !!!!! Спасибо вам большое! Сейчас он работает. –

Смежные вопросы