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. Dismiss Notice

Question [kinda solved/workaround found] Weird compute shader texture behaviour

Discussion in 'Shaders' started by wichilowat, Jan 30, 2022.

  1. wichilowat

    wichilowat

    Joined:
    Feb 9, 2015
    Posts:
    10
    With my shader I'm generating a texture that shows the global positions of several objects relative to the camera. When I move the camera, The c# script inputs the velocity to the shader to move all the pixels in the opposite direction to ensure they are still in the correct position relative to the camera. I need to do this because I'm using a lerp to draw the texture.

    My code gives the expected behavior for every direction (x and z) except for when z speed is negative. I think this has something to do with uint3 since it doesn't have a sign, but then in my mind, the negative x direction should also behave weird.

    Here is my C# code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.VFX;
    5.  
    6. public class GrassBendManager : StaticInstance<GrassBendManager>
    7. {
    8.  
    9.   public ComputeShader computeShader;
    10.   public RenderTexture VectorField;
    11.  
    12.   public VisualEffect vfx;
    13.  
    14.   public Transform camTrans;
    15.   Vector3 smoothCamTrans;
    16. // public Transform[] Benders;
    17.  
    18.   [Tooltip("one pixel represents 1/ResolutionMultiplier meteres")]
    19.   public int ResolutionMultiplier = 5;
    20.  
    21.   public int TextureSize = 512;
    22.  
    23.   public Vector3 cameraVelocity;
    24.  
    25.   public BenderObject[] Benders;
    26.  
    27.   Bender[] BendersData;
    28.  
    29.   struct Bender
    30.   {
    31.       public Vector3 position;
    32.       public float radius;
    33.   };
    34.  
    35.   void Start() {
    36.  
    37.     if(camTrans == null)
    38.     {
    39.       camTrans = Camera.main.transform;
    40.     }
    41.  
    42.     VectorField = new RenderTexture(TextureSize,TextureSize,24);
    43.     VectorField.enableRandomWrite = true;
    44.     VectorField.Create();
    45.     vfx.SetTexture("GrassBendingTexture",VectorField);
    46.  
    47.     BendersData = new Bender[Benders.Length];
    48.    // computeShader.SetTexture(0,"Result", VectorField);
    49.    // computeShader.Dispatch(0, VectorField.width/8, VectorField.height/8,1);
    50.   }
    51.  
    52.   public bool UpdateTexture;
    53.  
    54.   Vector3 prevCamPos;
    55.   void LateUpdate() {
    56.     if(UpdateTexture)
    57.     {
    58.       //UpdateTexture = false;
    59.       OnUpdateTexture();
    60.     }
    61.  
    62.     int BendingDistance = TextureSize/ResolutionMultiplier/4;
    63.  
    64.     smoothCamTrans = new Vector3(Mathf.Round(camTrans.position.x/BendingDistance)*BendingDistance,0,Mathf.Round(camTrans.position.z/BendingDistance)*BendingDistance);
    65.     cameraVelocity = (smoothCamTrans-prevCamPos);
    66.     prevCamPos = smoothCamTrans;
    67.   }
    68.  
    69.   void OnUpdateTexture()
    70.   {
    71.     vfx.SetVector3("MainCamPos",smoothCamTrans);
    72. //    Debug.Log("tried atleast");
    73.     int i = 0;
    74.     foreach(var bender in Benders)
    75.     {
    76.       BendersData[i].position = bender.trans.position - smoothCamTrans; //give the position relative to camera
    77.       BendersData[i].radius = bender.radius;
    78.       i++;
    79.     }
    80.  
    81.     int size = Benders.Length;
    82.     int vector3Size = sizeof(float)*3;
    83.     int totalSize = vector3Size + sizeof(float);
    84.  
    85.     ComputeBuffer fieldBuffer = new ComputeBuffer(size, totalSize);
    86.     fieldBuffer.SetData(BendersData);
    87.  
    88.     computeShader.SetBuffer(0, "benders", fieldBuffer);
    89.     computeShader.SetTexture(0,"Result", VectorField);
    90.     computeShader.SetInt("BendersSize",BendersData.Length);
    91.     computeShader.SetInt("ResolutionMultiplier",ResolutionMultiplier);
    92.     computeShader.SetFloat("deltaTime", Time.deltaTime);
    93.     computeShader.SetVector("camVel",cameraVelocity);
    94.  
    95.     Vector2 res = new Vector2(VectorField.width, VectorField.height);
    96.     computeShader.SetVector("textureRes", res);
    97.     computeShader.Dispatch(0, (int)res.x/8, (int)res.y/8,1);
    98.     fieldBuffer.Release();
    99.   }
    100. }
    101.  
    102. [System.Serializable]
    103. public class BenderObject
    104. {
    105.   public Transform trans;
    106.   public float radius;
    107.  
    108. }
    and here is the Compute shader:
    Code (CSharp):
    1. // Each #kernel tells which function to compile; you can have many kernels
    2. #pragma kernel CSMain
    3.  
    4. // Create a RenderTexture with enableRandomWrite flag and set it
    5. // with cs.SetTexture
    6. RWTexture2D<float4> Result;
    7.  
    8. float2 textureRes;
    9. int ResolutionMultiplier;
    10. float deltaTime;
    11. float3 camVel;
    12.  
    13. struct Bender
    14. {
    15.     float3 position;
    16.     float radius;
    17. };
    18.  
    19. int BendersSize;
    20. RWStructuredBuffer<Bender> benders;
    21.  
    22. float SQRdist(float2 a, float2 b)
    23. {
    24.     return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
    25. }
    26.  
    27. [numthreads(8,8,1)]
    28. void CSMain (uint3 id : SV_DispatchThreadID)
    29. {
    30.     float4 color = float4(0,0,0,0);
    31.  
    32.  
    33.     for(int i = 0; i < BendersSize; i++)
    34.     {
    35.         Bender bender = benders[i];
    36.         float2 WorldPos;
    37.         WorldPos.x = ((float)id.x)/ResolutionMultiplier;
    38.         WorldPos.y = ((float)id.y)/ResolutionMultiplier;
    39.         if((SQRdist(WorldPos, float2(bender.position.x + (textureRes.x/2)/ResolutionMultiplier,bender.position.z+ (textureRes.x/2)/ResolutionMultiplier))) < bender.radius*bender.radius)
    40.         {
    41.             float2 dir = (WorldPos - float2(bender.position.x + (textureRes.x/2)/ResolutionMultiplier,bender.position.z+ (textureRes.x/2)/ResolutionMultiplier))*0.5f;
    42.             color = float4(dir.x,0.75f,dir.y,0);
    43.             //todo, make this vector go outward from bender center instead.
    44.         }
    45.     }
    46.  
    47.     float2 idF = id.xy;
    48.     int2 adjustedID = idF.xy+(float2(camVel.x,camVel.z)*ResolutionMultiplier);
    49.  
    50.     Result[id.xy] = Result[adjustedID];
    51.  
    52.     Result[id.xy] += clamp((color - Result[id.xy]),-0.025f,1)*deltaTime*20;
    53.  
    54.  
    55. }
    56.  
    Here is an example of when I haven't moved the camera in -z direction:


    and here is when I have moved in -z direction:



    Does any shader magician know what my problem might be? Thanks!
     
  2. wichilowat

    wichilowat

    Joined:
    Feb 9, 2015
    Posts:
    10
  3. esgnn

    esgnn

    Joined:
    Mar 3, 2020
    Posts:
    35
    I couldn't understand what your code does (my bad), however based on your description, I have two different approaches.
    1. Will you be able to achieve the same output if you make those objects child object of your camera?
    2. Instead of dealing with velocities, calculate the position of object with respect to camera using camera.TransformPoint (object,transform.position) formulas inside the compute shader?
     
    wichilowat likes this.
  4. wichilowat

    wichilowat

    Joined:
    Feb 9, 2015
    Posts:
    10
    The relative position is calculated before I input it to the shader so the center will alway be in the middle of the texture (you could say
    Hi and thanks for the reply,

    To answer your questions, 1: kinda yes, but this wasn't what was causing issues because i was calculating the correct relative positions in my c# script.
    2: At first I was only using the point and this worked flawlessly! Unfortunately, I needed to add a fade effect when the object moved (the lerp in the shader), This caused the lerped/old pixels to look like they moved in the opposite direction of the camera when mapped on a plane, thats why i needed to offset them with the camera's velocity.

    I did however find a workaround for my problem by using 2 textures that switch I between when the camera gets close to an edge. Thanks for your response and time even though my problem was hard to understand!
     
  5. esgnn

    esgnn

    Joined:
    Mar 3, 2020
    Posts:
    35
    Aah ok, glad you found a solution.