在绘制一个HLSL超椭圆 [英] Drawing a SuperEllipse in HLSL

查看:405
本文介绍了在绘制一个HLSL超椭圆的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:回答人们如何使用Superformula在年底前制订



我需要绘制一个圆角矩形,如这一个,使用超椭圆



图一个是能够绘制地方很容易时:





但在HLSL,你不能,我被困在条件打印或不是一个像素:





下面是HLSL代码:

  sampler2D输入:寄存器(S0); 

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0< / minValue(最小值)>
///<&maxValue分别GT; 10.0 LT; /&maxValue分别GT;
///<设置defaultValue> 4.0< /设置defaultValue>
浮动N:注册(C1);

静态常量浮PI = 3.1415926535f;

FLOAT2超椭圆(浮点N,浮动,浮动B,浮动THETA)
{
浮动克拉= COS(THETA);
浮动ST = SIN(THETA);
浮X = A *符号(克拉)* POW(ABS(CT),2.0F / N);
浮动Y = B *号(ST)* POW(ABS(ST),2.0F / N);
返回FLOAT2(X,Y);
}

FLOAT4主(FLOAT2 UV:TEXCOORD):COLOR
{
FLOAT2欠电压= UV * FLOAT2(2.0F,2.0F) - FLOAT2(1.0F ,1.0F);
浮动角=度(ATAN2(uv1.y,uv1.x))+ 180.0f;
浮动TMAX = PI * 2.0F;
浮动THETA = 1.0F / 360.0f * *角TMAX;
FLOAT2本身=超椭圆(N,1,1,θ-);
浮法角度1 =度(ATAN2(se.y,se.x))+ 180.0f;
FLOAT2零= FLOAT2(0.0,0.0);
浮动DIST1 =距离(SE,零);
浮动dist2 =距离(欠电压,零);

个float4颜色= float4变量(0,0,0,1);
如果(dist2&下; = DIST1)
表色+ = float4变量(0,1,0,1);
返回色;

}



错误似乎与DIST1'和'dist2变数。



