Áp suất mô phỏng trong mô phỏng chất lỏng dựa trên lưới


30

Tôi có một hệ thống nước dựa trên lưới 2D trong trò chơi XNA của mình, chúng tôi có một phương pháp sử dụng automata di động để mô phỏng nước rơi và lan rộng.

Ví dụ về nước chảy xuống một dốc:

Vật lý nước

Mỗi ô có thể chứa khối lượng từ 0 đến 255 giá trị của chất lỏng, được lưu trữ trong một byte. Tôi không sử dụng floats, hệ thống nước cũ mà tôi đã làm, tuy nhiên nó đã thêm các biến chứng và có một hiệu suất.

Mỗi ô nước tự cập nhật với một bộ quy tắc đơn giản:

  1. Nếu ô bên dưới có không gian trong đó, hãy di chuyển càng nhiều càng tốt từ ô hiện tại sang ô dưới cùng (Chảy xuống)
  2. Nếu 2 mặt không giống nhau và không bằng 0 và cả hai đều có thể qua được, chúng ta sẽ lấy tổng của 3 ô (trái + hiện tại + phải) và chia cho 3 phần còn lại ở ô giữa (hiện tại)
  3. Nếu quy tắc trên cho số 2 là tổng, chúng ta nên chia các ô thành hai bên (1, 0, 1)
  4. Nếu quy tắc 2 cho 1 là tổng, hãy chọn một bên ngẫu nhiên để chảy vào
  5. Nếu quy tắc 2 thất bại, chúng ta nên kiểm tra xem một bên có thể vượt qua được không và bên kia không. Nếu đó là sự thật, chúng tôi chia một nửa ô hiện tại cho 2 ô

Làm thế nào tôi có thể mở rộng logic này để bao gồm áp lực? Áp lực sẽ làm cho chất lỏng tăng lên trên "U-Bends" và lấp đầy các túi khí.

Ví dụ về cách hiện tại không thành công:

Áp lực thất bại

Nước sẽ chảy và cân bằng ở mỗi bên của U-Bend. Ngoài ra, tôi đã tạo ra các phương pháp để tìm hiểu xem khối nước xuống bao xa và do đó nó chịu áp lực bao nhiêu. Bây giờ tôi cần có thể lấy những con số này và áp dụng chúng cho các khu vực khác để cân bằng áp lực.


Vấn đề là thật khó để giữ cho nó một automata di động. Vì bây giờ mỗi khối cần biết nhiều hơn những gì bên cạnh nó. Tôi đã tạo một hệ thống tương tự như hệ thống bạn muốn trong 3D. Đây là một hệ thống khá phức tạp, nhưng tôi nghĩ nó sẽ dễ thực hiện hơn trong 2D.
MichaelHouse

@ Byte56 Vâng, chúng tôi không cần nó là automata di động, miễn là chúng tôi có thể giữ cho nó chạy ở tốc độ hợp lý.
Cyral

3
Tôi sẽ tạo ra một câu trả lời đầy đủ nếu tôi tìm thấy một chút thời gian tối nay. Tuy nhiên, nói một cách đơn giản, về cơ bản, tôi đã tạo ra đường dẫn nước. Khối muốn tìm một nơi nào đó với ít áp lực hơn để đi. Họ tìm đường đi qua vùng nước khác để tìm nơi nào đó có ít nước hơn họ (không khí bên cạnh nước bao gồm). Nó giải quyết phần lớn các trường hợp sử dụng.
MichaelHouse

Cảm ơn, điều đó sẽ được đánh giá cao. Tôi đã đọc một số cuộc phỏng vấn với nhà sản xuất Pháo đài Lùn và anh ấy đã làm điều này tôi tin, nhưng tôi không chắc chắn làm thế nào để khắc phục một số vấn đề anh ấy gặp phải, vì vậy tôi chưa bao giờ thực sự cố gắng.
Cyral

