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:
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.
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
@ananthonline awesome! Lam ơn Lam! – Roliga
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