(创建了 Shazzam



下面的工作C#代码:

 ; 
使用System.Collections.Generic;
使用System.Drawing中;使用System.Windows.Forms的
;

命名空间WindowsFormsApplication1
{
公共部分Form1类:表格
{
公共Form1中()
{
的InitializeComponent() ;
}

私人无效Form1_Load的(对象发件人,EventArgs五)
{
}

私人无效的run()
{
常量一倍halfPi = Math.PI * 2.0D;
双n值= trackBar1.Value / 10.0D;
双安勤= trackBar2.Value / 100.0d;
双bValue = trackBar3.Value / 100.0d;
label1.Text = nValue.ToString(F2);
label2.Text = aValue.ToString(F2);
label3.Text = bValue.ToString(F2);
双N = n值;
加倍=安勤;
双B = bValue;

//建设点
const int的积分榜= 100;
常量双步= 360.0d /分;
无功名单=新名单,LT;的PointF>();
的for(int i = 0; I< =点;我++)
{
双角=步*我;
双T = 1.0D / 360.0d *角;
双THETA = T * halfPi;
双X;
双Y;
SuperEllipse.Evaluate(N,A,B,THETA,出X,出Y);
list.Add(新的PointF((浮动)×(浮动)Y));
}

/ * *拉丝/
//规模和中心
为(INT指数= 0;指数 - LT; list.Count;指数++)
{
的PointF的PointF =列表[指数]
pointF.X ++;
pointF.Y ++;
pointF.X * =(pictureBox1.Width - 10)/ 2F;
pointF.Y * =(pictureBox1.Height - 10)/ 2F;
pointF.X + = 5;
pointF.Y + = 5;
名单[指数] =的PointF;
}
//绘制和显示
VAR位=新位图(pictureBox1.Width,pictureBox1.Height);使用
(图形图像= Graphics.FromImage(位图))
{
//graphics.TranslateTransform(1,1);
graphics.DrawLines(Pens.Red,list.ToArray());
// graphics.FillClosedCurve(Brushes.Red,FS,FillMode.Alternate);
}
如果(pictureBox1.Image!= NULL)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image =位图;
}

私人无效trackBar1_Scroll(对象发件人,EventArgs五)
{
的run();
}

私人无效trackBar2_Scroll(对象发件人,EventArgs五)
{
的run();
}

私人无效trackBar3_Scroll(对象发件人,EventArgs五)
{
的run();
}
}

公共静态类超椭圆
{
公共静态无效评估(双N,双A,双B,双THETA,出双X,出双Y)
{
双成本= Math.Cos(THETA);
双SINT = Math.Sin(THETA);
X = A * Math.Sign(成本)* Math.Pow(Math.Abs​​(成本),2.0D / N);
Y = B * Math.Sign(圣马丁)* Math.Pow(Math.Abs​​(圣马丁),2.0D / N);
}
}
}



更新



在SuperFormula HLSL(仍然没有右)
在这里输入的形象描述

  sampler2D输入:寄存器(S0); 

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0 LT; /&maxValue分别GT;
///<设置defaultValue> 1.0 LT; /设置defaultValue>
浮动答:注册(C0);

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0 LT; /&maxValue分别GT;
///<设置defaultValue> 1.0 LT; /设置defaultValue>
浮动乙:注册(C1);

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0 LT; /&maxValue分别GT;
///<设置defaultValue> 1.0 LT; /设置defaultValue>
浮动玛:注册(C2);

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0,0.0,0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0,8.0,8.0< /&maxValue分别GT;
///<设置defaultValue> 1.0,1.0,1.0< /设置defaultValue>
FLOAT3 N:注册(C3);

FLOAT4主(FLOAT2 UV:TEXCOORD):COLOR
{
FLOAT2欠电压= UV * FLOAT2(2.0F,2.0F) - FLOAT2(1.0F,1.0F);
浮动角=度(ATAN2(uv1.y,uv1.x))+ 180.0f;
浮动MT = M *角/ 4.0F;
浮动幅度= POW((POW((COS(MT)/ A),N.Y)+ POW((SIN(MT)/ B),N.z)) - (1.0F / n.x的));
FLOAT2零= FLOAT2(0.0,0.0);
浮动DIST1 =距离(欠电压,零);
个float4颜色= float4变量(0,0,0,1);
如果(DIST1&下; =幅度)
表色+ = float4变量(DIST1,1,0,1);
返回色;
}



最后,使用的 Superformula 感谢Kevin:



  sampler2D输入:寄存器(S0) ; 

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0 LT; /&maxValue分别GT;
///<设置defaultValue> 1.0 LT; /设置defaultValue>
浮动答:注册(C0);

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0 LT; /&maxValue分别GT;
///<设置defaultValue> 1.0 LT; /设置defaultValue>
浮动乙:注册(C1);

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0 LT; /&maxValue分别GT;
///<设置defaultValue> 8.0 LT; /设置defaultValue>
浮动玛:注册(C2);

///<总结>说明这个变量的目的< /总结>
///< minValue(最小值)> 0.0,0.0,0.0< / minValue(最小值)>
///<&maxValue分别GT; 8.0,8.0,8.0< /&maxValue分别GT;
///<设置defaultValue> 1.0,1.0,1.0< /设置defaultValue>
FLOAT3 N:注册(C3);

FLOAT4主(FLOAT2 UV:TEXCOORD):COLOR
{
FLOAT2欠电压= UV * FLOAT2(2.0F,2.0F) - FLOAT2(1.0F,1.0F);
浮动角= ATAN2(uv1.y,uv1.x);
浮动MT = M *角/ 4.0F;
浮动幅度= POW((POW((ABS(COS(MT))/ A),纽约州)+ POW((ABS(罪过(MT))/ B),NZ)) - (1.0F /为nx));
FLOAT2零= FLOAT2(0.0,0.0);
浮动DIST1 =距离(欠电压,零);
个float4颜色= float4变量(0,0,0,1);
浮动阿尔法= 1.0F /幅度* DIST1;
如果(DIST1&下; =幅度)
表色+ = float4变量(1,0.5,0,1);

返回色;
}


解决方案

出现问题的原因超椭圆(THETA)返回一个点的角度不必 THETA 。例如,超椭圆(3.6)返回3.2弧度的角度点。
这样一来,在你的的main()功能,它并没有真正意义的比较的幅度欠电压 SE ,因为他们有不同的角度。



请参阅这个图片。清扫直线代表传递到超椭圆的角度,和曲线的端点代表,其中新点实际上是放置。只是偶尔一次的扫线新点的谎言。



如果您使用的是极坐标方程为超椭圆的,而不是一个参数方程,那么你可以用它来执行你的距离测试。为方便起见,钨Mathworld 刚这样一个等式:





您。只需要一个编码并把它放到你的主函数

  FLOAT4主(FLOAT2 UV:TEXCOORD):COLOR 
{
FLOAT2欠电压= UV * FLOAT2(2.0F,2.0F) - FLOAT2(1.0F,1.0F);
浮动角=度(ATAN2(uv1.y,uv1.x))+ 180.0f;
//做:如上图所示实施方程。使用`angle`对THETA。
//`M`应该是4,如果你想有一个四管齐下的形状。
浮动幅度=?

FLOAT2零= FLOAT2(0.0,0.0);
浮动DIST1 =距离(欠电压,零);
float4变量颜色=个float4(0,0,0,1);
如果(DIST1< =大小)//紫外线是超椭圆
色+ =个float4(0,1,0,1)内;
返回色;
}


Update : answer on how to draw one using Superformula is at the end

I need to draw a rounded rectangle such as this one, using a SuperEllipse.

Drawing one when being able to plot wherever was easy :

But in HLSL where you cannot, I got stuck on the condition for plotting or not a pixel :

Here is the HLSL code :

sampler2D input : register(s0);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0</minValue>
/// <maxValue>10.0</maxValue>
/// <defaultValue>4.0</defaultValue>
float N : register(C1);

static const float pi = 3.1415926535f;

float2 superEllipse(float n, float a, float b, float theta)      
{
    float ct = cos(theta);
    float st = sin(theta);
    float x = a * sign(ct) * pow(abs(ct), 2.0f / n);
    float y = b * sign(st) * pow(abs(st), 2.0f / n);
    return float2(x, y);
}

float4 main(float2 uv : TEXCOORD) : COLOR 
{
    float2 uv1 = uv * float2(2.0f, 2.0f) - float2(1.0f, 1.0f);
    float angle = degrees(atan2(uv1.y, uv1.x)) + 180.0f;
    float tMax = pi * 2.0f;
    float theta = 1.0f / 360.0f * angle * tMax;
    float2 se = superEllipse(N, 1, 1, theta);
    float angle1 = degrees(atan2(se.y, se.x)) + 180.0f;
    float2 zero = float2(0.0f, 0.0f);
    float dist1 = distance(se, zero);
    float dist2 = distance(uv1, zero);

    float4 color = float4(0, 0, 0, 1);
    if(dist2 <= dist1)
        color += float4(0, 1, 0, 1);
    return color;

}

Error seems to be with 'dist1' and 'dist2' variables.

(Created with Shazzam)

Here's the working C# code :

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void Run()
        {
            const double halfPi = Math.PI*2.0d;
            double nValue = trackBar1.Value/10.0d;
            double aValue = trackBar2.Value/100.0d;
            double bValue = trackBar3.Value/100.0d;
            label1.Text = nValue.ToString("F2");
            label2.Text = aValue.ToString("F2");
            label3.Text = bValue.ToString("F2");
            double n = nValue;
            double a = aValue;
            double b = bValue;

            // Build list of points
            const int points = 100;
            const double step = 360.0d/points;
            var list = new List<PointF>();
            for (int i = 0; i <= points; i++)
            {
                double angle = step*i;
                double t = 1.0d/360.0d*angle;
                double theta = t*halfPi;
                double x;
                double y;
                SuperEllipse.Evaluate(n, a, b, theta, out x, out y);
                list.Add(new PointF((float) x, (float) y));
            }

            /* Drawing */
            // Scale and center
            for (int index = 0; index < list.Count; index++)
            {
                PointF pointF = list[index];
                pointF.X++;
                pointF.Y++;
                pointF.X *= (pictureBox1.Width - 10)/2f;
                pointF.Y *= (pictureBox1.Height - 10)/2f;
                pointF.X += 5;
                pointF.Y += 5;
                list[index] = pointF;
            }
            // Draw and show
            var bitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            using (Graphics graphics = Graphics.FromImage(bitmap))
            {
                //graphics.TranslateTransform(1, 1);
                graphics.DrawLines(Pens.Red, list.ToArray());
                // graphics.FillClosedCurve(Brushes.Red, fs, FillMode.Alternate);
            }
            if (pictureBox1.Image != null)
            {
                pictureBox1.Image.Dispose();
            }
            pictureBox1.Image = bitmap;
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            Run();
        }

        private void trackBar2_Scroll(object sender, EventArgs e)
        {
            Run();
        }

        private void trackBar3_Scroll(object sender, EventArgs e)
        {
            Run();
        }
    }

    public static class SuperEllipse
    {
        public static void Evaluate(double n, double a, double b, double theta, out double x, out double y)
        {
            double cost = Math.Cos(theta);
            double sint = Math.Sin(theta);
            x = a*Math.Sign(cost)*Math.Pow(Math.Abs(cost), 2.0d/n);
            y = b*Math.Sign(sint)*Math.Pow(Math.Abs(sint), 2.0d/n);
        }
    }
}

