그리드 기반 액체 시뮬레이션에서 압력 시뮬레이션


30

내 XNA 게임에 2D 그리드 기반의 물 시스템이 있으며, 셀룰러 오토마타를 사용하여 떨어지는 물과 확산을 시뮬레이션하는 방법이 있습니다.

경사면을 흐르는 물의 예 :

물 물리

각 타일은 0에서 255 개의 액체 값을 바이트 단위로 저장할 수 있습니다. 나는 floats이전에 사용 했던 오래된 물 시스템을 사용하지 않지만 합병증을 추가하고 성능이 저하되었습니다.

각 워터 타일은 간단한 규칙 세트로 자체 업데이트됩니다.

  1. 아래 타일에 공간이 있으면 가능한 한 현재 타일에서 아래쪽 타일로 이동하십시오 (Flow Down).
  2. 2면이 같지 않고 0이 아니고 둘 다 통과 가능하면 3 타일 (왼쪽 + 현재 + 오른쪽)의 합을 가져 와서 3을 나눕니다. 중간 (현재) 타일에 나머지를 남겨 둡니다.
  3. 위의 규칙이 합계로 2의 숫자를 주면 타일을 양면으로 나눠야합니다 (1, 0, 1)
  4. 규칙 2가 1을 합계로한다면
  5. 규칙 2가 실패하면 한쪽이 통과 가능하고 다른 쪽이 통과 할 수 없는지 확인해야합니다. 그것이 사실이라면, 우리는 현재 타일을 2 개의 타일에 대해 반으로 나눕니다.

압력을 포함하도록이 논리를 어떻게 확장 할 수 있습니까? 압력은 액체가 "U- 굽힘"위로 올라가서 에어 포켓을 채 웁니다.

이것이 현재 실패하는 예 :

압력 실패

물은 U- 벤드의 양쪽에서 흐르고 균등해야합니다. 또한 워터 블록이 얼마나 멀리 떨어져 있는지, 그리고 압력이 얼마나 많은지 알아내는 방법을 만들었습니다. 이제이 숫자를 가져 와서 압력을 균등화하기 위해 다른 영역에 적용 할 수 있어야합니다.


문제는 셀룰러 오토마타를 유지하기가 어렵다는 것입니다. 이제 각 블록은 그 옆에있는 것 이상을 알아야합니다. 3D로 원하는 시스템과 유사한 시스템을 만들었습니다. 꽤 복잡한 시스템이지만 2D에서 더 잘 할 수 있다고 생각합니다.
MichaelHouse

@ Byte56 글쎄, 우리는 합리적인 속도로 계속 작동 할 수 있다면 셀룰러 오토마타 일 필요 는 없다 .
Cyral

3
오늘 저녁 시간이되면 정식 답변을 드리겠습니다. 그러나 간단히 말해서 본질적으로 물에 대한 길 찾기를 만들었습니다. 블록은 가야할 압력이 적은 곳을 찾고 싶어합니다. 그들은 물이 적은 곳 (물 옆의 공기 포함)을 찾는 다른 물을 통해 길을 찾습니다. 대부분의 사용 사례를 해결합니다.
MichaelHouse

고마워요. 나는 Dwarf Fortress의 제조사와의 인터뷰를 읽었으며 그는 이것을 믿었지만 그가 겪었던 문제 중 일부를 극복하는 방법을 확신하지 못했기 때문에 실제로 시도하지 않았습니다.
Cyral

1
공기 압력을 추가하면 두 개의 공기 주머니 예제가 완전히 유효합니다 (닫힌 압력 챔버). 255 바이트를 사용하지 않고 0-255 값을 사용한다고 가정합니다 . 어쨌든 전체 범위를 그런 식으로 사용하고 싶지 않을 것입니다. 나는 아마도 압력의 '1 분위기'에 대해 흠, 0-15로 제한 할 것입니다 ( '네거티브'압력과 같은 것은 없습니까?) 고압을 허용하면 현재 부족합니다. 심에 '공기'블록을 포함 시키면 물 블록의 자연적으로 더 높은 '무게'가 굽힘 주위로 흐를 수 있습니다.
Clockwork-Muse

답변:


6

나는 이것을 한 적이 없다. 이것들은 도움이 될만한 아이디어 일뿐입니다. 아니면 완전히 가짜 일 수도 있습니다. Terraria 이후 로이 문제를 해결하고 싶었지만 현재는 그런 게임을하고 있지 않습니다.

