Search code examples
c#monogamehlsl

HLSL 'optimizing' used variable


This is my shader for 2d polygons. For some reason, even though the vertex shader is running through all the walls, the compiler still treats this as an unused variable and will optimize it away, meaning that when I try to actually set the parameter from monogame, the parameter is null and there doesn't set. I don't understand why the shader thinks the 'walls' variable is not being used when it clearly is.

#if OPENGL
    #define SV_POSITION POSITION
    #define VS_SHADERMODEL vs_3_0
    #define PS_SHADERMODEL ps_3_0
#else
    #define VS_SHADERMODEL vs_4_0_level_9_1
    #define PS_SHADERMODEL ps_4_0_level_9_1
#endif

matrix WorldViewProjection;
float4 walls[6];
float2 lightPos = float2(0, 0);
float4 lightColor = float4(0, 0, 0, 1.0);

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float4 Color : COLOR0;
};

struct VertexShaderOutput
{
    float4 Position : SV_Position;
    float4 Color : COLOR0;
    float2 ScreenPos : TEXCOORD0;
};


int orientation(float2 p, float2 q, float2 r)
{
    int val = (q.y - p.y) * (r.x - q.x) -
        (q.x - p.x) * (r.y - q.y);
    if (val == 0)
        return 0;
    if (val > 0)
        return 1;
    return 2;
}

bool onSegment(float2 p, float2 q, float2 r)
{
    if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) &&
        q.y <= max(p.y, r.y) && q.y >= min(p.y, r.y))
        return true;
    return false;
}

bool intersect(float2 p1, float2 q1, float2 p2, float2 q2)
{
    int o1 = orientation(p1, q1, p2);
    int o2 = orientation(p1, q1, q2);
    int o3 = orientation(p2, q2, p1);
    int o4 = orientation(p2, q2, q1);

    if (o1 != o2 && o3 != o4)
        return true;

    if (o1 == 0 && onSegment(p1, p2, q1))
        return true;
    if (o2 == 0 && onSegment(p1, q2, q1))
        return true;
    if (o3 == 0 && onSegment(p2, p1, q2))
        return true;
    if (o4 == 0 && onSegment(p2, q1, q2))
        return true;

    return false;
}

float map(float value, float min1, float max1, float min2, float max2)
{
    return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}


VertexShaderOutput MainVS(in VertexShaderInput input)
{
    VertexShaderOutput output = (VertexShaderOutput)0;
    
    float2 screenPos = input.Position.xy;
    output.ScreenPos = screenPos;
    output.Position = mul(input.Position, WorldViewProjection);
    
    bool collided = true;
    
    //Run through all the wall segments and make sure light actually hits this vertex
    for (int i = 0; i < 6; i++)
    {
        float2 p = float2(walls[i].x, walls[i].y), q = float2(walls[i].z, walls[i].w);
        
        if (intersect(lightPos, screenPos, p, q))
        {
            //The light hits a wall before hitting this vertex
            collided = false;
        }
    }
    
    float4 color = input.Color;
    
    if (!collided)
    {
        color = float4(0, 0, 0, 0);
    }
    else
    {
        color *= lightColor;
        color.a = map(distance(screenPos, lightPos), 0, 150, 1.0f, 0);
    }
    output.Color = color;
    
    return output;
}


float4 MainPS(VertexShaderOutput input) : COLOR
{
    return input.Color;
}

technique BasicColorDrawing
{
    pass P0
    {
        VertexShader = compile VS_SHADERMODEL MainVS();
        PixelShader = compile PS_SHADERMODEL MainPS();
    }
};

Solution

  • Was able to get rid of the compiler optimizing by adding an [unroll] before the loop which allowed the setting of the walls variable and subsequent parsing of the array in the vertex shader.