1
Lưu ý rằng, một khi bạn được thêm áp suất không khí, hai ví dụ túi khí có khả năng hoàn toàn hợp lệ (buồng áp suất đóng). Tôi giả sử bạn không sử dụng 255 byte , mà là các giá trị 0-255; trong mọi trường hợp, có lẽ bạn sẽ không muốn sử dụng toàn bộ phạm vi đó. Có lẽ tôi sẽ giới hạn ở mức, hmm, 0-15 cho '1 bầu không khí' áp lực (không có thứ gọi là áp suất 'âm', phải không?), Cho phép áp lực cao hơn mà bạn hiện đang thiếu. Khi bạn bao gồm các khối 'không khí' trong sim, 'trọng lượng' tự nhiên của các khối nước sẽ khiến nó chảy xung quanh các khúc cua.
Đồng hồ-Muse

Câu trả lời:


6

Lưu ý rằng tôi chưa bao giờ làm điều này; đây chỉ là những ý tưởng có thể giúp đỡ Hoặc có thể hoàn toàn không có thật. Tôi đã muốn giải quyết vấn đề này kể từ Terraria nhưng hiện tại tôi không làm việc với một trò chơi như vậy.

Một cách tôi đã cố gắng là cung cấp cho mỗi khối nước bề mặt (bất kỳ khối nào có nước trong đó và không có khối nước nào ở trên nó) một giá trị áp suất ban đầu bằng (hoặc một hàm của) chiều cao của nó từ đáy thế giới. Giá trị áp suất ngầm định của bất kỳ gạch không thể xuyên thủng nào là MAX_PRESSURE(giả sử 255) và đối với gạch không khí mở là MIN_PRESSURE(0).

Áp lực sau đó được lan truyền lên / xuống / sang một bên từ bất kỳ ô nào có áp suất cao hơn đến các ô có áp suất thấp hơn trong mỗi tích tắc, kiểu tự động di động. Tôi phải có được một mô phỏng thực tế để tìm ra chính xác những gì cần cân bằng. Áp suất của một khối phải bằng với áp suất ngầm của nó cộng với áp suất "dư thừa" từ xung quanh được cân bằng (vì vậy bạn chỉ cần lưu trữ áp suất dư này, không phải áp suất ngầm).

Nếu gạch bề mặt có áp suất lớn hơn áp suất dựa trên chiều cao ngầm định của nó và nếu gạch ở trên có không gian trống cho nước, một phần nhỏ nước sẽ được di chuyển lên trên. Nước chỉ chảy xuống nếu cả hai gạch có phòng có áp suất thấp hơn dự kiến.

Điều này mô phỏng đại khái ý tưởng rằng "điểm" nước càng sâu thì càng có nhiều áp lực, mặc dù các giá trị áp suất đại diện cho chiều cao nhiều hơn áp suất thực tế (vì gạch cao hơn dự kiến ​​sẽ có "áp suất" cao hơn). Điều này làm cho áp lực hơi giống như hthuật ngữ trong phương trình (nhưng không thực sự):

P' = P + qgh

Kết quả là nếu áp lực của nước cao hơn độ sâu của nó, nó sẽ bị đẩy lên. Điều đó có nghĩa là mực nước trong các hệ thống kín sẽ cân bằng áp suất trên tất cả các mức độ cao theo thời gian.

Tôi không chắc chắn làm thế nào để đối phó hoặc liệu người ta thậm chí có cần phải xử lý "bong bóng khí" sẽ được tạo ra hay không (trong đó một viên gạch không có bề mặt sẽ có lượng nước không đầy khi nước được đẩy lên trên). Tôi vẫn không chắc chắn làm thế nào bạn sẽ tránh được các vòng áp lực nước không bằng nhau ở một bên và sau đó sau khi đánh dấu là không bằng nhau ở phía bên kia, qua lại.


20

Tôi đã tạo một hệ thống tương tự như hệ thống mà bạn theo đuổi trong 3D. Tôi có một đoạn video ngắn trình bày các cơ chế đơn giản của nó ở đây và một bài đăng blog ở đây .

Đây là một gif nhỏ tôi làm bằng cơ học áp lực đằng sau một bức tường vô hình (chơi ở tốc độ cao):

nhập mô tả hình ảnh ở đây

