Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have been trying to get my shader code (HLSL) to draw a simple circle but after a day and a half I am getting nowhere. It seems people are using the x^2 + y^2 = r^2 and remap texcoords but I only get a white quad.

    struct VertexShaderStruct
{
    float4 Position : POSITION0;
    float2 Tex0 : TEXCOORD0;
};

VertexShaderStruct VertexShaderFunction(VertexShaderStruct input)
{
    VertexShaderStruct output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
    output.Tex0 = input.Tex0;

    return output;
}

float4 PixelShaderFunction(VertexShaderStruct input) : COLOR0
{
    float dx = 2 * input.Tex0.x - 1;
    float dy = 2 * input.Tex0.y - 1;
    float hyp = (dx * dx + dy * dy);

    return (hyp == 1)? circleColor : otherColor;
}

I define circleColor as blue and otherColor as white, so it seems hyp ==1 always fails. Can someone help me solve this problem? Thank you.

share|improve this question
    
I have having this exact same problem. It sounds like your code is now working. Could you post the entire HLSL file contents? It would really help me. –  Justin R. Jan 23 '13 at 22:48

1 Answer 1

up vote 7 down vote accepted

The fragment shader is executed for each fragment with a single uv for this fragment which will probably never fall perfectly on 1.

You could map the target area roughly to the width of a render target fragment.

Eg something like:

abs(hyp - 1) * CircleRadiusInPixel < BorderWidthInPixel*0.5

Further explanation:

Your gpu rasterizes the triangles and executes the fragment shader for each fragment. A fragment is basically a pixel on your screen when MSAA is not active. For each of these fragments the input.Tex0 is filled by interpolating the values from the vertices. As the vertex values for Tex0 range from (0,0) to (1,1) the fragments get values between (0,0) and (1,1). Each fragment only gets one Tex0 representing the value at the center of the current fragment. So it is very unlikely that the fragment centers lie EXACTLY at distance 1 from the center of the circle. If you align everything perfectly, you could probably get 4 pixels (left-middle, right-middle, top-center and button-center) to get correctly colored but never the whole circle and it will probably look different on different vga's.

Even if you somehow could be sure that all pixels are aligned, never compare floats you calculated to an exact value. Floats are never exact as they have limited precision and are adjusted to it after each computation. Compare ranges instead.

You can get an even better looking circle adding some kind of fade out:

float nonBorder = saturate( abs(hyp - 1) * CircleRadiusInPixel / BorderWidthInPixel*0.5 );
nonBorder = pow( nonBorder, 2.0f );
float4 outColor = lerp( circleColor, otherColor, nonBorder );
return pow( outColor, 1.0f / 2.2f ); // gamma correction
share|improve this answer
    
Thank you very much your answer has solved my problem. Id like to understand how you figured out the math or why it works. Or why mine did not. I should do some research but at least its solved. Thanks. –  Michael Jan 23 '13 at 0:29
    
Anytime, added some additional information! –  Archy Jan 23 '13 at 1:01
1  
You have answered my questions amazingly, and shown me how to improve the circle, which works great. Ive learned most importantly how my calculated floats will most likely not land exactly where I expect and to account for this with ranges. I will continue to study this until I have it fully cemented. Thanks a lot for all your help, and I hope others will find this and learn too. –  Michael Jan 23 '13 at 1:52
    
Kind of a n00b question, but how are you getting CircleRadiusInPixel and BorderWidthInPixel into your shader function? -- Are they part of your VertexShaderStruct? If so, what are they declared as semantically? –  BrainSlugs83 May 1 at 5:26
    
Figured it out, I was able to pass in the extra information as a TEXCOORD. –  BrainSlugs83 May 2 at 6:00

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.