내가 생각한 방법은 각 지표면 워터 블록 (물이 있고 그 위에 워터 블록이없는 블록)에 세계 바닥에서 높이와 같은 초기 압력 값 (또는 그 기능)을 제공하는 것입니다. 통과 할 수없는 타일의 암시 적 압력 값은 MAX_PRESSURE(255)이며, 야외 타일의 경우 MIN_PRESSURE(0)입니다.

그런 다음, 압력이 높은 타일에서 셀틱 오토마타 스타일의 각 진드기 동안 압력이 낮은 타일로 압력이 위 / 아래 / 옆으로 퍼집니다. 이퀄라이저를 정확히 무엇인지 파악하려면 실제 시뮬레이션을 얻어야합니다. 블록의 압력은 암시 적 압력과 균등화 된 주변의 "초과"압력과 같아야합니다 (따라서 암시 적 압력이 아닌이 초과 압력 만 저장하면됩니다).

표면 타일이 암시 적 높이 기반 압력보다 큰 압력을 갖고 위 타일에 물을위한 여유 공간이 있으면 물의 작은 부분이 위로 이동합니다. 타일 ​​둘 다 예상보다 낮은 압력을 갖는 공간이있는 경우에만 물이 흐릅니다.

이것은 압력 값이 실제 압력보다 높은 높이를 나타내지 만 (높은 타일이 높은 "압력"을 가질 것으로 예상되기 때문에) 물이 더 깊을수록 더 많은 압력을가한다는 생각을 대략 시뮬레이션합니다. 이것은 압력을 h방정식 의 용어 와 비슷하게 만들지 만 실제로는 아닙니다.

P' = P + qgh

결과적으로 수압이 수심보다 높아지면 위로 올라갑니다. 폐쇄 시스템의 수위는 시간이 지남에 따라 모든 높이의 압력을 균일하게합니다.

어떻게 처리해야하는지 또는 생성 될 "기포"를 처리해야하는지 확실하지 않습니다 (비 표면 타일이 물을 위로 밀면 물이 가득 차지 않는 경우). 또한 여전히 수압 루프가 한쪽에서 불균형 한 다음 다른 쪽에서 앞뒤로 불균일 한 것을 피하는 방법을 여전히 확신하지 못합니다.


20

3D에서 사용하는 것과 비슷한 시스템을 만들었습니다. 여기에 간단한 메커니즘을 보여주는 짧은 비디오 와 블로그 게시물이 있습니다 .

다음은 보이지 않는 벽 뒤의 압력 역학으로 만든 작은 GIF입니다 (고속 재생).

여기에 이미지 설명을 입력하십시오

시스템의 일부 기능에 대한 아이디어를 제공하기 위해 관련된 데이터를 설명하겠습니다. 현재 시스템에서 각 물 블록은 2 바이트로 다음을 포함합니다.

//Data2                          Data
//______________________________  _____________________________________
//|0    |0      |000   |000    |  |0        |0       |000      |000   |
//|Extra|FlowOut|Active|Largest|  |HasSource|IsSource|Direction|Height|
//------------------------------  -------------------------------------
  • Height 입방체의 물의 양은 압력과 비슷하지만 내 시스템에는 8 레벨이 있습니다.
  • Direction흐름이 진행되는 방향입니다. 다음에 물이 어디로 흐를지를 결정할 때, 현재 방향으로 계속 이어질 가능성이 높습니다. 또한 필요할 때 플로우를 소스 큐브까지 신속하게 역 추적하는 데 사용됩니다.
  • IsSource이 큐브가 소스 큐브인지 여부를 나타냅니다. 즉, 물이 부족하지 않습니다. 강, 샘 등의 소스에 사용됩니다. 위의 gif에서 왼쪽의 큐브는 소스 큐브입니다.
  • HasSource이 큐브가 소스 큐브에 연결되어 있는지 나타냅니다. 소스에 연결되면 큐브는 다른 "전체"비 소스 큐브를 찾기 전에 더 많은 물을 얻기 위해 소스를 두 드리려고 시도합니다.
  • Largest이 큐브와 해당 소스 큐브 사이의 최대 흐름이 무엇인지이 큐브에 알려줍니다. 이것은 물이 좁은 간격을 통해 흐르면이 큐브로의 흐름을 제한합니다.
  • Active카운터입니다. 이 큐브가 큐브를 통과하거나 큐브를 통과하는 활성 흐름을 가지면 활성이 증가합니다. 그렇지 않으면 활성이 임의로 감소합니다. 활성이 0에 도달하면 (활성이 아님)이 큐브에서 물의 양이 감소하기 시작합니다. 이런 종류의 증발이나 땅에 몸을 담그는 것과 같은 작용을합니다. ( 흐름이 있으면 썰물이 있어야합니다! )
  • FlowOut이 큐브가 세계 가장자리에있는 큐브에 연결되어 있는지 나타냅니다. 세상의 가장자리로가는 길이 만들어지면 물은 다른 길보다 그 길을 선택하는 경향이 있습니다.
  • Extra 나중에 사용하기위한 추가 비트입니다.