Update

SuperFormula in HLSL (still not right)

sampler2D input : register(s0);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0</minValue>
/// <maxValue>8.0</maxValue>
/// <defaultValue>1.0</defaultValue>
float A : register(C0);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0</minValue>
/// <maxValue>8.0</maxValue>
/// <defaultValue>1.0</defaultValue>
float B : register(C1);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0</minValue>
/// <maxValue>8.0</maxValue>
/// <defaultValue>1.0</defaultValue>
float M : register(C2);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0, 0.0, 0.0</minValue>
/// <maxValue>8.0, 8.0, 8.0</maxValue>
/// <defaultValue>1.0, 1.0, 1.0</defaultValue>
float3 N : register(C3);

float4 main(float2 uv : TEXCOORD) : COLOR 
{
    float2 uv1 = uv * float2(2.0f, 2.0f) - float2(1.0f, 1.0f);
    float angle = degrees(atan2(uv1.y, uv1.x)) + 180.0f;
    float mt = M * angle / 4.0f;
    float magnitude = pow((pow((cos(mt) / A), N.y) + pow((sin(mt) / B), N.z)), -(1.0f / N.x));
    float2 zero = float2(0.0f, 0.0f);
    float dist1 = distance(uv1, zero);
    float4 color = float4(0, 0, 0, 1);
    if(dist1 <= magnitude)
        color += float4(dist1, 1, 0, 1);
    return color;
}

