Xây dựng một Octree để tạo địa hình


9

Trước đây tôi đã thực hiện diễu hành khối / tứ diện để hiển thị IsoSurface. Nó đã hoạt động ( YouTube ), nhưng hiệu suất rất tệ vì tôi chưa bao giờ thực hiện Cấp độ chi tiết thay đổi dựa trên khoảng cách xem (hoặc thậm chí loại bỏ các đoạn cũ, xa).

Tôi quyết định có một lần đi khác và làm điều đó đúng cách lần này. Tôi đã bắt đầu bằng cách tạo OctreeNode hoạt động như sau khi Build()được gọi.

  • Nếu chunk quá nhỏ để xây dựng, trở lại ngay lập tức.
  • Làm việc nếu bề mặt đi qua khối lượng của khối này.
  • Nếu vậy, sau đó quyết định xem chúng tôi có muốn tăng LOD không (vì máy ảnh đã đóng)
  • Nếu vậy, sau đó sinh ra 8 đứa trẻ và gọi quá trình tương tự trên chúng
  • Nếu không, xây dựng lưới bằng kích thước của nút hiện tại

Một số mã giả:

OctNode Build() {
    if(this.ChunkSize < minChunkSize) {
        return null;
    }
    densityRange = densitySource¹.GetDensityRange(this.bounds);
    if(densityRange.min < surface < densityRange.max) {
        if(loDProvider.DesiredLod(bounds > currentLoD) {
            for(i 1 to 8) {
                if(children[i] == null) {
                    children[i] = new OctNode(...)
                }
                children[i] = children[i].Build();
            }
        } else {
            BuildMesh();
        }
        return this;
    }
}

Cũng như trả về mật độ tại một điểm, nguồn mật độ có thể xác định phạm vi mật độ có thể có cho một khối lượng nhất định.

² Nhà cung cấp LoD lấy một hộp giới hạn và trả về LoD tối đa mong muốn dựa trên vị trí / sự thất vọng của máy ảnh, cài đặt người dùng, v.v ...

Vì vậy, ... Tất cả điều này hoạt động khá tốt. Sử dụng một hình cầu đơn giản làm nguồn Mật độ và hiển thị tất cả các nút:

Octree đầy đủ

Và chỉ những chiếc lá:

Octree chỉ hiển thị lá

Tuy nhiên, có một vài vấn đề:

  • Tôi phải xác định khối lượng giới hạn ban đầu (và nó càng lớn thì tôi càng phải xử lý nhiều hơn)
  • Ở phần gốc của cây, tôi không biết lá sẽ sâu đến mức nào, vì vậy việc đánh số LoD của tôi bắt đầu ở chất lượng thấp nhất (gốc) và tăng lên khi các khối nhỏ hơn. Vì LoD hiện tại có liên quan đến khối lượng ban đầu, nên tôi không sử dụng nhiều khi tôi muốn làm mọi thứ ở kích cỡ / chất lượng cụ thể.

Tôi đã nghĩ đến một vài lựa chọn nhưng cả hai đều có vẻ thiếu sót:

  • Duy trì một bộ sưu tập Octrees và thêm / xóa tùy theo khoảng cách. Không thể thấy cách tôi chia lưới một cách độc đáo¹, cộng với tôi cần một danh sách các nút trống đã biết, đặc biệt là nếu tôi muốn các bề mặt 3D tùy ý (để tránh tính toán lại các khối lượng trống liên tục)
  • Thêm một nút cha mẹ vào gốc hiện tại, sau đó thêm bảy anh chị em cho nút ban đầu. Điều này sẽ hoạt động và theo yêu cầu nhưng có vẻ phức tạp để thu nhỏ lại một cách hợp lý khi người chơi di chuyển qua phong cảnh. Nó cũng sẽ làm cho số LoD thậm chí ít ý nghĩa hơn.

¹ [Để làm rõ Q bên dưới] Hiện tại, nếu 2 nút liền kề vật lý trong cây ở các LOD khác nhau, tôi có một số mã để ép buộc các câu sao cho không có đường nối khi các lưới được tạo. Tôi có thể làm điều này bằng cách biết mật độ cho nhiều nút xung quanh. Trong trường hợp tôi có 2 quãng tám độc lập cạnh nhau, tôi không có cách nào dễ dàng để lấy thông tin này, dẫn đến các đường nối.

Cách tối ưu để tiếp cận điều này là gì?

Câu trả lời:


1

Tôi không chắc chắn mình đang trả lời chính xác câu hỏi, vì vậy tôi sẽ trả lời theo từng phân đoạn và thoải mái trả lời trong các bình luận nếu có sự hiểu lầm về các chi tiết của một câu hỏi cụ thể.

Tôi phải xác định khối lượng giới hạn ban đầu (và nó càng lớn thì tôi càng phải xử lý nhiều hơn)

Điều này dường như không phải là trường hợp. Vì octree tăng độ chi tiết theo cấp số nhân, nên thêm một vài cấp độ ở trên cùng sẽ là một sự gia tăng rất nhỏ trong hiệu suất đạt được.

Ở phần gốc của cây, tôi không biết lá sẽ sâu đến mức nào, vì vậy việc đánh số LoD của tôi bắt đầu ở chất lượng thấp nhất (gốc) và tăng lên khi các khối nhỏ hơn. Vì LoD hiện tại có liên quan đến khối lượng ban đầu, nên tôi không sử dụng nhiều khi tôi muốn làm mọi thứ ở kích cỡ / chất lượng cụ thể.

Nếu bạn sửa lỗi octree gốc của mình thành một số "giá trị đủ lớn" thì "LoD liên quan đến khối lượng ban đầu" sẽ không thành vấn đề. Và như đã đề cập ở trên, tôi không nghĩ việc có thêm cấp độ ở đầu sẽ ảnh hưởng đến hiệu suất tổng thể.

Duy trì một bộ sưu tập Octrees và thêm / xóa tùy theo khoảng cách. Không thể thấy cách tôi kết nối độc đáo, cộng với tôi cần một danh sách các nút trống đã biết, đặc biệt là nếu tôi muốn các bề mặt 3D tùy ý (để tránh tính toán lại các khối lượng trống nhiều lần)

Theo tôi hiểu, giải pháp đề xuất này là về việc giảm LoD khi di chuyển khỏi khu vực chi tiết trước đó. Tôi nghĩ rằng nó sẽ trông rất giống với đường dẫn mã "tăng LoD":

if (loDProvider.DesiredLod(bounds) <(is a lot less than)< currentLoD) { 
    for(i = 1 to 8) { 
        children[i].Destroy();
    }
    BuildMesh();
}

Sau đó, bạn không dành quá nhiều thời gian để kiểm tra các nút ở xa vì bạn có thể dựa vào thực tế là ở xa, không có quá nhiều nút "hoạt động", vì tất cả các nút có độ phân giải cao hơn sẽ bị xóa.


Giả sử các nút nhỏ có quy mô lớn, điều đó có nghĩa là có khả năng hàng chục nếu không phải là hàng trăm cấp khi tôi đi qua một lục địa

Tôi nghĩ rằng thang đo logarit của octree làm cho nó vẫn khả thi. Nếu mức cao nhất của bạn rộng 1.000,0000,000 m (nó sẽ rộng hơn 25 lần so với Trái đất thực và với diện tích bề mặt là 625x) và các bit cấp thấp nhất của bạn có chiều ngang 10cm, đó là 32 cấp độ trong octree, có lẽ là 32 cấp độ đủ quản lý. Nếu bạn muốn một hành tinh rộng hơn Trái đất 100 lần (và với diện tích bề mặt gấp 10000 lần), thì đó chỉ là 3-4 cấp độ bổ sung trong quãng tám của bạn. Tại thời điểm này, người chơi sẽ mất hàng trăm năm để đi bộ trên toàn thế giới và nếu bạn sử dụng toán học dấu phẩy động ngây thơ, thế giới sẽ tích lũy các lỗi chính xác.

Duy trì một bộ sưu tập Octrees và thêm / xóa tùy theo khoảng cách. Không thể thấy cách tôi chia lưới một cách độc đáo¹, cộng với tôi cần một danh sách các nút trống đã biết, đặc biệt là nếu tôi muốn các bề mặt 3D tùy ý (để tránh tính toán lại các khối lượng trống liên tục)

Điều này về cơ bản không tương đương với việc có quãng đường rộng hàng tỷ km nhưng vẫn giữ một danh sách các con trỏ cho mỗi khối, 1km? Sau đó, "chia lưới" chỉ đơn giản là dựa vào các nút có kích thước 2km. Giữ một tham chiếu cục bộ cho từng "khối lớn" cấp trung cũng giúp bạn không phải lặp qua các nút cấp cao nhất, nếu bạn lo lắng về "có thể hàng chục cấp độ tám bổ sung"


Cảm ơn đã trả lời. Tôi không thể chỉ chọn một khối lượng ban đầu lớn vì địa hình của tôi là vô hạn (đó là mục tiêu của tôi). Xem video để có được một ý tưởng. Như vậy, cây nút của tôi sẽ ngày càng cao hơn. Giả sử các nút nhỏ có quy mô đá, điều đó có nghĩa là có khả năng hàng chục nếu không phải là hàng trăm cấp độ khi tôi đi qua một lục địa. Re: Chia lưới, hãy để tôi thêm một số chi tiết cho câu hỏi [Xong]
Cơ bản

như xa như các cầu thủ là có liên quan "một tỷ dặm" là khá gần với "vô hạn". Nhiều đối số cho một khối lượng ban đầu cố định được thêm vào để trả lời.
Jimmy

Tôi vẫn không tin. Tại sao có hơn 30 lớp xử lý vô dụng? Nó không thanh lịch, nói gì đến hiệu quả. Tôi đưa ra quan điểm của bạn về thời gian để đi bộ, nhưng chúng ta chỉ đơn giản nói về việc tạo địa hình. Không có gì nói rằng tôi phải tập trung vào điểm gốc, cũng không thể bay ở tốc độ cao (mặc dù tôi sẽ không được chia lưới ở tốc độ đó!). FWIW Tôi đang sử dụng gấp đôi nội bộ để tránh vấn đề chính xác đó.
Cơ bản
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.