중력을 어떻게 구현할 수 있습니까?


답변:


52

다른 사람들이 의견에서 언급했듯이 tenpn의 답변에 설명 된 기본 오일러 통합 방법 에는 몇 가지 문제가 있습니다.

  • 일정한 중력 하에서 탄도 점프와 같은 간단한 동작의 경우에도 체계적인 오류가 발생합니다.

  • 오류는 타임 스텝에 따라 다릅니다. 즉, 타임 스텝을 변경하면 게임이 가변 타임 스텝을 사용하는 경우 플레이어가 알 수있는 체계적인 방식으로 오브젝트 궤적을 변경합니다. 물리 시간 단계가 고정 된 게임의 경우에도 개발 중 시간 단계를 변경하면 주어진 힘으로 발사 된 물체가 비행하는 거리와 같이 게임 물리에 현저한 영향을 미쳐 이전에 설계된 수준을 파괴 할 수 있습니다.

  • 기본 물리학이 필요하더라도 에너지를 절약하지 못합니다. 특히 꾸준히 진동 해야하는 물체 (예 : 진자, 샘, 궤도 행성 등)는 전체 시스템이 터질 때까지 꾸준히 에너지를 축적 할 수 있습니다.

다행스럽게도 Euler 통합을 거의 단순하지만 이러한 문제가없는 것, 특히 도약 통합 또는 밀접하게 관련된 속도 Verlet 방법 과 같은 2 차 대칭 적분기로 대체하는 것은 어렵지 않습니다 . 특히 기본 오일러 통합은 속도와 위치를 다음과 같이 업데이트합니다.

가속도 = 힘 (시간, 위치) / 질량;
시간 + = 타임 스텝;
위치 + = 타임 스텝 * 속도;
속도 + = 타임 스텝 * 가속;

속도 Verlet 방법은 다음과 같이합니다.

가속도 = 힘 (시간, 위치) / 질량;
시간 + = 타임 스텝;
위치 + = 타임 스텝 * ( 속도 + 타임 스텝 * 가속 / 2) ;
newAcceleration = 힘 (시간, 위치) / 질량; 
속도 + = 타임 스텝 * ( 가속 + 새로운 가속 ) / 2 ;

상호 작용하는 객체가 여러 개인 경우 힘을 다시 계산하고 속도를 업데이트하기 전에 모든 위치를 업데이트해야합니다. 새 가속을 저장하고 다음 타임 스텝에서 위치를 업데이트하는 데 사용할 수 force()있으므로 Euler 메서드와 마찬가지로 호출 횟수를 타임 스텝 당 1 개 (개체 당)로 줄입니다.

또한 가속도가 일반적으로 일정하면 (탄도 점프 중 중력과 같이) 위의 내용을 간단히 단순화 할 수 있습니다.

시간 + = 타임 스텝;
위치 + = 타임 스텝 * ( 속도 + 타임 스텝 * 가속 / 2) ;
속도 + = 타임 스텝 * 가속;

여기서 굵은 체로 표시된 추가 용어는 기본 오일러 통합에 비해 유일한 변경입니다.

오일러 통합과 비교할 때 속도 Verlet 및 leapfrog 메소드에는 몇 가지 멋진 특성이 있습니다.

  • 일정한 가속을 위해 정확한 결과를 얻습니다 (어쨌든 부동 소수점 반올림 오차까지). 이는 시간 간격이 변경 되어도 탄도 점프 궤적이 동일하게 유지됨을 의미합니다.

  • 이들은 2 차 적분기이므로, 다양한 가속도를 사용하더라도 평균 적분 오차는 타임 스텝의 제곱에 비례합니다. 이것은 정확성을 떨어 뜨리지 않고 더 큰 타임 스텝을 허용합니다.

  • 그것들은 증상이 있는데 , 그것은 기본 물리학이 (적어도 시간 단계가 일정하다면) 에너지를 보존한다는 것을 의미합니다. 특히 이것은 행성이 자발적으로 궤도에서 날아가거나 스프링으로 서로 붙어있는 물체와 같은 것들이 점점 터져 나올 때까지 점점 더 많이 흔들리지 않을 것임을 의미합니다.