이제 데이터를 알았으므로 알고리즘에 대한 높은 수준의 개요를 살펴 보겠습니다. 시스템의 기본 아이디어는 아래로 흐르는 것을 우선 순위 화하는 것입니다. 비디오에서 설명 하듯이, 나는 아래에서 위로 일합니다. 각 층의 물은 y 축에서 한 번에 한 수준 씩 처리됩니다. 각 레벨의 큐브는 무작위로 처리되며 각 큐브는 각 반복마다 소스에서 물을 끌어 오려고 시도합니다.

플로우 큐브는 소스 큐브 또는 상위가없는 플로우 큐브에 도달 할 때까지 플로우 방향을 따라 소스에서 물을 끌어옵니다. 각 큐브에 흐름 방향을 저장하면 연결된 목록을 순회하는 것처럼 소스 경로를 쉽게 따라갈 수 있습니다.

알고리즘의 의사 코드는 다음과 같습니다.

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()

흐름을 확장하기위한 기본 규칙

  1. 아래 큐브에 물이 적 으면 흘러 내립니다.
  2. 같은 수준의 인접한 큐브에 물이 적 으면 측면으로 흐릅니다.
  3. 위의 큐브에 물이 적고 소스 큐브가 위의 큐브보다 높으면 위로 올라갑니다.

알아요, 그것은 꽤 높은 수준입니다. 그러나 점점없이 더 자세히 들어가 어려운 방법을 자세히.

이 시스템은 꽤 잘 작동합니다. 구덩이를 쉽게 채울 수있어 흘러 넘치게됩니다. 위의 GIF에서 볼 수 있듯이 U 자형 터널을 채울 수 있습니다. 그러나 내가 말했듯이 시스템이 불완전하고 아직 모든 것을 해결하지 못했습니다. 나는 오랫동안 흐름 시스템에서 일하지 않았습니다 (알파에 필요하지 않다고 결정하고 보류했습니다). 그러나 내가 어디에서 처리 할 때 다루어야 할 문제는 다음과 같습니다.

  • 수영장 . 큰 물웅덩이를 얻을 때, 아이에서 부모로가는 포인터는 임의의 방향으로 흐르기 위해 임의의 큐브가 선택되었다는 미친 혼란과 같습니다. 바보 같은 끈으로 욕조를 채우는 것처럼. 욕조를 비우고 싶을 때 바보 같은 줄의 경로를 따라 다시 소스로 가야합니까? 아니면 가장 가까운 것을 가져 가야합니까? 따라서 큐브가 큰 풀에있는 상황에서는 부모 흐름을 무시하고 위에있는 모든 것에서 가져와야합니다. 나는 이것에 대한 기본 작업 코드를 생각해 냈지만 결코 만족할 수있는 우아한 해결책을 찾지 못했습니다.

  • 여러 부모 . 자식 스트림은 둘 이상의 부모 스트림에 의해 쉽게 공급 될 수 있습니다. 그러나 한 부모에게 포인터를 가진 아이는 그것을 허용하지 않을 것입니다. 가능한 각 부모 방향에 대해 비트를 허용하기에 충분한 비트를 사용하여이를 해결할 수 있습니다. 부모가 여러 명인 경우 경로를 임의로 선택하도록 알고리즘을 변경했을 수 있습니다. 그러나 다른 문제가 무엇인지 테스트하고 확인하기 위해 결코 그것을 찾지 못했습니다.


