用HLSL和一些数学绘制一个圆圈

时间:2013-11-26 19:11:45

标签: xna hlsl pixel-shader

我正在使用2D纹理,我想绘制一个简单的圆,使用此函数来了解圆上是否有像素,然后为其指定一种颜色:Equation

其中(a,b)是圆的中心。

我不介意这是否是一种愚蠢,低效的方式来实现这种效果,我只是想学习如何操纵浮点数来绘制那个圆圈。假设C#中的所有部分都是正确的,并且纹理是正方形,我该如何纠正我的代码呢?

sampler s0;   
int radius;
static const float X_c = radius/2;
static const float Y_c = radius/2;

float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0   
{   
    float4 color = tex2D(s0, coords);   
    float2 coords_sec = coords*radius*2; //To map coordinates in [0, radius*2] instead of [0,1]

    //The same equation as above, just putting to the left radius
    if ( ( (int)pow((coords_sec.x - X_c),2)
           + (int)pow((coords_sec.y - Y_c),2)
            - (int)pow(radius,2) ) == 0.0 )

    {
        color.r = 1; //I want to draw a red circle
    }

    return color;
}

technique Technique1
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();  //Dice quale versione del pixelshader compilare
    }
}

聚苯乙烯。看来我什么都没画。我怀疑if条件总是假的

第二个问题:是否有一个简单的指南,博客或书籍来帮助我理解这些概念(关于2D)?

2 个答案:

答案 0 :(得分:1)

首先,施放到int会产生反作用。您有float个值,并且不希望通过转换为int来放松精度,{0, 1 ... 4 * radius^2}始终是== 0之一。

此外,与<= 0的比较需要一些运气才能被击中。如果你想填充圆圈,请使用abs(...) <= epsilon或者如果你想绘制一条线,请尝试类似float4 PixelShaderFunction(float2 coords: TEXCOORD0) : COLOR0 { float dx = coords.x - 0.5f; float dy = coords.y - 0.5f; if(dx * dx + dy * dy <= 0.25f) return float4(1.0f, 0.0f, 0.0f, 1.0f); else return float4(0.0f, 0.0f, 0.0f, 0.0f); } 的内容,其中epsilon是一个描述线条粗细的小数字。

请注意,您只需将返回颜色的r分量设置为1.这不需要产生红色圆圈(例如,如果您已经有白色纹理)。

我会做以下事情:

{{1}}

请注意,您不需要显式半径或中心,因为纹理坐标已标准化。

答案 1 :(得分:1)

这是一种非常简单的方法(但可能不是很快);它有效。我并不认为它是最好的解决方案,但它运行良好,非常灵活和简单,允许您使用GDI +。

首先:添加引用&#34; System.Drawing&#34;从项目菜单中。

第二:在新文件中创建此类。

using Microsoft.Xna.Framework.Graphics;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace WindowsGame1 // This should be the namespace of your application.
{
    class CircleDrawer
    {
        public static Texture2D GetCircle(GraphicsDevice device, System.Drawing.Color    color, int radius)
        {
            Image img = new Bitmap(radius, radius);
            Graphics g = Graphics.FromImage(img);
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.FillEllipse(new SolidBrush(color), 0, 0, radius, radius);
            img.Save("temp.png", System.Drawing.Imaging.ImageFormat.Png);
            Texture2D result = Texture2D.FromFile(device, "temp.png");
            System.IO.File.Delete("temp.png");
            return result;
        }
    }
}

第三:现在所有人都有一个方法可以画一个圆圈的方法

让我们看一个如何应用它的示例:

只需在&#34; Draw&#34;中写下这四行。游戏类的方法

        Texture2D txt = CircleDrawer.GetCircle(GraphicsDevice, 
            System.Drawing.Color.Green, 40);
        spriteBatch.Begin();
        spriteBatch.Draw(txt, new Rectangle(10, 10, 60, 60), Color.White);
        spriteBatch.End();