2012-01-31 91 views
8

Bạn có thể đề xuất thuật toán có thể vẽ hình cầu trong không gian 3D bằng cách chỉ sử dụng nguyên mẫu cơ bản plot(x,y,z) (có vẽ một voxel đơn) không?Vẽ hình cầu bằng pixel 3D (voxels)

Tôi đã hy vọng một điều gì đó tương tự như Bresenham's circle algorithm, nhưng đối với 3D thay vì 2D.

FYI, tôi đang làm việc trên dự án phần cứng là màn hình 3D có độ phân giải thấp sử dụng ma trận 3 chiều của đèn LED, vì vậy tôi cần vẽ một hình cầu chứ không chỉ là phép chiếu 2D (tức là vòng tròn).

Dự án này là rất tương tự như sau:

3D LED cube

... hoặc nhìn thấy nó trong hành động here.

Một khả năng tôi có trong tâm trí là thế này:

  • tính toán tọa độ Y của các cực (cho bán kính) (đối với một lĩnh vực trọng tâm trong nguồn gốc, đây sẽ là -r+r)
  • cắt hình cầu: cho mỗi mặt phẳng nằm ngang p i giữa các tọa độ này, tính bán kính của vòng tròn thu được bằng cách giao nhau mặt phẳng cho biết với quả cầu =>r i.
  • vẽ vòng tròn bán kính thực tế r i trên mặt phẳng p i bằng thuật toán của Bresenham.

FWIW, tôi đang sử dụng .NET micro-framework microprocessor, vì vậy lập trình là C#, nhưng tôi không cần câu trả lời để ở trong C#.

+0

Đánh giá bởi quả cầu LED, chúng ta có nên giả sử bạn cần nội thất của hình cầu được vẽ theo cách nào đó không? – NominSim

+0

@NominSim Tôi không nghĩ vậy. Trong trường hợp này, anh ta sẽ không nói về sự lặp lại vòng tròn của Bresenham và chỉ có thể sử dụng giải pháp sức mạnh vũ phu của japreiss. –

+0

@Christian Trên thực tế, tôi muốn có cả hai tùy chọn. –

Trả lời

7

Phương pháp bạo lực đơn giản, mạnh mẽ là lặp qua mọi voxel trong lưới và tính khoảng cách của nó từ trung tâm hình cầu. Sau đó tô màu voxel nếu khoảng cách của nó nhỏ hơn bán kính hình cầu. Bạn có thể lưu nhiều hướng dẫn bằng cách loại bỏ căn bậc hai và so sánh sản phẩm dấu chấm với bán kính bình phương.

Khá xa tối ưu, chắc chắn. Nhưng trên một lưới 8x8x8 như được hiển thị, bạn sẽ cần phải thực hiện thao tác này 512 lần trên mỗi hình cầu. Nếu trung tâm hình cầu nằm trên lưới, và bán kính của nó là một số nguyên, bạn chỉ cần toán số nguyên. Sản phẩm chấm là 3 nhân và 2 bổ sung. Hệ số nhân chậm; giả sử mỗi người có 4 hướng dẫn. Thêm vào đó bạn cần so sánh. Thêm vào tải và lưu trữ, giả sử nó tốn 20 hướng dẫn cho mỗi voxel. Đó là 10240 hướng dẫn trên mỗi hình cầu.

Một Arduino chạy ở 16 MHz có thể đẩy 1562 hình cầu mỗi giây. Trừ khi bạn đang làm tấn toán học khác và I/O, thuật toán này nên là đủ tốt.

+0

Vâng, vấn đề là anh ta dường như không muốn một quả cầu rắn. Trong trường hợp này, bạn có vấn đề rasterization cổ điển trong việc ngăn ngừa các lỗ và các vết sưng trên bề mặt của quả cầu. Mặc dù ông vẫn có thể sử dụng giải pháp của bạn và thực hiện một lần thứ hai vượt qua loại bỏ tất cả các voxels nội thất bằng cách kiểm tra 6-hàng xóm của họ. –

+0

Ồ đúng, bạn không cần một đèo thứ hai để loại bỏ voxels nội thất, vì đối tượng được xác định ngầm. Nhưng trong trường hợp này, bạn phải thực hiện tính toán khoảng cách cao hơn 1 lần trên mỗi voxel. –

+0