그러나 속도 Verlet / 도약 방법은 확실히 같은 대안보다 훨씬 간단 거의 간단하고 빠른 기본 오일러 통합으로, 그리고 4 차 Runge-Kutta 통합 일반적으로 아주 좋은 통합하면서 사교 속성을 부족하고 필요, ( 사 개 평가 의 force()시간 스텝 당 작용). 따라서 한 플랫폼에서 다른 플랫폼으로 점프하는 것만 큼 간단하더라도 모든 종류의 게임 물리 코드를 작성하는 사람에게는 강력히 권장합니다.


편집 : 속도 Verlet 방법의 공식 파생은 힘이 속도와 무관 한 경우에만 유효하지만 실제로 유체 드래그 와 같은 속도 종속 힘으로도 잘 사용할 수 있습니다 . 최상의 결과를 얻으려면 다음 force()과 같이 두 번째 호출에 대한 새 속도를 추정하기 위해 초기 가속 값을 사용해야합니다 .

가속도 = 힘 (시간, 위치, 속도) / 질량;
시간 + = 타임 스텝;
위치 + = 타임 스텝 * ( 속도 + 타임 스텝 * 가속 / 2) ;
속도 + = 타임 스텝 * 가속;
newAcceleration = 힘 (시간, 위치, 속도) / 질량; 
속도 + = 타임 스텝 * (newAcceleration-가속) / 2 ;

속도 Verlet 방법의 특정 변형이 특정 이름을 가지고 있는지 확실하지 않지만 테스트 한 결과 아주 잘 작동하는 것 같습니다. 그것은 오차 Runge-Kutta만큼 정확하지는 않지만 (2 차 방법에서 기대할 수 있듯이) 중간 속도 추정이없는 오일러 또는 순진한 속도 Verlet보다 훨씬 우수하며 여전히 정상의 대칭 특성을 유지합니다 보수적이며 속도에 의존하지 않는 힘을위한 속도 Verlet.

편집 2 : Groot & Warren ( J. Chem. Phys. 1997) 과 같은 매우 유사한 알고리즘이 설명되어 있지만 라인 사이를 읽으면 newAcceleration추정 속도를 사용하여 계산 된 값 을 저장하여 추가 속도에 대한 정확도를 희생 한 것처럼 보입니다. acceleration다음 타임 스텝 으로 다시 사용합니다 . 또한 초기 속도 추정값 과 곱한 0 ≤ λ ≤ 1 파라미터를 도입합니다 acceleration. 어떤 이유로, 그들은 추천 λ 모든에도 불구하고, = 0.5를 테스트가 제안 λ를= 1 (효과적으로 위에서 사용하는 것)은 가속 재사용 유무에 관계없이 잘 작동합니다. 아마도 그들의 힘에는 확률 론적 브라운 운동 성분이 포함되어 있다는 사실과 관련이있을 것입니다.


Velocity Verlet 멋지지만 속도에 따른 전위를 가질 수 없으므로 마찰을 구현할 수 없습니다. 나는 Runge-Kutta 2가 내 목적에 가장 적합하다고 생각합니다.)
Pizzirani Leonardo

1
@PizziraniLeonardo : 속도에 의존하는 힘에도 속도 Verlet을 사용할 수 있습니다. 위의 편집 내용을 참조하십시오.
Ilmari Karonen

1
문헌은 Velocity Verlet에 대한이 해석에 다른 이름을 부여하지 않습니다. 이 백서 fire.nist.gov/bfrlpubs/build99/PDF/b99014.pdf에 명시된 바와 같이 예측 자-수정 자 전략에 의존합니다 .
teodron

3
@ Unit978 : 게임, 특히 구현 한 물리 모델에 따라 다릅니다. force(time, position, velocity)그냥 "에서 물체에 작용하는 힘에 대한 속기 위의 내 대답 position에 이동 velocitytime". 일반적으로 힘은 물체가 자유 낙하 상태인지 또는 단단한 표면에 앉아 있는지, 근처의 다른 물체가 물체에 힘을가하는지 여부, 물체가 표면 위로 얼마나 빨리 움직이는 지 (마찰) 및 / 또는 액체를 통과하는 것과 같은 것에 의존합니다. 또는 가스 (끌기) 등
Ilmari Karonen

