GLSL struct operation returns the wrong member variables

85 Views Asked by At

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!

0

There are 0 best solutions below