Hãy để tôi giải thích các dữ liệu liên quan, để đưa ra ý tưởng về một số tính năng của hệ thống. Trong hệ thống hiện tại, mỗi khối nước chứa 2 byte sau:

//Data2                          Data
//______________________________  _____________________________________
//|0    |0      |000   |000    |  |0        |0       |000      |000   |
//|Extra|FlowOut|Active|Largest|  |HasSource|IsSource|Direction|Height|
//------------------------------  -------------------------------------
  • Height là lượng nước trong khối lập phương, tương tự như áp lực của bạn, nhưng hệ thống của tôi chỉ có 8 cấp độ.
  • Directionlà hướng của dòng chảy. Khi quyết định nơi nước sẽ chảy tiếp theo, nhiều khả năng nó sẽ tiếp tục theo hướng hiện tại. Điều này cũng được sử dụng để nhanh chóng theo dõi một dòng chảy ngược lên khối nguồn của nó khi cần thiết.
  • IsSourcecho biết nếu khối này là một khối nguồn, có nghĩa là nó không bao giờ hết nước. Được sử dụng cho nguồn của sông, suối, v.v ... Khối bên trái trong gif ở trên là một khối nguồn chẳng hạn.
  • HasSourcecho biết nếu khối này được kết nối với một khối nguồn. Khi được kết nối với một nguồn, các khối sẽ cố gắng khai thác nguồn để có thêm nước trước khi tìm các khối không nguồn "đầy đủ" khác.
  • Largestcho khối này biết dòng chảy lớn nhất giữa nó và khối nguồn của nó là gì. Điều này có nghĩa là nếu nước chảy qua một khe hẹp, nó sẽ hạn chế dòng chảy vào khối này.
  • Activelà một truy cập. Khi khối này có dòng hoạt động đi qua nó, đến nó hoặc từ nó, hoạt động được tăng lên. Nếu không hoạt động được giảm ngẫu nhiên. Khi hoạt động chạm 0 (nghĩa là không hoạt động), lượng nước sẽ bắt đầu giảm trong khối này. Loại hành động này như bốc hơi hoặc ngấm xuống đất. ( Nếu bạn có dòng chảy, bạn nên có ebb! )
  • FlowOutcho biết nếu khối này được kết nối với một khối lập phương ở rìa thế giới. Khi một con đường đến rìa thế giới được tạo ra, nước có xu hướng chọn con đường đó hơn bất kỳ con đường nào khác.
  • Extra là một chút thêm cho việc sử dụng trong tương lai.

Bây giờ chúng ta đã biết dữ liệu, hãy xem xét tổng quan cấp cao của thuật toán. Ý tưởng cơ bản của hệ thống là ưu tiên chảy xuống và ra ngoài. Như tôi giải thích trong video, tôi làm việc từ dưới lên. Mỗi lớp nước được xử lý một cấp tại một thời điểm trong trục y. Các khối cho mỗi cấp được xử lý ngẫu nhiên, mỗi khối sẽ cố gắng kéo nước từ nguồn của nó trên mỗi lần lặp.

Các khối dòng chảy kéo nước từ nguồn của chúng bằng cách theo hướng dòng chảy của chúng trở lại cho đến khi chúng đạt đến một khối nguồn hoặc một khối dòng chảy không có cha mẹ. Lưu trữ hướng dòng chảy trong mỗi khối làm cho việc đi theo đường dẫn đến nguồn dễ dàng như duyệt qua danh sách được liên kết.

Mã giả cho thuật toán như sau:

for i = 0 to topOfWorld //from the bottom to the top
   while flowouts[i].hasitems() //while this layer has flow outs
       flowout = removeRandom(flowouts[i]) //select one randomly
       srcpath = getPathToParent(flowout) //get the path to its parent
       //set cubes as active and update their "largest" value
       //also removes flow from the source for this flow cycle
       srcpath.setActiveAndFlux() 