1
이것은 훌륭한 답변이지만 고정 시간 단계에 대해 이야기하지 않고는 불완전합니다 ( gafferongames.com/game-physics/fix-your-timestep ). 별도의 답변을 추가하고 싶지만 대부분의 사람들은 허용 된 답변에 멈 춥니 다. 특히 여기에서와 같이 투표율이 가장 높은 경우에는 특히 그렇습니다. 나는 이것을 강화함으로써 공동체가 더 잘 봉사한다고 생각합니다.
Jibb Smart

13

게임의 모든 업데이트 루프는 다음과 같이하십시오 :

if (collidingBelow())
    gravity = 0;
else gravity = [insert gravity value here];

velocity.y += gravity;

예를 들어, 플랫 포머에서 점프 중력이 활성화되면 (collidingBelow는 바로 아래에 접지가 있는지 여부를 알려줍니다) 접지에 도달하면 비활성화됩니다.

이 외에도 점프를 구현하려면 다음을 수행하십시오.

if (pressingJumpButton() && collidingBelow())
    velocity.y = [insert jump speed here]; // the jump speed should be negative

그리고 분명히 분명히 업데이트 루프에서 위치를 업데이트해야합니다.

position += velocity;

6
무슨 소리 야? 자신의 중력 값을 선택하면 위치뿐만 아니라 속도가 변경되므로 자연스럽게 보입니다.
Pecant

1
나는 중력을 끄는 것을 싫어합니다. 중력이 일정해야한다고 생각합니다. 변해야 할 것은 당신의 점프 능력입니다.
ultifinitus

2
도움이된다면 실제로는 '중력'이 아니라 '떨어지는'것으로 생각하십시오. 전체 기능은 물체가 중력 으로 인해 떨어지는 지 여부를 제어합니다 . 중력 자체는 [중력 값을 여기에 삽입]과 동일하게 존재합니다. 그런 의미에서, 중력 일정합니다. 물체가 공중에 있지 않으면 아무것도 사용하지 않습니다.
Jason Pineo

2
이 코드는 프레임 속도에 따라 다르지만 좋지는 않지만 지속적으로 업데이트하면 웃고 있습니다.
tenpn

1
-1 죄송합니다. 의미가없는 속도와 중력 또는 위치와 속도 추가. 당신이하고있는 지름길을 이해하지만 잘못되었습니다. 나는 내가 찾은 가장 큰 단서로 그 일을하는 학생이나 연수생 또는 동료를 때릴 것입니다. 단위의 일관성은 중요합니다.
sam hocevar

8

적절한 프레임 속도 독립적 * 뉴턴 물리학 통합 :

Vector forces = 0.0f;

// gravity
forces += down * m_gravityConstant; // 9.8m/s/s on earth

// left/right movement
forces += right * m_movementConstant * controlInput; // where input is scaled -1..1

// add other forces in for taste - usual suspects include air resistence
// proportional to the square of velocity, against the direction of movement. 
// this has the effect of capping max speed.

Vector acceleration = forces / m_massConstant; 
m_velocity += acceleration * timeStep;
m_position += velocity * timeStep;

중력 조정 상수, 이동 상수 및 질량 직관적 인 것이며 기분이 좋아지는 데 시간이 걸릴 수 있습니다.

힘 벡터를 쉽게 확장하여 새로운 게임 플레이를 추가 할 수 있습니다. 예를 들어 근처 폭발이나 블랙홀을 향해 힘을 추가하십시오.

* 편집 :이 결과는 시간이 지남에 따라 잘못되지만 충실도 또는 적성에 "충분히 만족"할 수 있습니다. 자세한 내용은 http://lol.zoy.org/blog/2011/12/14/understanding-motion-in-games 링크를 참조하십시오 .


4
오일러 통합을 사용하지 마십시오. 글렌 피들러 (Glenn Fiedler)의이 기사를 참조 하면 문제와 해결 방법을 설명 할 수 있습니다. :)
Martin Sojka

