2

For a little background this is for doing particle collisions with lookup textures on the GPU. I read the position texture with javascript and create a grid texture that contains the particles that are in the corresponding grid cell. The working example that is mentioned in the post can be viewed here: https://pacific-hamlet-84784.herokuapp.com/

The reason I want the buckets system is that it will allow me to do much fewer checks and the number of checks wouldn't increase with the number of particles.

For the actual problem description:

I am attempting to read from a lookup texture centered around a pixel (lets say i have a texture that is 10x10, and I want to read the pixels around (4,2), i would read

(3,1),(3,2)(3,3)
(4,1),(4,2)(4,3)
(5,1),(5,2)(5,3)

The loop is a little more complicated but that is the general idea. If I make the loop look like the following

float xcenter = 5.0;
float ycenter = 5.0;
for(float i = -5.0; i < 5.0; i++){
    for(float j = -5.0; j < 5.0; j++){

    }
}

It works (however it goes over all of the particles which defeats the purpose), however if I calculate the value dynamically (which is what I need), then I get really bizarre behavior. Is this a problem with GLSL or a problem with my code? I output the values to an image and read the pixel values and they all appear to be within the right range. The problem is coming from using the for loop variables (i,j) to change a bucket index that is calculated outside of the loop, and use that variable to index a texture.

The entire shader code can be seen here: (if I remove the hard coded 70, and remove the comments it breaks, but all of those values are between 0 and 144. This is where I am confused. I feel like this code should still work fine.).

uniform sampler2D pos;
uniform sampler2D buckets;


uniform vec2  res;
uniform vec2  screenSize;
uniform float size;
uniform float bounce;
const float width = &WIDTH;
const float height = &HEIGHT;
const float cellSize = &CELLSIZE;
const float particlesPerCell = &PPC;
const float bucketsWidth = &BW;
const float bucketsHeight = &BH;

$rand
void main(){

  vec2 uv = gl_FragCoord.xy / res;
  vec4 posi  = texture2D( pos , uv );
  float x = posi.x;
  float y = posi.y;
  float z = posi.z;
  float target = 1.0 * size;


  float x_bkt = floor( (x + (screenSize.x/2.0) )/cellSize);
  float y_bkt = floor( (y + (screenSize.y/2.0) )/cellSize);


  float x_bkt_ind_start = 70.0; //x_bkt * particlesPerCell;
  float y_bkt_ind_start =70.0; //y_bkt * particlesPerCell;

  //this is the code that is acting weirdly
  for(float j = -144.0 ; j < 144.0; j++){
    for(float i = -144.0 ; i < 144.0; i++){

      float  x_bkt_ind = (x_bkt_ind_start + i)/bucketsWidth;
      float  y_bkt_ind = (y_bkt_ind_start + j)/bucketsHeight;


      vec4 ind2 = texture2D( buckets , vec2(x_bkt_ind,y_bkt_ind) );

      if( abs(ind2.z - 1.0) > 0.00001  || x_bkt_ind < 0.0 || x_bkt_ind > 1.0 || y_bkt_ind < 0.0 || y_bkt_ind > 1.0 ){
        continue;
      }

       vec4 pos2 = texture2D( pos , vec2(ind2.xy)/res );

       vec2 diff = posi.xy - pos2.xy;

       float dist = length(diff);


      vec2 uvDiff = ind2.xy -  gl_FragCoord.xy ;
      float uvDist = abs(length(uvDiff));


      if(dist <= target && uvDist >= 0.5){
        float factor = (dist-target)/dist;
        x = x - diff.x * factor * 0.5;
        y = y - diff.y * factor * 0.5;
      }


    }
  }


  gl_FragColor = vec4( x, y, x_bkt_ind_start , y_bkt_ind_start);


}

EDIT: To make my problem clear, what is happening is that when I do the first texture lookup, I get the position of the particle:

vec2 uv = gl_FragCoord.xy / res;
vec4 posi  = texture2D( pos , uv );

After, I calculate the bucket that the particle is in:

float x_bkt = floor( (x + (screenSize.x/2.0) )/cellSize);
float y_bkt = floor( (y + (screenSize.y/2.0) )/cellSize);
float x_bkt_ind_start = x_bkt * particlesPerCell;
float y_bkt_ind_start = y_bkt * particlesPerCell;

All of this is correct. Like I am getting the correct values and if I set these as the output values of the shader and read the pixels they are the correct values. I also changed my implementation a little and this code works fine.

In order to text the for loop, I replaced the pixel lookup coordinates in the grid bucket by the pixel positions. I adapted the code and it works fine, however I have to recalculate the buckets multiple times per frame so the code is not very efficient. If instead of storing the pixel positions I store the uv coordinates of the pixels and then do a lookup using those uv positions:

//get the texture coordinate that is offset by the for loop
float  x_bkt_ind = (x_bkt_ind_start + i)/bucketsWidth;
float  y_bkt_ind = (y_bkt_ind_start + j)/bucketsHeight;
//use the texture coordinates to get the stored texture coordinate in the actual position table from the bucket table
vec4 ind2 = texture2D( buckets , vec2(x_bkt_ind,y_bkt_ind) );

and then I actually get the position

vec4 pos2 = texture2D( pos , vec2(ind2.xy)/res );

this pos2 value will be wrong. I am pretty sure that the ind2 value is correct because if instead of storing a pixel coordinate in that bucket table I store position values and remove the second texture lookup, the code runs fine. But using the second lookup causes the code to break.

In the original post if I set the bucket to be any value, lets say the middle of the texture, and iterate over every possible bucket coordinate around the pixel, it works fine. However if I calculate the bucket position and iterate over every pixel it does not. I wonder if it has to do with the say glsl compiles the shaders and that some sort of optimization it is making is causing the double texture lookups to break in the for look. Or it is just a mistake in my code. I was able to get the single texture lookup in a for loop working when I just stored position values in the bucket texture.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Luple
  • 481
  • 3
  • 21
  • 2
    I've read this three times now, and have no idea what you are trying to do nor what the problem is. What do shaders and particles have to do with servers? *"Everything seems to be working"* what is **everything**? – pailhead Sep 05 '17 at 19:49
  • Oh crap, i didn't mean server. let me fix that. I will update my answer with a better explanation – Luple Sep 05 '17 at 19:51
  • 1
    I second it is absolutely unclear what the problem or question is about. You did not specify what you mean by **acting weirdly** what it does exactly and what it should do? You could try to add some debug prints to determine the problem see: [GLSL debug prints](https://stackoverflow.com/a/44797902/2521214) you just need to make an constant input for printed area which can be done by few `if` statements for variables and not needed for constants at all. – Spektre Sep 10 '17 at 08:39
  • Thanks for the recommendation. I am able to read the shader values by using readRenderTargetPixels, and I know that the values of my textures are correct and I changed my implementation to avoid the problem I was having, however it is much less efficient so I would still like to get this working. I will add an edited section to my post and try to explain in as much detail as I can what the problem is. – Luple Sep 10 '17 at 12:37
  • Let me know if it is still unclear. I am sorry if its hard to understand, its not that easy for me to explain it. Thanks for telling me though so I knew to change it. – Luple Sep 10 '17 at 12:47
  • from the edit I got the impresision that using single texture is working and 2 not so: Are you using separate texture units for the textures? if not the bug is on CPU side code instead ... – Spektre Sep 11 '17 at 06:17
  • yeah, thats what is happening. and I use two different textures of different sizes. so the position texture has res as the size, while the bucket texture has bucketsWidth and bucketsHeight, which are set with javascript. it is possible the javascript code that creates the buckets is wrong, but after reading the outputs it seems unlikely. but i can post that code as well. – Luple Sep 11 '17 at 15:20

0 Answers0