감사! 매우 유익한! 나는 이것을 빨리 시작하고 모든 것이 잘되면 그것을 받아 들일 것이다.
Cyral

확실한 것. 나는 당신의 시스템의 하이브리드를 상상하고 이것이 2D 세계에 매우 효과적이라고 생각합니다. 세부 사항을 논의하려면 채팅 (@ byte56과)으로 나를 핑하십시오.
MichaelHouse

좋아, 내가 이것을 시도 할 기회를 얻기 전에 하루 정도 될 수 있습니다.
Cyral

3
알겠습니다 아마 몇 달 동안 그것을 해결하고 재 해결하는 데 보냈습니다. 나는 잠시 동안 주위에있을 것이다 :)
MichaelHouse

2

나는 Sean과 동의하지만 조금 다르게 할 것입니다.

블록은 자체 무게와 동일한 압력을 생성하고 (물에 얼마나 많은 양의 물이 있는지) 블록을 아래 및 옆의 블록에 적용합니다. 나는 그것이 세계에서 그 위치가 관련이있는 이유를 보지 못한다.

각 진드기에서 물을 고압에서 저압으로 옮기 되 균등화에 필요한 물의 일부만 움직입니다. 블록의 압력이 너무 커서 사각형에 가해지는 압력에 비해 물을 밀어 올릴 수도 있습니다.

수압이 한 방향으로 너무 멀리 흐른 후 수정해야하는 고리가 생길 것입니다. 그러나 틱당 전체 양의 물을 움직이지 않기 때문에 이러한 현상이 완화됩니다. 실제로 물이 홍수처럼 쏟아져서 서지 효과를 볼 수 있기 때문에 실제로 좋은 일이라고 생각합니다.


위에서 가해지는 압력이 너무 클 때 물이 올라가면 저압 블록으로 이동하지 않습니다. 위의 압력이 너무 크려면 아래 블록보다 커야합니다. 또한 압력은 상하 좌우로 움직여야합니다.
MichaelHouse

@ Byte56 당신은 내가 말한 것을 잘못 해석하고 있습니다. 나는 당신이 분석하는 블록의 압력이 위의 압력이 너무 높을 때 물이 올라가고 있다고 말하고 있습니다.
Loren Pechtel

자, 당신이 말한 것을 바꿔서 말하겠습니다. "분석하는 블록 의 압력이 위에서 가해지는 압력 보다 클 때 물이 올라갑니다 ." 그 맞습니까?
MichaelHouse

@ Byte56 예. 블록의 압력은 그 위의 물의 무게이거나 우리가 어딘가에 단단한 표면이있을 때 옆으로 가해 져야합니다. 압력이 너무 낮 으면 물이 부족하여 물을 위로 올리십시오.
Loren Pechtel

나는 또한 흐르는 물을 다룰 때 이것으로 충분하지 않으며 관성을 고려해야하거나 물이 너무 느리게 움직일 것이라고 덧붙이고 싶습니다.
큐브

1

아래쪽의 레이어부터 시작하여 자유 지점을 찾을 때까지 타일을 사용하여 왼쪽 또는 오른쪽으로 벽을 통과하는 규칙을 추가 할 수 있습니다. 찾을 수 없으면 타일은 현재 위치에 유지됩니다. 찾으면 다른 규칙에 따라 이동 한 타일을 교체해야합니다 (필요한 경우).


이것은 모든 경우에 효과가 있는지 확실하지 않지만 고려할 것입니다.
Cyral

승인! 작동 여부를 알려주세요. 안부
almanegra

나는 최근에 조금 바빴습니다.
Cyral

-2

움직일 수없는 양의 압력으로 작용하는 다른 유형의 블록을 정의 할 수없는 이유는 무엇입니까? 따라서 일반적으로 워터 블록을 이동하고 위로 올라갈 수 있는지 여부를 확인하는 방법을 사용하면 불가능합니다.

사용자가 블록 당 압력의 양을 입력 할 수있는 블록에 다른 정의를 추가하여 물 블록의 양에 따라 압력을 증가시키는 것이 더 좋습니다.


1
"따라서 일반적으로 워터 블럭을 옮기고 위로 올라갈 수 있는지 확인하는 방법을 사용할 때는 불가능합니다." 응 ... 벌써 못해 문제는, 나는 그것을 동일하게 유지하는 방법을 찾고 있지 않습니다.
Cyral
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.