1
Euler가 시간이 지남에 따라 어떻게 부 정확한지 이해하지만 실제로 중요하지 않은 시나리오가 있다고 생각합니다. 규칙이 모든 사람에게 일관되고 "느끼는"느낌이 있으면 괜찮습니다. 피직스에 대해 배우는 것만으로도 기억하기가 매우 쉽습니다.
tenpn

... 좋은 링크. ;)
tenpn

4
당신은 단순히 대체하여 오일러 통합 대부분의 문제를 해결할 수 position += velocity * timestep위에서 position += (velocity - acceleration * timestep / 2) * timestep(여기서 velocity - acceleration * timestep / 2단순히 과거와 속도의 평균). 특히,이 적분기는 가속도가 일정한 경우 일반적으로 중력에 대한 것이므로 정확한 결과를 제공합니다. 다양한 가속에서 정확도를 높이기 위해 속도 업데이트에 유사한 보정을 추가하여 속도 Verlet 통합 을 얻을 수 있습니다.
Ilmari Karonen

당신의 주장은 의미가 있으며, 부정확성은 종종 큰 문제가 아닙니다. 그러나 이것이 "프레임 레이트 독립"이 아니기 때문에 "적절한 프레임 레이트 독립"통합이라고 주장해서는 안됩니다.
sam hocevar

3

약간 더 큰 규모로 중력을 구현하려면 각 루프마다 다음과 같은 계산을 사용할 수 있습니다.

for each object in the scene
  for each other_object in the scene not equal to object
    if object.mass * other_object.mass / object.distanceSquaredBetweenCenterOfMasses(other_object) < epsilon
      abort the calculation for this pair
    if object.mass is much, much bigger than other_object.mass
      abort the calculation for this pair
    force = gravitational_constant
            * object.mass * other_object.mass
            / object.distanceSquaredBetweenCenterOfMasses(other_object)
    object.addForceAtCenterOfMass(force * object.normalizedDirectionalVectorTo(other_object))
  end for loop
end for loop

더 큰 (은하계) 스케일의 경우, 중력만으로는 "실제"모션을 생성하기에 충분하지 않습니다. 스타 시스템의 상호 작용은 유체 역학에 대한 Navier-Stokes 방정식에 의해 결정된 중요하고 매우 눈에 띄는 범위이므로 유한 한 빛의 속도와 중력도 염두에 두어야합니다.


1

Ilmari Karonen이 제공 한 코드는 거의 정확하지만 약간의 결함이 있습니다. 실제로 틱당 2 회 가속도를 계산하는데, 이는 교과서 방정식을 따르지 않습니다.

acceleration = force(time, position) / mass; // Here
time += timestep;
position += timestep * (velocity + timestep * acceleration / 2);
newAcceleration = force(time, position) / mass;
velocity += timestep * (acceleration + newAcceleration) / 2;

다음 모드가 정확합니다.

time += timestep;
position += timestep * (velocity + timestep * acceleration / 2);
oldAcceletation = acceleration; // Store it
acceleration = force(time, position) / mass;
velocity += timestep * (acceleration + oldAcceleration) / 2;

건배'


가속은 속도에 따라
super

-4

Pecant의 답변은 프레임 시간을 무시하여 물리 행동을 때때로 다르게 만듭니다.

아주 간단한 게임을 만들려면 작은 물리 엔진을 만들어 움직이는 물체마다 질량과 모든 종류의 물리 매개 변수를 할당하고 충돌 감지를 수행 한 다음 프레임마다 위치와 속도를 업데이트하십시오. 이 진행을 가속화하려면 충돌 메시를 단순화하고 충돌 감지 호출을 줄이는 등의 작업이 필요합니다. 대부분의 경우 이는 고통스러운 일입니다.

physix, ODE 및 bullet과 같은 물리 엔진을 사용하는 것이 좋습니다. 그들 중 하나는 당신을 위해 충분히 안정적이고 효율적입니다.

http://www.nvidia.com/object/physx_new.html

http://bulletphysics.org/wordpress/


4
-1 질문에 대답하지 않는 도움이되지 않는 응답입니다.
doppelgreener

4
글쎄, 시간에 맞게 조정하려면 마지막 update ()에서 경과 시간으로 속도를 조정할 수 있습니다.
피 칸트
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.