Vor ein paar Tagen fing ich an, effizient Bezier Kurven zu zeichnen, und ich stieß auf eine von Charles Loop und Jim Blinn entwickelte Methode, die sehr interessant schien. Wie auch immer, nachdem ich viel mit ihrem Algorithmus experimentiert habe, kann ich einfach nicht sehen, dass sie in der Lage ist, die kubischen Kurven zu rendern. Quadratics sind in Ordnung, kein Problem.Bézier Kurven, Loop und Blinn Stil
Die einzigen Ressourcen, die ich bisher gefunden haben, sind wie folgt:
Resolution Independent Curve Rendering using Programmable Graphics Hardware
die Prüfung bis zu bekommen und schnell läuft, mache ich dies in XNA. Im Grunde gebe ich Texturkoordinaten mit meinen Scheitelpunkten an die GPU weiter, wende eine perspektivische Transformation an und verwende die in allen Artikeln eines Pixel-Shaders genannte Formel, um das Endergebnis zu rendern. Wie auch immer, das Problem (denke ich) liegt darin, wie ich die Texturkoordinaten berechne. Überprüfen Sie diesen Code aus:
public void Update()
{
float a1 = Vector3.Dot(p1, Vector3.Cross(p4, p3));
float a2 = Vector3.Dot(p2, Vector3.Cross(p1, p4));
float a3 = Vector3.Dot(p3, Vector3.Cross(p2, p2));
float d1 = a1 - 2 * a2 + 3 * a3;
float d2 = -a2 + 3 * a3;
float d3 = 3 * a3;
float discr = d1 * d1 * (3 * d2 * d2 - 4 * d1 * d3);
if (discr > 0)
{
Type = CurveTypes.Serpentine;
float ls = 3 * d2 - (float)Math.Sqrt(9 * d2 * d2 - 12 * d1 * d3);
float lt = 6 * d1;
float ms = 3 * d2 + (float)Math.Sqrt(9 * d2 * d2 - 12 * d1 * d3);
float mt = 6 * d1;
TexCoord1 = new Vector3(ls * ms, (float)Math.Pow(ls, 3), (float)Math.Pow(ms, 3));
TexCoord2 = new Vector3((3 * ls * ms - ls * mt - lt * ms)/3, ls * ls * (ls - lt), ms * ms * (ms - mt));
TexCoord3 = new Vector3((lt * (mt - 2 * ms) + ls * (3 * ms - 2 * mt))/3, (float)Math.Pow(lt - ls, 2) * ls, (float)Math.Pow(mt - ms, 2) * ms);
TexCoord4 = new Vector3((lt - ls) * (mt - ms), -(float)Math.Pow(lt - ls, 3), -(float)Math.Pow(mt - ms, 3));
}
else if (discr == 0)
{
Type = CurveTypes.Cusp;
}
else if (discr < 0)
{
Type = CurveTypes.Loop;
}
}
Entschuldigen Sie die Unordnung, es ist nur ein paar Test-Code. p1 ... p4 sind die Kontrollpunkte im Weltraum und TexCoord1 ... TexCoord4 sind die entsprechenden Texturkoordinaten. Dies ist eine Replikation von dem, was in dem GPU Gems Artikel gesagt wird.
Es gibt ein paar Probleme hier, zuerst bei der Berechnung von a3, wir verwenden p2 für beide Parameter, was natürlich immer zu einem (0,0,0) Vektor führt und das Skalarprodukt von diesem und p3 immer nimmt gib uns 0. Das ist ziemlich nutzlos, also warum sollten sie das in dem Artikel erwähnen?
Dies wird natürlich discr falsch machen, und wir werden nicht einmal in der Lage sein zu bestimmen, welche Art von Kurve es ist.
Nachdem ich eine Weile mit dem Code herumgespielt hatte, beschloss ich, genau das zu tun, was sie in der Loop- und Blinn-Arbeit getan hatten. Von diesem bekomme ich etwas in der Art:
public void Update()
{
Matrix m1 = new Matrix(
p4.X, p4.Y, 1, 0,
p3.X, p3.Y, 1, 0,
p2.X, p2.Y, 1, 0,
0, 0, 0, 1);
Matrix m2 = new Matrix(
p4.X, p4.Y, 1, 0,
p3.X, p3.Y, 1, 0,
p1.X, p1.Y, 1, 0,
0, 0, 0, 1);
Matrix m3 = new Matrix(
p4.X, p4.Y, 1, 0,
p2.X, p2.Y, 1, 0,
p1.X, p1.Y, 1, 0,
0, 0, 0, 1);
Matrix m4 = new Matrix(
p3.X, p3.Y, 1, 0,
p2.X, p2.Y, 1, 0,
p1.X, p1.Y, 1, 0,
0, 0, 0, 1);
float det1 = m1.Determinant();
float det2 = -m2.Determinant();
float det3 = m3.Determinant();
float det4 = -m4.Determinant();
float tet1 = det1 * det3 - det2 * det2;
float tet2 = det2 * det3 - det1 * det4;
float tet3 = det2 * det4 - det3 * det3;
float discr = 4 * tet1 * tet3 - tet2 * tet2;
if (discr > 0)
{
Type = CurveTypes.Serpentine;
float ls = 2 * det2;
float lt = det3 + (float)((1/Math.Sqrt(3)) * Math.Sqrt(3 * det3 * det3 - 4 * det2 * det4));
float ms = 2 * det2;
float mt = det3 - (float)((1/Math.Sqrt(3)) * Math.Sqrt(3 * det3 * det3 - 4 * det2 * det4));
TexCoord1 = new Vector3(lt * mt, (float)Math.Pow(lt, 3), (float)Math.Pow(mt, 3));
TexCoord2 = new Vector3(-ms * lt - ls * mt, -3 * ls * lt * lt, -3 * ms * mt * mt);
TexCoord3 = new Vector3(ls * ms, 3 * ls * ls * lt, 3 * ms * ms * mt);
TexCoord4 = new Vector3(0, -ls * ls * ls, -ms * ms * ms);
}
else if (discr == 0)
{
Type = CurveTypes.Cusp;
}
else if (discr < 0)
{
Type = CurveTypes.Loop;
}
}
Rate mal, das hat auch nicht funktioniert. Wie dem auch sei, discr scheint jetzt zumindest ein wenig korrekter zu sein. Zumindest hat es das richtige Vorzeichen, und es ist Null, wenn die Kontrollpunkte so angeordnet sind, dass sie eine Spitze bilden. Ich erhalte immer noch das gleiche visuelle Ergebnis, nur dass die Kurve für eine Weile zufällig verschwindet (die Pixel-Shader-Formel ist immer größer als Null) und kehrt zurück, nachdem ich den Kontrollpunkt zurück zu einer eher quadratischen Form gebracht habe. Hier ist der Pixel-Shader-Code übrigens:
PixelToFrame PixelShader(VertexToPixel PSIn)
{
PixelToFrame Output = (PixelToFrame)0;
if(pow(PSIn.TexCoords.x, 3) - PSIn.TexCoords.y * PSIn.TexCoords.z > 0)
{
Output.Color = float4(0,0,0,0.1);
}
else
{
Output.Color = float4(0,1,0,1);
}
return Output;
}
Das ist über alle nützlichen Informationen, die ich gerade denken kann. Hat jemand eine Idee was los ist? Weil ich ihnen auslaufe.
Ich fing an, diese Methode selbst zu implementieren und werde zurück schreiben, wenn ich etwas arbeite. Wollte nur, dass Sie wissen, dass diese Frage nicht aufgegeben wird :) – Ani
@ananthonline genial! Bitte! – Roliga
Ich habe auch Probleme damit. Hast du es zur Arbeit gebracht? Kannst du meine Frage beantworten? http://stackoverflow.com/questions/15519142/resolution-independent-cubic-bezier-drawing-on-gpu-blinn-loop – scippie