Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Can a compute shader incrementally change a texture?

Discussion in 'Shaders' started by starstriker1, Jun 17, 2015.

  1. starstriker1

    starstriker1

    Joined:
    Jul 15, 2012
    Posts:
    38
    I'm trying to use a compute shader to modify a 3D render texture. I want to keep the existing contents, but additively paint into the texture in a specific location. However, while I could use a compute shader to fill everything with a constant colour, I couldn't get it to do any modifications on top of existing state. I've been banging my head against this for a while and can't find any useful documentation on the subject.

    My compute shader:

    Code (CSharp):
    1.  
    2. #pragma kernel CSMain
    3.  
    4. Texture3D<float4> texIn;
    5. RWTexture3D<float4> texOut;
    6.  
    7. float3 boundsDimensions;
    8. float3 boundsCenter;
    9.  
    10. float3 paintCenter;
    11. float paintRadius;
    12. float paintMult;
    13. float paintPower;
    14. float4 paintColor;
    15.  
    16. [numthreads(8,8,8)]
    17. void CSMain (uint3 id : SV_DispatchThreadID)
    18. {
    19.     float3 texSize;
    20.     texIn.GetDimensions(texSize.x, texSize.y, texSize.z);
    21.  
    22.     float3 unitsPerTexel = (boundsDimensions/texSize);
    23.     float3 diff = (id.xyz*unitsPerTexel + boundsCenter - paintCenter);
    24.     float dist = length(diff);
    25.  
    26.     float amount = saturate(1-dist/paintRadius);
    27.     amount = pow(amount,paintPower) * paintMult;
    28.      
    29.     float4 finalPaint = saturate(texIn[id.xyz] + amount * paintColor);
    30.  
    31.     texOut[id.xyz] = finalPaint;
    32. }
    33.  
    The calling code:
    Code (CSharp):
    1.         ComputeShader paintShader = Resources.Load<ComputeShader>("ComputeShaders/PaintSphere");
    2.      
    3.         paintShader.SetTexture(0, "texIn", paintVolume.Volume);
    4.         paintShader.SetTexture(0, "texOut", paintVolume.Volume);
    5.  
    6.         paintShader.SetVector("boundsDimensions", paintVolume.BoundsSize);
    7.         paintShader.SetVector("boundsCenter", paintVolume.BoundsCenter);
    8.         paintShader.SetVector("paintCenter", transform.InverseTransformPoint(worldPosition));
    9.         paintShader.SetFloat("paintRadius", radius);
    10.         paintShader.SetFloat("paintMult", mult);
    11.         paintShader.SetFloat("paintPower", power);
    12.         paintShader.SetVector("paintColor", color);
    13.  
    14.         paintShader.Dispatch(0, paintVolume.Volume.width / 8, paintVolume.Volume.height / 8, paintVolume.Volume.volumeDepth / 8);
    ...And, for good measure, the render texture creation:
    Code (CSharp):
    1.             volume = new RenderTexture(volumeDimensions, volumeDimensions, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
    2.             volume.isVolume = true;
    3.             volume.volumeDepth = volumeDimensions;
    4.             volume.enableRandomWrite = true;
    As far as I can tell, the questionable bit is that I'm feeding the same texture into the shader as both an input and an output variable. However, I don't know another way to approach this. Does anyone know what I'm doing wrong, or what I could do as an alternative approach?
     
  2. starstriker1

    starstriker1

    Joined:
    Jul 15, 2012
    Posts:
    38
    I was able to work around this by using two render textures and swapping between them; a bit circuitous, but it seems to get the job done. Some strange issues when I try to do too many paint events at once, though. I haven't been able to sort them out, but I suspect they have to do with execution order or possibly some sort of concurrency issue. It'd be much better if I could change the texture in-place with some sort of additive scheme...