//now we deal with regular flow
for i = 0 to topOfWorld //from the bottom to the top
    while activeflows[i].hasitems() //while this layer has water
        flowcube = removeRandom(activeflows[i]) //select one randomly
        //if the current cube is already full, try to distribute to immediate neighbors
        flowamt = 0
        if flowcube.isfull 
           flowamt = flowcube.settleToSurrounding
        else
           srcpath = getPathToParent(flowcube) //get the path to its parent
           flowamt = srcpath.setActiveAndFlux()
           flowcube.addflow(flowamt)

        //if we didn't end up moving any flow this iteration, reduce the activity
        //if activity is 0 already, use a small random chance of removing flow
        if flowamt == 0
           flowcube.reduceActive()

 refillSourceCubes()

Các quy tắc cơ bản để mở rộng luồng trong đó (được ưu tiên theo thứ tự):

  1. Nếu khối bên dưới có ít nước, chảy xuống
  2. Nếu khối lập phương liền kề trên cùng mức có ít nước hơn, hãy chảy bên.
  3. Nếu khối trên có ít nước VÀ khối nguồn cao hơn khối ở trên, hãy chảy lên.

Tôi biết, đó là mức khá cao. Nhưng thật khó để đi vào chi tiết hơn mà không đi vào chi tiết.

Hệ thống này hoạt động khá tốt. Tôi có thể dễ dàng lấp đầy các hố nước, tràn ra ngoài để tiếp tục ra ngoài. Tôi có thể lấp đầy các đường hầm hình chữ U như bạn thấy trong gif ở trên. Tuy nhiên, như tôi đã nói, hệ thống chưa hoàn thiện và tôi chưa làm việc hết. Tôi đã không làm việc trên hệ thống dòng chảy trong một thời gian dài (tôi quyết định rằng nó không cần thiết cho alpha và tôi đã giữ nó ở trạng thái chờ). Tuy nhiên, các vấn đề tôi đã giải quyết khi tôi giữ nó ở đâu:

  • Bể bơi . Khi nhận được một vũng nước lớn, các con trỏ từ con đến cha mẹ giống như một mớ hỗn độn điên rồ của bất kỳ khối lập phương ngẫu nhiên nào được chọn để chảy theo bất kỳ hướng nào. Giống như làm đầy một bồn tắm với chuỗi ngớ ngẩn. Khi bạn muốn tháo bồn, bạn có nên đi theo con đường của chuỗi ngớ ngẩn trở về nguồn của nó không? Hay bạn chỉ nên lấy bất cứ thứ gì gần nhất? Vì vậy, trong các tình huống mà các hình khối nằm trong một bể lớn, chúng có thể nên bỏ qua dòng chảy bố mẹ và kéo từ bất cứ thứ gì lên trên chúng. Tôi đã đưa ra một số mã làm việc cơ bản cho việc này, nhưng chưa bao giờ có một giải pháp tao nhã mà tôi có thể hài lòng.

  • Nhiều cha mẹ . Một luồng con có thể dễ dàng được nuôi bởi nhiều hơn một luồng cha. Nhưng đứa trẻ có một con trỏ đến một cha mẹ duy nhất sẽ không cho phép điều đó. Điều này có thể được khắc phục bằng cách sử dụng đủ bit để cho phép một bit cho mỗi hướng cha có thể. Và có khả năng thay đổi thuật toán để chọn ngẫu nhiên một đường dẫn trong trường hợp có nhiều cha mẹ. Nhưng, tôi chưa bao giờ đến đó để kiểm tra và xem những vấn đề khác có thể phơi bày.


Cảm ơn! Rất nhiều thông tin! Tôi sẽ bắt đầu làm việc này sớm và chấp nhận nó nếu mọi việc suôn sẻ.
Cyral

Điều chắc chắn. Tôi tưởng tượng một hệ thống lai của bạn và cái này sẽ rất hiệu quả cho một thế giới 2D. Ping tôi trong trò chuyện (với @ byte56) nếu bạn muốn thảo luận chi tiết.
MichaelHouse

Được rồi, có thể là một ngày hoặc lâu hơn trước khi tôi có cơ hội để thử điều này.
Cyral

3
Có thể hiểu được. Tôi có lẽ đã dành nhiều tháng để làm việc đó (và làm việc lại). Tôi sẽ ở đây một thời gian nữa :)
MichaelHouse

2