Vâng, lúc đầu, tôi nghĩ rằng nó đã được lấp đầy trong video giới thiệu, nhưng trên kiểm tra chặt chẽ hơn nó trông giống như vỏ chỉ. Tôi đồng ý với bình luận đầu tiên của bạn, làm một hoạt động hình thái sẽ đơn giản nhất. – japreiss

4

Giả sử rằng bạn đã có một chức năng cốt truyện như bạn nói:

public static void DrawSphere(double r, int lats, int longs) 
    { 
     int i, j; 
     for (i = 0; i <= lats; i++) 
     { 
      double lat0 = Math.PI * (-0.5 + (double)(i - 1)/lats); 
      double z0 = Math.Sin(lat0) * r; 
      double zr0 = Math.Cos(lat0) * r; 

      double lat1 = Math.PI * (-0.5 + (double)i/lats); 
      double z1 = Math.Sin(lat1) * r; 
      double zr1 = Math.Cos(lat1) * r; 

      for (j = 0; j <= longs; j++) 
      { 
       double lng = 2 * Math.PI * (double)(j - 1)/longs; 
       double x = Math.Cos(lng); 
       double y = Math.Sin(lng); 

       plot(x * zr0, y * zr0, z0); 
       plot(x * zr1, y * zr1, z1); 
      } 
     } 
    } 

chức năng đó sẽ vẽ một hình cầu tại gốc với vĩ độ cụ thể và giải quyết kinh độ (xét xử của khối lập phương của bạn, bạn có thể muốn một cái gì đó khoảng 40 hoặc 50 như một dự đoán sơ bộ). Thuật toán này không "lấp đầy" hình cầu, vì vậy nó sẽ chỉ cung cấp một phác thảo, nhưng chơi với bán kính sẽ cho phép bạn điền vào bên trong, có lẽ với độ phân giải giảm của những con chuột và lâu dài trên đường đi.

+1

bạn không cần nhân các tọa độ bằng r trong các cuộc gọi âm mưu? vì nó là r là không sử dụng, có nghĩa là nó sẽ luôn luôn vẽ một quả cầu bán kính 1. –

1

Chỉ cần tìm thấy một q cũ & một khoảng tạo ra một Sphere Mesh, nhưng câu trả lời đầu thực sự mang đến cho bạn một đoạn ngắn của pseudo-code để tạo X, Y và Z:

(x, y, z) = (sin(Pi * m/M) cos(2Pi * n/N), sin(Pi * m/M) sin(2Pi * n/N), cos(Pi * m/M))

Kiểm tra này Q & Một để biết chi tiết :) procedurally generate a sphere mesh

+1

Đây không phải là giải pháp của NominSim? –

3

tôi không tin chạy thuật toán vòng tròn trung điểm trên mỗi lớp sẽ cho kết quả mong muốn khi bạn đạt được cực, vì bạn sẽ có những khoảng trống trên bề mặt nơi đèn LED không thắp sáng . Điều này có thể cho kết quả bạn muốn, tuy nhiên, do đó sẽ được lên đến thẩm mỹ. Bài viết này dựa trên việc sử dụng thuật toán vòng tròn giữa để xác định bán kính của các lớp thông qua hai octants thẳng đứng giữa, và sau đó khi vẽ từng vòng tròn đó cũng thiết lập các điểm cho các octants cực.

Tôi nghĩ dựa trên nhận xét và câu trả lời của @Nick Udall here sử dụng thuật toán vòng tròn để xác định bán kính lát ngang của bạn sẽ hoạt động với sửa đổi mà tôi đã đề xuất trong nhận xét về câu trả lời của anh ấy. Thuật toán vòng tròn nên được sửa đổi để lấy làm đầu vào một lỗi ban đầu, và cũng vẽ các điểm bổ sung cho các octants cực.

  • Vẽ điểm thuật toán vòng tròn tiêu chuẩn tại y0 + y1y0 - y1: x0 +/- x, z0 +/- z, y0 +/- y1, x0 +/- z, z0 +/- x, y0 +/- y1, tổng 16 điểm. Điều này tạo thành phần lớn dọc của hình cầu.
  • Ngoài ra vẽ các điểm x0 +/- y1, z0 +/- x, y0 +/- zx0 +/- x, z0 +/- y1, y0 +/- z, tổng cộng 16 điểm, sẽ tạo thành các mũ cực cho hình cầu.

