在HLSL中绘制SuperEllipse

更新:关于如何使用Superformula绘制一个的答案就在最后

我需要使用SuperEllipse绘制一个圆角矩形,例如这个。 在此处输入图像描述

在能够在任何地方轻松绘制时绘制一个:

在此处输入图像描述

但是在你不能的HLSL中,我遇到了绘图或不是像素的条件:

在此处输入图像描述

这是HLSL代码:

sampler2D input : register(s0); /// Explain the purpose of this variable. /// 0.0 /// 10.0 /// 4.0 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; } 

错误似乎与’dist1’和’dist2’变量有关。

(使用Shazzam创建)

这是有效的C#代码:

 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(); 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); } } } 

更新

HLSL中的SuperFormula(仍然不对) 在此处输入图像描述

 sampler2D input : register(s0); /// Explain the purpose of this variable. /// 0.0 /// 8.0 /// 1.0 float A : register(C0); /// Explain the purpose of this variable. /// 0.0 /// 8.0 /// 1.0 float B : register(C1); /// Explain the purpose of this variable. /// 0.0 /// 8.0 /// 1.0 float M : register(C2); /// Explain the purpose of this variable. /// 0.0, 0.0, 0.0 /// 8.0, 8.0, 8.0 /// 1.0, 1.0, 1.0 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), Ny) + pow((sin(mt) / B), Nz)), -(1.0f / Nx)); 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; } 

最后,感谢凯文使用Superformula的圆角矩形:

在此处输入图像描述

 sampler2D input : register(s0); /// Explain the purpose of this variable. /// 0.0 /// 8.0 /// 1.0 float A : register(C0); /// Explain the purpose of this variable. /// 0.0 /// 8.0 /// 1.0 float B : register(C1); /// Explain the purpose of this variable. /// 0.0 /// 8.0 /// 8.0 float M : register(C2); /// Explain the purpose of this variable. /// 0.0, 0.0, 0.0 /// 8.0, 8.0, 8.0 /// 1.0, 1.0, 1.0 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), Ny) + pow((abs(sin(mt)) / B), Nz)), -(1.0f / Nx)); 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; } 

出现此问题的原因是superEllipse(theta)返回一个角度不一定是theta 。 例如, superEllipse(3.6)返回角度为3.2弧度的点。 因此,在main()函数中,比较uv1se的大小并没有多大意义,因为它们具有不同的角度。

看到这个图像 。 扫描直线表示传递给superEllipse的角度,曲线的末端表示实际放置新点的位置。 只有很少的新点出现在清扫线上。

如果对超椭圆使用极坐标方程而不是参数方程,则可以使用它来执行距离测试。 方便的是, Wolfram Mathworld就是这样一个等式:

在此处输入图像描述

您只需将其编码并将其放入主函数中即可。

 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; }