2012-04-24 37 views
8

Một vài ngày trước, tôi bắt đầu nhìn vào hiệu quả vẽ đường cong bezier, và tôi đi qua một phương pháp này được phát triển bởi Charles Loop và Jim Blinn có vẻ rất thú vị. Làm thế nào bao giờ hết, sau rất nhiều thử nghiệm với thuật toán của họ, tôi dường như không thể làm cho nó có khả năng render các đường cong khối. Quadratics là tốt, không có vấn đề ở đó.Bézier đường cong, Loop và Blinn phong cách

Các nguồn tài nguyên duy nhất mà tôi đã tìm thấy cho đến nay như sau:

GPU Gems 3 Chapter 25

Curvy Blues

Resolution Independent Curve Rendering using Programmable Graphics Hardware

Để có được thử nghiệm và chạy nhanh, tôi đang làm điều này trong XNA. Về cơ bản tôi đang chuyển các tọa độ kết cấu với các đỉnh của tôi lên GPU, áp dụng phép biến đổi phối cảnh và sử dụng công thức được đề cập trong tất cả các bài viết trong trình đổ bóng pixel để hiển thị kết quả cuối cùng. Làm thế nào bao giờ, vấn đề (tôi nghĩ) đặt trong cách tôi tính toán các tọa độ kết cấu. Kiểm tra mã này:

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

Xin lỗi, đó chỉ là một số mã thử nghiệm. p1 ... p4 là các điểm kiểm soát trong không gian thế giới, và TexCoord1 ... TexCoord4 là tọa độ kết cấu tương ứng. Đây là một bản sao của những gì được nói trong bài viết về Gems của GPU. Có một vài vấn đề ở đây, đầu tiên khi tính a3, chúng tôi sử dụng p2 cho cả hai tham số, tất nhiên luôn dẫn đến một (0,0,0) vectơ và lấy sản phẩm chấm của p3 và luôn luôn cung cấp cho chúng tôi 0. Điều đó hoàn toàn vô dụng, vậy tại sao họ lại đề cập đến điều đó trong bài báo?

Điều này tất nhiên sẽ làm cho không chính xác, và chúng tôi thậm chí sẽ không thể xác định loại đường cong đó là gì.

Sau khi không quan tâm đến mã đó trong một thời gian, tôi quyết định cố gắng làm điều đó một cách chính xác lý do tại sao họ làm trong giấy Loop và Blinn. Từ đó tôi nhận được một cái gì đó như thế này:

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

Đoán những gì, điều đó không có tác dụng. Làm thế nào bao giờ, discr có vẻ là ít nhất một chút chính xác hơn bây giờ. Ít nhất nó có dấu hiệu đúng, và nó bằng không khi các điểm điều khiển được sắp xếp để tạo thành một đỉnh. Tuy nhiên, tôi vẫn nhận được kết quả trực quan giống nhau, ngoại trừ đường cong biến mất một cách ngẫu nhiên trong một thời gian (công thức đổ bóng pixel luôn lớn hơn 0) và trả về sau khi tôi di chuyển điểm điều khiển trở lại nhiều hình vuông hơn. Dưới đây là mã trình tạo pixel theo cách:

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

Đó là tất cả thông tin hữu ích mà tôi có thể nghĩ ngay bây giờ. Có ai có bất kỳ ý tưởng gì đang xảy ra? Bởi vì tôi đang chạy ra khỏi chúng.

+0

Tôi bắt đầu tự triển khai phương pháp này và sẽ đăng lại khi tôi làm việc gì đó. Chỉ muốn bạn biết rằng câu hỏi này không bị bỏ rơi :) – Ani

+0

@ananthonline awesome! Lam ơn Lam! – Roliga

+0

Tôi cũng gặp sự cố với vấn đề này. Bạn có làm cho nó hoạt động không? Bạn có thể trả lời câu hỏi của tôi không? http://stackoverflow.com/questions/15519142/resolution-independent-cubic-bezier-drawing-on-gpu-blinn-loop – scippie

Trả lời

7

Tôi đã nhìn vào giấy và mã của bạn, và nó đường nối bạn đang thiếu phép nhân với ma trận M3.

Tọa độ p1, p2, p3 và p4 của bạn phải được đặt trong ma trận và nhân với ma trận M3, trước khi sử dụng nó để tính toán các yếu tố quyết định. ví dụ:

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; 

Sau đó, bạn sử dụng mỗi hàng của ma trận C làm tọa độ cho ma trận m1 đến m4 trong mã của bạn. Trường hợp giá trị đầu tiên và thứ hai của hàng là tọa độ x, y và giá trị cuối cùng là tọa độ w.

Cuối cùng, ma trận tọa độ kết cấu cần phải được thay đổi theo nghịch đảo của M3 ví dụ:

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; 

Mỗi hàng ma trận kết quả tương ứng với tọa độ kết cấu cần thiết cho trình đổ bóng.

Tôi chưa tự mình triển khai, vì vậy không thể đảm bảo rằng nó sẽ giải quyết được sự cố của bạn. Nó chỉ đơn giản là những gì tôi nhận thấy là mất tích từ việc thực hiện của bạn sau khi đọc bài báo.

Tôi hy vọng điều này sẽ hữu ích, nếu tôi sai, hãy cho tôi biết nguyên nhân tôi sẽ cố gắng thực hiện việc này sớm.

+0

Người đàn ông tuyệt vời! Không thể tin rằng tôi đã có nó messed lên rằng xấu: D Vấn đề là mặc dù, det1 luôn luôn có vẻ là 0, mà chắc chắn là không đúng. Tôi sẽ làm một số thử nghiệm vào ngày mai và xem tôi có thể tìm ra vấn đề không. Cho tôi biết nếu bạn có bất kỳ ý tưởng nào. – Roliga

+1

Trong bài báo trong phần tích phân Cubics (4.4) trong đoạn đầu tiên, nó nói rằng đối với hình khối tích phân nó sẽ có yếu tố quyết định đầu tiên bằng không. Làm giảm phương trình mã đổ bóng xuống k^3-lm – rdsgalvao

+0

Ồ đúng. Lý do tôi nghĩ rằng có điều gì đó sai vì tôi chỉ nghĩ rằng các đường cong thực sự có vòng lặp được cho là sử dụng phương trình vòng lặp, nhưng điều đó dường như không đúng, vì vậy sau khi thực hiện phương trình vòng lặp, tất cả đều hoạt động. Bây giờ trên để cấu trúc điều này để nó thực sự có thể được sử dụng: D Tôi sẽ thả một bình luận nếu tôi chạy vào bất kỳ vấn đề nhiều hơn nữa. – Roliga

Các vấn đề liên quan