Bằng cách chuyển lỗi thuật toán bên ngoài vào thuật toán vòng tròn, nó sẽ cho phép điều chỉnh phụ voxel của vòng tròn của mỗi lớp. Nếu không truyền lỗi vào thuật toán bên trong, đường xích đạo của vòng tròn sẽ được xấp xỉ với một hình trụ và mỗi mặt cầu gần đúng trên trục x, y và z sẽ tạo thành một hình vuông. Với lỗi bao gồm, mỗi khuôn mặt được cung cấp một bán kính đủ lớn sẽ được xấp xỉ như một vòng tròn đầy.


Mã sau đây được sửa đổi từ Midpoint circle algorithm của Wikipedia. Thuật toán DrawCircle có thuật ngữ thay đổi để hoạt động trong mặt phẳng xz, bổ sung điểm ban đầu thứ ba y0, độ lệch y y1 và lỗi ban đầu error0. DrawSphere đã được sửa đổi từ chức năng tương tự để có những điểm ban đầu thứ ba y0 và gọi DrawCircle hơn DrawPixel

public static void DrawCircle(int x0, int y0, int z0, int y1, int radius, int error0) 
{ 
    int x = radius, z = 0; 
    int radiusError = error0; // Initial error state passed in, NOT 1-x 

    while(x >= z) 
    { 
    // draw the 32 points here. 
    z++; 
    if(radiusError<0) 
    { 
     radiusError+=2*z+1; 
    } 
    else 
    { 
     x--; 
     radiusError+=2*(z-x+1); 
    } 
    } 
} 

public static void DrawSphere(int x0, int y0, int z0, int radius) 
{ 
    int x = radius, y = 0; 
    int radiusError = 1-x; 

    while(x >= y) 
    { 
    // pass in base point (x0,y0,z0), this algorithm's y as y1, 
    // this algorithm's x as the radius, and pass along radius error. 
    DrawCircle(x0, y0, z0, y, x, radiusError); 
    y++; 
    if(radiusError<0) 
    { 
     radiusError+=2*y+1; 
    } 
    else 
    { 
     x--; 
     radiusError+=2*(y-x+1); 
    } 
    } 
} 

Đối với một quả cầu bán kính 4 (mà thực sự đòi hỏi 9x9x9), điều này sẽ chạy ba lần lặp của DrawCircle thường lệ, với bản vẽ đầu tiên bán kính 4 vòng tròn (ba bước), thứ hai vẽ bán kính 4 vòng tròn với sai số ban đầu là 0 (cũng ba bước), và sau đó vẽ thứ ba bán kính 3 vòng tròn với lỗi ban đầu 0 (cũng ba bước). Điều đó kết thúc lên được chín điểm tính toán, vẽ 32 pixel mỗi. Điều đó làm cho 32 (điểm trên mỗi vòng tròn) x 3 (cộng hoặc trừ các phép toán cho mỗi điểm) + 6 (cộng, trừ, thay đổi hoạt động trên mỗi lần lặp) = 102 cộng, trừ, hoặc thay đổi hoạt động cho mỗi điểm được tính toán. Trong ví dụ này, đó là 3 điểm cho mỗi vòng tròn = 306 hoạt động mỗi lớp.Thuật toán bán kính cũng thêm 6 hoạt động cho mỗi lớp và lặp lại 3 lần, do đó, 306 + 6 * 3 = 936 phép tính số học cơ bản cho bán kính mẫu là 4. Chi phí ở đây là bạn sẽ lặp lại thiết lập một số pixel mà không cần kiểm tra điều kiện bổ sung (tức là x = 0, y = 0, hoặc z = 0), vì vậy nếu I/O của bạn chậm, bạn có thể tốt hơn khi thêm kiểm tra điều kiện. Giả sử tất cả các đèn LED đã bị xóa khi bắt đầu, vòng tròn ví dụ sẽ đặt 288 đèn LED, trong khi có rất ít đèn LED thực sự được chiếu sáng do các bộ lặp lại. Có vẻ như điều này sẽ hoạt động tốt hơn phương pháp bruteforce cho tất cả các hình cầu phù hợp với lưới 8x8x8, nhưng phương pháp bruteforce sẽ có thời gian nhất quán bất kể bán kính, trong khi phương pháp này sẽ chậm lại khi vẽ các bán kính lớn chỉ một phần sẽ được hiển thị. Do khối hiển thị tăng độ phân giải, tuy nhiên, thời gian giải thuật này sẽ vẫn ổn định trong khi bruteforce sẽ tăng lên.

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