dcsimg
Results 1 to 3 of 3

Thread: Convert If...Else to formula

  1. #1

    Thread Starter
    Not NoteMe SLH's Avatar
    Join Date
    Mar 2002
    Location
    192.168.0.1 Preferred Animal: Penguin Reason for errors: Line#38
    Posts
    3,051

    Convert If...Else to formula

    I'm writing a pixel shader that will be used to draw a slider type control that has min/max and current values.

    Any pixel before the current value should be full colour (original texture alpha level), anything shortly after should gradually fade away, and anything far after the current value should be fully transparent.

    Currently i have this code:
    Code:
    if (textureCoordinate.x < SliderValue)
        {
    		return TileColour;
        }
        else if(textureCoordinate.x < SliderValue + (SliderValue / 10))
        {
    		float Proportion = (SliderValue + (SliderValue / 10) - textureCoordinate.x) / (SliderValue / 10);
    		
    		return float4(TileColour.rgb, TileColour.a * Proportion);
        }
        else
        {
    		return 0;
        }
    However, conditionals are slow on a graphics card, so i'd ideally like to get this down to a single formula.

    The SliderValue is in range 0 to 1, as are texture coordinates. The TileColour variable is the original texture colour. TileColour.a is the original alpha level of the texture (range 0..1, 0 for transparent).

    The first part deals with pixels before the slider value.The last part deals with pixels far after the slider value,

    The middle bit deals with pixels within a range shortly after the slider value (when the slider value is low this range is small, when the slider value is high the range is high). Basically i'm defining a range that's 1 tenth the size of the current slider value. Pixels within that range i want to fade from fully oblique to fully transparent.

    This code produces the effect i want, but i'd like it in a single formula if possible.

    Hopefully i've explained this enough to take away any need for knowledge of pixel shaders!!
    Quotes:
    "I am getting better then you guys.." NoteMe, on his leet english skills.
    "And I am going to meat her again later on tonight." NoteMe
    "I think you should change your name to QuoteMe" Shaggy Hiker, regarding NoteMe
    "my sweet lord jesus. I've decided never to have breast implants" Tom Gibbons
    Have I helped you? Please Rate my posts.


  2. #2
    Only Slightly Obsessive jemidiah's Avatar
    Join Date
    Apr 2002
    Posts
    2,431

    Re: Convert If...Else to formula

    In pure math, you want a function f with input and output in [0, 1] where f(x) = 1 for x <= d, f(x) =0 for x >= d + s, and f linearly interpolates in [d, d+s] for some constants d and s. (No shader knowledge required .)

    You can approximate such a function by polynomials--i.e. create a function that is very close to 1, then very close to a linear interpolation, then very close to 0. Computing it would probably take longer than an If, though.


    Really what you seem to want is a way to convert values > 1.0 to 1 and values < 0.0 to 0, without using an If.

    You can define the sgn(x) function as x / Abs(x). Abs(x) can be defined by Sqrt(x^2), or it can be defined using binary logic depending on the underlying representation of x. For instance, if x is a signed 32 bit integer, x And &7FFF should return a positive version of x by shaving off the most significant bit. Now sgn(x) will error if x = 0. You can get around that by making sure you never pass x=0. There might be more elegant solutions I'm not thinking of. It's important for you to keep in mind this singularity if you do use this method, though it should be relatively easy to avoid.

    With the sgn(x) function, we're in a position to define the usual unit step function u(x) where u(x) = 0 for x < 0, u(0) = 1/2, and u(x) = 1 for x > 0. We can do this by setting u(x) = (sgn(x) + 1) / 2.

    We can shift u(x) to u(x-c) to make a function which is 1 past c and 0 before c. For a function f(x) we can make a function which is precisely f(x) before c and is 0 after c by using u(x-c)*f(x). We can make a function which is precisely f(x) *after* c and is 0 *before* c by using very similar logic to get u(c-x)*f(x). Combining these, we can make a function which is precisely f(x) between d and d+s and 0 elsewhere by using g(x) = u(x-d)*u((d+s)-x)*f(x).

    If f is a linear interpolation where f(d) = 1 and f(d+s) = 0, then the function g(x) is almost what we want--it's linear between d and d+s, 0 after d+s, but is 0 before d as well. This can be rectified by using h(x) = g(x) + u(d-x).

    We've been ignoring the end points. h(d) = g(d) + u(d-d) = u(d-d)*u((d+s)-d)*f(d) + u(d-d) = 1/2*1*1+1/2 = 1, which is precisely what we wanted. Similarly h(d+s) = 0.

    h(x) can be slightly simplified using the identity 1-u(x-d) = u(d-x) to get h(x) = u(x-d)*u((d+s)-x)*f(x) + u(d-x) = u(x-d)*u((d+s)-x)*f(x) + 1 - u(x-d) = 1 + u(x-d)*(u((d+s)-x)*f(x)-1).


    In all, you can use
    h(x) = 1 + u(x-d)*(u((d+s)-x)*f(x)-1)
    u(y) = (sgn(y) + 1) / 2
    sgn(y) = (y) / Abs(y)
    Abs(y) = Sqrt(y^2), or y And &7FFF

    where you never evaluate sgn(0).


    Hopefully I haven't made any mistakes, though even if I have these tools and lines of reasoning will work.

    Edit: I don't have time to fix it, but the identity I used is incorrect. It should be 1-u(x-c) = u(c-x)
    Further edit: Fixed.
    Another edit: Fixed an issue with the singularity of sgn.
    Last edited by jemidiah; Feb 12th, 2011 at 07:56 PM.
    The time you enjoy wasting is not wasted time.
    Bertrand Russell

    <- Remember to rate posts you find helpful.

  3. #3

    Thread Starter
    Not NoteMe SLH's Avatar
    Join Date
    Mar 2002
    Location
    192.168.0.1 Preferred Animal: Penguin Reason for errors: Line#38
    Posts
    3,051

    Re: Convert If...Else to formula

    Fantastic! Thanks for the very detailed explanation of your thought process. Top marks for showing your workings. I would rate, but apparently i need to spread some rep around first.

    In case anyone's interested heres the finished pixel shader code:
    Code:
    float SliderValue;
    Texture coloredTexture;
    
    sampler coloredTextureSampler = sampler_state
    {
        texture = <coloredTexture>;
    };
    
    float sgn(float x)
    {
    	return x / abs(x);
    }
    
    float u(float x)
    {
    	return (sgn(x) + 1) / 2;
    }
    
    float f(float x)
    {
    	float d = SliderValue;
    	float s = (SliderValue / 10);
    	return (d + s - x) / s;
    }
    
    float h(float x)
    {
    	float d = SliderValue;
    	float s = (SliderValue / 10);
    	
    	return 1 + u(x - d)*(u((d + s) - x) * f(x) - 1);
    }
    
    float4 MenuSlider20(float2 textureCoordinate : TEXCOORD0) : COLOR0
    {
    	float4 TileColour = tex2D(coloredTextureSampler, textureCoordinate);
    	
    	return float4(TileColour.rgb, h(textureCoordinate.x) * TileColour.a);
    }
    
    technique MenuSlider
    {
        pass MenuSliderPass
        {
            PixelShader = compile ps_2_0 MenuSlider20();
        }
    }
    Quotes:
    "I am getting better then you guys.." NoteMe, on his leet english skills.
    "And I am going to meat her again later on tonight." NoteMe
    "I think you should change your name to QuoteMe" Shaggy Hiker, regarding NoteMe
    "my sweet lord jesus. I've decided never to have breast implants" Tom Gibbons
    Have I helped you? Please Rate my posts.


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width