在绘制一个HLSL超椭圆 [英] Drawing a SuperEllipse in 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屋!