Tôi đồng ý với Sean nhưng tôi sẽ làm khác đi một chút:

Một khối tạo ra một áp lực bằng trọng lượng của chính nó (bao nhiêu nước trong đó) và áp dụng nó cho các khối bên dưới và bên cạnh nó. Tôi thấy không có lý do gì vị trí của nó trên thế giới có liên quan.

Trên mỗi đánh dấu di chuyển nước từ áp suất cao đến áp suất thấp nhưng chỉ di chuyển một phần nước cần thiết để cân bằng. Nước cũng có thể được đẩy lên nếu áp suất trong khối quá lớn so với áp suất được đặt xuống trên hình vuông.

Bạn sẽ nhận được các vòng lặp khi áp lực nước chảy quá xa một chiều và sau đó phải sửa nhưng vì bạn không di chuyển toàn bộ lượng nước trên mỗi tích tắc, những thứ này sẽ bị ẩm. Tôi nghĩ rằng đó thực sự là một điều tốt khi bạn sẽ có được hiệu ứng dâng trào khi nước tràn vào một khu vực như bạn thực tế.


Nếu nước di chuyển lên khi áp suất từ ​​phía trên quá lớn, thì nó sẽ không chuyển sang khối áp suất thấp hơn. Để áp lực ở trên quá lớn, nó sẽ phải lớn hơn khối bên dưới. Ngoài ra, áp lực phải di chuyển lên cũng như xuống và trái / phải.
MichaelHouse

@ Byte56 Bạn đang hiểu sai những gì tôi nói. Tôi đang nói nước dâng lên khi áp suất trong khối bạn đang phân tích quá cao so với áp suất từ ​​phía trên, không phải là áp lực từ phía trên quá lớn!
Loren Pechtel

OK, vì vậy hãy để tôi nói lại những gì bạn nói để tôi hiểu: "nước dâng lên khi áp suất trong khối bạn đang phân tích lớn hơn áp lực được áp dụng từ phía trên". Đúng không?
MichaelHouse

@ Byte56 Có. Áp lực trong khối phải là trọng lượng của nước bên trên nó hoặc được đặt sang một bên khi chúng ta có một bề mặt rắn ở đâu đó phía trên. Quá ít áp lực lên nó có nghĩa là không có đủ nước ở trên, di chuyển nước lên.
Loren Pechtel

Tôi chỉ muốn nói thêm rằng, nếu bạn đang xử lý nước chảy thì điều này sẽ không đủ và bạn cũng phải xem xét quán tính nếu không nước sẽ chảy quá chậm.
khối

1

Bạn có thể thêm một quy tắc cố gắng đi sang trái hoặc phải (xuyên qua các bức tường) với các ô cho đến khi bạn tìm thấy một điểm miễn phí, bắt đầu với các lớp ở phía dưới. Nếu bạn không thể tìm thấy, thì gạch vẫn ở vị trí hiện tại. Nếu bạn tìm thấy, thì các quy tắc khác sẽ đảm bảo thay thế gạch di chuyển (nếu cần).


Đây cũng là một ý tưởng tốt, không chắc nó sẽ hoạt động trong mọi trường hợp nhưng tôi sẽ xem xét nó.
Cyral

Được! Hãy cho tôi biết liệu nó đã làm việc hay không. liên quan
almanegra

Tôi sẽ, chỉ là một chút bận rộn gần đây.
Cyral

-2

Tại sao bạn không thể định nghĩa một loại khối khác hoạt động như một áp lực bất động? Do đó, khi bạn sử dụng cách di chuyển bình thường các khối nước và kiểm tra xem nó có thể di chuyển lên không, nó không thể.

Thậm chí tốt hơn là thêm một định nghĩa khác cho các khối cho phép người dùng nhập lượng áp suất trên mỗi khối, tăng áp suất theo lượng khối nước thêm vào nó.


1
"ở đây khi bạn sử dụng cách di chuyển bình thường các khối nước và kiểm tra xem nó có thể di chuyển lên không, nó không thể." Phải ... Nó đã không thể. Đó là vấn đề, tôi không tìm cách để làm cho nó giữ nguyên.
Cyral
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.