Finally, a rounded rectangle using Superformula thanks to Kevin :

sampler2D input : register(s0);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0</minValue>
/// <maxValue>8.0</maxValue>
/// <defaultValue>1.0</defaultValue>
float A : register(C0);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0</minValue>
/// <maxValue>8.0</maxValue>
/// <defaultValue>1.0</defaultValue>
float B : register(C1);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0</minValue>
/// <maxValue>8.0</maxValue>
/// <defaultValue>8.0</defaultValue>
float M : register(C2);

/// <summary>Explain the purpose of this variable.</summary>
/// <minValue>0.0, 0.0, 0.0</minValue>
/// <maxValue>8.0, 8.0, 8.0</maxValue>
/// <defaultValue>1.0, 1.0, 1.0</defaultValue>
float3 N : register(C3);

float4 main(float2 uv : TEXCOORD) : COLOR 
{
    float2 uv1 = uv * float2(2.0f, 2.0f) - float2(1.0f, 1.0f);
    float angle = atan2(uv1.y, uv1.x);
    float mt = M * angle / 4.0f;
    float magnitude = pow((pow((abs(cos(mt)) / A), N.y) + pow((abs(sin(mt)) / B), N.z)), -(1.0f / N.x));
    float2 zero = float2(0.0f, 0.0f);
    float dist1 = distance(uv1, zero);
    float4 color = float4(0, 0, 0, 1);
    float alpha = 1.0f / magnitude * dist1;
    if(dist1 <= magnitude)
        color += float4(1, 0.5, 0, 1);

    return color;
}

解决方案

The problem occurs because superEllipse(theta) returns a point whose angle is not necessarily theta. For example, superEllipse(3.6) returns a point with an angle of 3.2 radians. As a result, in your main() function, it doesn't really make sense to compare the magnitudes of uv1 and se, since they have different angles.

See this image. The sweeping straight line represents the angle passed in to superEllipse, and the end of the curve represents where the new point is actually placed. Only rarely does the new point lie on the sweeping line.

If you use a polar equation for a superellipse, rather than a parametric equation, then you can use it to perform your distance test. Conveniently, Wolfram Mathworld has just such an equation:

You just need to code that up and put it in your main function.

float4 main(float2 uv : TEXCOORD) : COLOR 
{
    float2 uv1 = uv * float2(2.0f, 2.0f) - float2(1.0f, 1.0f);
    float angle = degrees(atan2(uv1.y, uv1.x)) + 180.0f;
    //to do: implement equation shown above. Use `angle` for theta.
    //`m` should be 4 if you want a four-pronged shape.
    float magnitude = ??? 

    float2 zero = float2(0.0f, 0.0f);
    float dist1 = distance(uv1, zero);
    float4 color = float4(0,0,0,1);
    if (dist1 <= magnitude) //uv is inside the superellipse
        color += float4(0,1,0,1);
    return color;
}

这篇关于在绘制一个HLSL超椭圆的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