0

I am writing my first series of shaders on shadertoy, and can't seem to find an explanation for the following behaviour. I have defined the Hit struct, and a Union function which takes two Hit variables, and returns the one with minimum rayDist. In practice, the Hit returned by the function seems to always have the right rayDist but not matID.

struct Hit
{
    float rayDist;
    float matID;
};

Hit Union(Hit hit1, Hit hit2)
{
    if(hit1.rayDist < hit2.rayDist)
    { 
        return hit1; 
    }
    else
    { 
        return hit2; 
    }
}

The function gets called in the following way:

#define MATERIAL2 2.0

Hit rayHit = Hit(MAXDIST,-1.);
vec3 gridCoord = floor(coord);
for(int i =-1; i <= 1; i++)
for(int j =-1; j <= 1; j++)
for(int k =-1; k <= 1; k++)
{
    vec3 cell = gridCoord + vec3(i,j,k);
    float matOffset = hash13(cell);
        
     Hit sphereHit = Hit(SDSphere(cell, coord, scale), MATERIAL2);
     sphereHit.matID += matOffset;
        
     rayHit = Union( rayHit, sphereHit); // only works when rayHit is used as assigned variable
}

In this example, I am expecting that calling Union should return the same value, regardless of the order in which the arguments are passed (commutative). However I have found that Union( rayHit, sphereHit); and Union( sphereHit, rayHit); yield different results, more specifically different matID. Both return the correct rayDist.

Union( rayHit, sphereHit); returns matID = MATERIAL2 + matOffset (which is what I am expecting), whilst Union( rayHit, sphereHit); returns matID = MATERIAL2.

Confusingly, changing the value which gets assigned the output of Union also alters the results. Again rayHit = Union( rayHit, sphereHit); works fine, but

Hit newHit = Union( rayHit, sphereHit); 
rayHit = newHit;

gives a result of matID = MATERIAL2.

I have tried changing the function to use vec2 instead :

vec2 Union(vec2 hit1, vec2 hit2)
{
    return hit1.x < hit2.x ? hit1 : hit2;
}

encoding rayDist in vec2.x and matID in vec2.y. This will always return the minimum object correctly, regardless of the order. It seems to indicate that the struct is the issue.

I am not familiar with how structs work in GLSL, why can't I seem to use them in this way? Thanks!

Frettini
  • 1
  • 1
  • I have trouble understanding the problem, can you edit your question to include the code that you'd expect to work vs the code that actually works? – LJᛃ Feb 03 '23 at 05:55
  • @LJᛃ I have edited the post to (hopefully) better explain my problem, thanks for having a look! – Frettini Feb 03 '23 at 13:58
  • The order of arguments to your union function only matters in the case where the distances are equal, glsl structs don't behave different from vectors in any regard related to what you describe, I created [this glsl-sandbox](https://glslsandbox.com/e#99526.0) maybe you can create a MVCE based on it. – LJᛃ Feb 03 '23 at 18:59
  • @LJᛃ Right, that seems to make sense, although in the sandbox you set the red channel by comparing rayDist, whereas I am having trouble with matID. That being said, I don't expect it to behave differently.. The issue I am having is at line 136 of this shader https://www.shadertoy.com/view/DlXXDs if you are curious. Thanks for your help, it's much appreciated! – Frettini Feb 03 '23 at 22:03
  • Flipping the arguments in that line doesn't change anything in the visuals for me. – LJᛃ Feb 04 '23 at 01:59
  • @LJᛃ Interesting, could be driver related then.. I've noticed that removing the nested for loops also resolves the issue, so could be something on my side that doesn't like those. – Frettini Feb 04 '23 at 17:28
  • What GPU are you running this on? – LJᛃ Feb 04 '23 at 21:57
  • @LJᛃ I use a Geforce RTX 2060. It seemed to work on my phone (at 3 fps) but didn't work on a RTX 3070 laptop. – Frettini Feb 04 '23 at 22:20
  • I was able to reproduce the error on the same machine using windows (previously tested on linux) probably a glsl->hlsl translation error, you should file a bug in the ANGLE bugtracker with a MVCE. – LJᛃ Feb 11 '23 at 06:46

0 Answers0