2012-04-24 15 views
8

私は数日前にベジエ曲線を効率的に描くことを検討し始めました。チャールズループとジムブリンが開発したこの方法は非常に興味深いものでした。アルゴリズムを試してみたのですが、立方体カーブを描くことができないようです。 Quadraticsは問題ありません。ベジエ曲線、ループ、ブリンスタイル

次のように私がこれまでに発見しただけのリソースがされています

GPU Gems 3 Chapter 25

Curvy Blues

Resolution Independent Curve Rendering using Programmable Graphics Hardware

検査まで、迅速に実行しているを取得するには、私はでこれをやっていますXNA。基本的には、頂点を持つテクスチャ座標をGPUに渡して、透視変換を適用し、ピクセルシェーダのすべての記事に記載されている式を使用して最終結果を描画します。どのくらいまで、問題は(私が思う)テクスチャの座標をどのように計算するかにあります。このコードをチェックしてください:

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

これは単なるテストコードです。 p1 ... p4はワールド空間の制御点、TexCoord1 ... TexCoord4は対応するテクスチャ座標です。これは、GPU Gemsの記事で述べられている内容の複製です。

ここでは、a3を計算するときに、両方のパラメータにp2を使用します。もちろん、常に(0,0,0)ベクトルになります。それはかなり役に立たないので、なぜ彼らはその記事に言及するだろうか?

これはもちろん、discrを間違ったものにしてしまい、どのようなカーブの種類を決定することさえできません。

しばらくの間、そのコードを見て回った後、私はループとBlinnの論文で何をしたのかを正確にしようと決めました。これから私はこのようなものを得ます:

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

何か、それはどちらもうまくいきませんでした。どのくらいまで、discrは少なくとももう少し正しいと思われる。少なくともそれには右の符号があり、制御点がカスプを形成するように配置されているときはゼロになります。しかし、カーブがしばらくランダムに消えてしまう(ピクセルシェーダーの式は常にゼロより大きい)点を除いて、同じ視覚的結果を得て、コントロールポイントをより多くの正方形に戻した後に戻ります。ここではピクセルシェーダコードを紹介します:

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

これは私が今考えているすべての有用な情報です。誰が何が起こっているか考えているのですか?私はそれらを使い果たしているので。

+0

私はこの方法を自分で実装し始めました。ちょうどあなたがこの質問が放棄されていないことを知りたかった:) – Ani

+0

@ananthonline awesome!してください! – Roliga

+0

私もこれに問題があります。あなたはそれを働かせましたか?私の質問に答えることができますか? http://stackoverflow.com/questions/15519142/resolution-independent-cubic-bezier-drawing-on-gpu-blinn-loop – scippie

答えて

7

私は紙とあなたのコードを見ていて、あなたはM3マトリックスへの乗算が不足しています。

p1、p2、p3、およびp4の座標は、行列を計算するために使用する前に、行列に配置し、M3行列を乗じる必要があります。例えば、 。

Matrix M3 = Matrix(
    1, 0, 0, 0, 
    -3, 3, 0, 0, 
    3, -6, 3, 0, 
    -1, 3, -3, 1); 
Matrix B = Matrix(
    p1.X, p1.Y, 0, 1, 
    p2.X, p2.Y, 0, 1, 
    p3.X, p3.Y, 0, 1, 
    p4.X, p4.Y, 0, 1); 
Matrix C = M3*B; 

次に、コード内のm1〜m4行列の座標として、C行列の各行を使用します。ここで、行の第1および第2の値はx、y座標であり、最後はw座標である。

最後に、テクスチャ座標のマトリクスはM3 の逆数で乗算する必要があります。

Matrix invM3 = Matrix(
    1, 0, 0, 0, 
    1, 0.3333333, 0, 0, 
    1, 0.6666667, 0.333333, 0, 
    1, 1, 1, 1); 
Matrix F = Matrix(
    TexCoord1, 
    TexCoord2, 
    TexCoord3, 
    TexCoord4); 
Matrix result = invM3*F; 

結果の行列の各行は、シェーダに必要なテクスチャ座標に対応します。

私はまだそれを実装していないので、それがあなたの問題を解決することを保証することはできません。それは単に私が論文を読んだ後であなたの実装から見逃していることに気付いたものです。

私が間違っている場合、これが助けてくれたら、すぐにこれを試してみてください。

+0

恐ろしい男!私はそれが悪いことを混乱させたとは信じられない:D問題はあるが、det1は常に0であるようだが、それは間違いなく正しい。私は明日にもう少しテストを行い、問題を見つけることができるかどうかを見極めるつもりです。アイデアがあれば教えてください。 – Roliga

+1

最初のパラグラフのIntegral Cubicsセクション(4.4)の論文では、積分3次方程式の場合、最初の行列式が0に等しくなると言います。シェーダのコード式をk^3-lmに減らすのは – rdsgalvao

+0

です。私は何かが間違っていると思った理由は、実際にはループを持っているカーブがループ式を使用すると考えられていただけだと思ったからですが、そうではなかったようです。今、このことを実際に使用できるように構造化しています:D私はもう一つの問題に遭遇すると別のコメントを削除します。 – Roliga

関連する問題