Search Unity

Compute Buffer and Camera Rendering with Replacement Shaders

Discussion in 'Shaders' started by FurryFur, Sep 1, 2013.

  1. FurryFur

    FurryFur

    Joined:
    Jun 30, 2013
    Posts:
    7
    How can I use compute buffers with normal camera rendering? Specifically I want to manually render the whole scene using a camera with replacement shaders and store some data about the scene in an append type compute buffer and then use this data for further calculations on the GPU. I've posted some snippets from my code below to show what I'm trying to do.

    The problem I'm having is that it doesn't seem to be writing anything to the compute buffer that I'm trying to attach to the replacement shader. The second low level draw call never draws anything, presumably because the buffer I'm using to draw with is empty. I've also tried pulling the count of the compute buffer from the args buffer after the value gets copied into it and displaying it using a GUI.Label, but it is always zero. I think the Graphics.SetRandomWriteTarget command only works when using low level draw commands and not when using the camera to render which is probably overwriting or throwing away this graphics state before rendering each object. Does anybody have any idea how I might solve this?
    Code (csharp):
    1.  
    2.  
    3. //Init compute buffers
    4. listOfData = new ComputeBuffer (MAX_DATA_AMOUNT, DATA_SIZE, ComputeBufferType.Append);
    5. argsBuffer = new ComputeBuffer (1, ARGS_SIZE, ComputeBufferType.DrawIndirect);
    6. var args = new uint[4];
    7. args[0] = 0;
    8. args[1] = 1; //1 Instance
    9. args[2] = 0;
    10. args[3] = 0;
    11. argsBuffer.SetData(args);
    12.  
    13. ...
    14.  
    15. Camera cam = GetCamera();
    16.        
    17. //Set computer buffer on shader
    18. Graphics.SetRandomWriteTarget (1, listOfData); //Attach to register u1 on shader
    19.  
    20. //Write data about the scene using replacement shader
    21. cam.RenderWithShader(writeDataShader, "");
    22.  
    23. //I don't really know what this does, it's clear from the DX11 examples that it doesn't actually clear the compute buffer or at least not immediatly
    24. Graphics.ClearRandomWriteTargets ();
    25.  
    26. ...
    27.  
    28. ComputeBuffer.CopyCount(listOfData, argsBuffer , 0);
    29.        
    30. //Set material/shader variables
    31. voxelDrawMat.SetPass(0);
    32. voxelDrawMat.SetBuffer("_ListOfData", listOfData);
    33. voxelDrawMat.SetMatrix("_MVP", Camera.main.projectionMatrix * Camera.main.worldToCameraMatrix * orthoCubeWorldMatrix);
    34. voxelDrawMat.SetFloat("_SceneBoundsCubeExtents", bounds.extents.x);
    35. voxelDrawMat.SetFloat("_SampleRez", _Resolution);
    36.        
    37. //Draw voxels
    38. Graphics.DrawProceduralIndirect(MeshTopology.Points, argsBuffer , 0);
    39.  
    40.  
    In camera replacement shader
    Code (csharp):
    1.  
    2. float4 frag(VS_OUTPUT input) : COLOR0
    3. {
    4. listOfDataOutput.Append(input.interpolatedData);
    5.  
    6. return float4(input.interpolatedData.xyz, 1); //This is just used for rough visual debugging to see if the interpolated data is correct
    7. }
    8.  
     
    Last edited: Sep 1, 2013
  2. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    It's a nonsensical limitation of Unity's renderer... You can't easily use MRTs or RWTs to render a whole camera view. You have to do it manually, mesh by mesh, including all the culling and batching Unity does for you.
     
  3. FurryFur

    FurryFur

    Joined:
    Jun 30, 2013
    Posts:
    7
    Hmmmm well Shader.SetGlobalBuffer works for setting read only buffers that can be used when rendering a whole camera view. I'm not sure if this works for setting writable buffers though as I haven't had much more luck with it than SetRandomWriteTargets. And I don't know how you would clear the buffer in this case either which, I assume, is normally handled by ClearRandomWriteTargets. I hope that unity exposes enough functionality to allow me to do the mesh rendering manually if it's my only option. I want to be able to preserve each gameobjects material properties (textures etc). I'd basically have to implement my own RenderWithShader method which does exactly what the unity one already does except allows me to set RWTs. ><
     
  4. Dolkar

    Dolkar

    Joined:
    Jun 8, 2013
    Posts:
    576
    Yeah... That's what I'll be doing for the next few weeks as well.. except with lighting and everything.
     
  5. Pyromuffin

    Pyromuffin

    Joined:
    Aug 5, 2012
    Posts:
    85
    I hope I am not too late, but it IS actually possible to write to a compute buffer (not sure about append, but it might work) in a pixel shader, using shader replacement. However, it is not possible, as far as I can tell, to do this with a RWTexture3D (which is what I really wanted... I solved it by doing it with a compute buffer).

    my C# code looks like
    Code (csharp):
    1.  
    2. myBuffer = new ComputeBuffer(mySize,8);
    3. Graphics.SetRandomWriteTarget(1, myBuffer);
    4.  
    Pixel shader code should look something like this
    Code (csharp):
    1.  
    2. RWStructuredBuffer<float> myBuffer : register(u1);
    3.  
    4. PS( whatever input){
    5.  myBuffer[someLinearIndex] = data;
    6.  
    7. }
    8.  
    9.  
    I'm still struggling with getting RWTextures to work in pixel shaders, and I would like some official input on it.
     
    Baggers_ and royalfoxgames like this.
  6. Alabatross

    Alabatross

    Joined:
    Dec 15, 2012
    Posts:
    223
    This still doesn't seem to work :(
     
  7. Daniel-Strayer

    Daniel-Strayer

    Joined:
    Apr 16, 2013
    Posts:
    68
    I'll second Alabatross' comment. I can't get RWTexture3D to be writable from Pixel shader any more. It used to work in Unity 4.x. Something must have broken.