>
Game Develop/Physics

2D물리엔진을 만드는 방법 3편 번역

http://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-friction-scene-and-jump-table--gamedev-7756

원본글은 위 링크


밑에 설명에도 나오지만 여기서 나오는 접선벡터는(탄젠트 벡터) 3d모델이라고 생각하면 폴리곤과 평행한 방향을 나타내는 거라고 생각하면됨(노멀과 수직)


Tangent(접선) Binormal(종법선) Normal (법선)를 생각하면 될듯 


------------------------------------------------------------------------------------



In the first two tutorials in this series, I covered the topics of Impulse Resolution and Core Architecture. Now it's time to add on some of the final touches to our 2D, impulse-based physics engine.

The topics we'll look at in this article are:

(다룰 항목들)

  • 마찰(Friction)
  • 신(Scene)
  • 충돌 점프 테이블(Collision Jump Table)

I highly recommended reading up on the previous two articles in the series before attempting to tackle this one. Some key information in the previous articles is built upon within this article.

Note: Although this tutorial is written using C++, you should be able to use the same techniques and concepts in almost any game development environment. <iframe src="http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html" style="display: none; visibility: hidden;"></iframe>


 

Here's a quick demo of what we're working towards in this part:


 

Friction is a part of collision resolution. Friction always applies a force upon objects in the direction opposite to the motion in which they are to travel.

(마찰은 충돌 검사의 일부이다. 마찰은 항상 물체의 반대방향으로 적용된다.)

In real life, friction is an incredibly complex interaction between different substances, and in order to model it, vast assumptions and approximations are made. These assumptions are implied within the math, and are usually something like "the friction can be approximated by a single vector" - similarly to how rigid body dynamics simulates real life interactions by assuming bodies with uniform density that cannot deform.

(실제 삶에서는 마찰은 믿기 힘들겠지만 다른 물질 사이의 복잡한 상호작용이고 이것을 구현하기 위해 어마한 추정치와 근사치를 만들어야 한다. 이 추정치들은 수학에서 암시되고 보통 "마찰은 하나의 벡터로 추정치가 될수 있다" - 변하지 않는 밀도를 가진 추정된 몸통으로 실생활 강체 다이나믹 시뮬레이션과 방법과 비슷하게 말이다.) 

Take a quick look at the video demo from the first article in this series:

The interactions between the bodies are quite interesting, and the bouncing during collisions feels realistic. However, once the objects land on the solid platform, they just sort of all press away and drift off the edges of the screen. This is due to a lack of friction simulation.

(몸체들 사이의 상호작용은 꽤 인상적이고 바운스하는 것은 실체같이 느껴진다. 하지만 물체가 단단한 플랫폼에 떨어지면 그것들은 단지 모든 힘을 정렬하고 화면의 끝을 끝낸다??. 이것은 마찰 시뮬레이션의 실수이다.)

As you should recall from the first article in this series, a particular value, j, represented the magnitude of an impulse required to separate two objects penetration during a collision. This magnitude can be referred as jnormal or jN as it is used to modify velocity along the collision normal.

(이 시리즈의 첫번째 글을 보면 j 값은 충돌시 두 물체의 침투를 분리시키는데 요구되는 충격의 크기를 나타낸다. 이 크기는 j노멀 또는 jN으로 표기가 가능하며 이것은 충돌 노말에 따라 속도를 수정하는 데 사용한다.)

Incorporating a friction response involves calculating another magnitude, referred to as jtangent or jT. Friction will be modeled as an impulse. This magnitude will modify the velocity of an object along the negative tangent vector of the collision, or in other words along the friction vector. In two dimensions, solving for this friction vector is a solvable problem, but in 3D the problem becomes much more complex.

(또 다른 크기 계산이 포함된 마찰 반응 통합은 j탄젠트 또는 jT라고 표현한다. 마찰은 충격으로 모델링 될 것이다. 그 크기는 충돌의 마이너스 접선 벡터를 따라 물체의 속도를 수정한다고 하거나 또는 다르게 말하면 마찰 벡터를 따라이다. 2차원에서는 이 마찰 벡터를 푸는 것은 해결할 수 있는 문제지만 3D의 문제는 더욱 더 복잡해진다.)

Friction is quite simple, and we can make use of our previous equation for j, except we will replace all instances of the normal n with a tangent vector t.

(마찰은 꽤 간단하고 우리는 이전 j의 식을 노멀 n을 탄젠트 t로 대체하여 구할수 있다.)


Equation 1

j%5Cquad%20%3D%5Cquad%20%5Cfrac%20%7B%20-(1%2Be)((%5Ccombi%20%5E%7B%20B%20%7D%7B%20V%20%7D-%5Ccombi%20%5E%7B%20A%20%7D%7B%20V%20%7D)%5Ccdot%20n)%20%7D%7B%20%5Cfrac%20%7B%201%20%7D%7B%20%5Ccombi%20%5E%7B%20A%20%7D%7B%20mass%20%7D%20%7D%2B%5Cfrac%20%7B%201%20%7D%7B%20%5Ccombi%20%5E%7B%20B%20%7D%7B%20mass%20%7D%20%7D%20%7D%20 


Replace n with t:(n을 t로 바꾸면)


Equation 2 

j%5Cquad%20%3D%5Cquad%20%5Cfrac%20%7B%20-(1%2Be)((%5Ccombi%20%5E%7B%20B%20%7D%7B%20V%20%7D-%5Ccombi%20%5E%7B%20A%20%7D%7B%20V%20%7D)%5Ccdot%20t)%20%7D%7B%20%5Cfrac%20%7B%201%20%7D%7B%20%5Ccombi%20%5E%7B%20A%20%7D%7B%20mass%20%7D%20%7D%2B%5Cfrac%20%7B%201%20%7D%7B%20%5Ccombi%20%5E%7B%20B%20%7D%7B%20mass%20%7D%20%7D%20%7D%20

 

Although only a single instance of n was replaced with t in this equation, once rotations are introduced a few more instances must be replaced besides the single one in the numerator of Equation 2.

(이 식에서 n을 t로 바꾼 것밖에 없지만 식2의 분자를 하나하나 바꾼 몇 개의 인스턴스들에 의해 회전이 알려진다.)

Now the matter of how to calculate t arises. The tangent vector is a vector perpendicular to the collision normal that is facing more towards the normal. This might sound confusing - don't worry, I have a diagram!

(이제 t를 어떻게 계산해야하는지 문제가 발생한다. 그 접선 벡터는 노말을 향한 충돌 노말의 수직이다. 이것은 혼란스럽지만 걱정하지마라 내가 그림을 그렸다!)

Below you can see the tangent vector perpendicular to the normal. The tangent vector can either point to the left or the right. To the left would be "more away" from the relative velocity. However, it is defined as the perpendicular to the normal that is pointing "more towards" the relative velocity.

(너는 접선 벡터와 수직인 노말 벡터를 볼 수 있다. 접선 벡터는 왼쪽 또는 오른쪽 중 하나가 된다. 왼쪽은 상대속도로부터 "더 멀리"가 될 것이다. 하지만 그것은 노멀의 수직으로 상대 속도에서 " 향해"라는 뜻으로 정의된다.)

Vectors of various types within the timeframe of a collision of rigid bodies.
Vectors of various types within the timeframe of a collision of rigid bodies.(강체들의 충돌의 타임 프레임내에서 다양한 벡터들)


As stated briefly earlier, friction will be a vector facing opposite to the tangent vector. This means that the direction in which to apply friction can be directly computed, since the normal vector was found during the collision detection.

Knowing this, the tangent vector is (where n is the collision normal):

(쉽게 말해 마찰은 접선 벡터의 반대방향을 가리킬 것이다. 이것은 충돌 검출동안 찾아낸 노멀벡터로 부터 마찰 방향이 직접 계산되어진다는 것을 의미한다. 접선 벡터는(n은 충돌 노멀을 뜻한다.) 다음과 같다:)


%5Ccombi%20%5E%7B%20R%20%7D%7B%20V%20%7D%3D%5Ccombi%20%5E%7B%20B%20%7D%7B%20V%20%7D-%5Ccombi%20%5E%7B%20A%20%7D%7B%20V%20%7D%20

t%3D%5Ccombi%20%5E%7B%20R%20%7D%7B%20V%20%7D-(%5Ccombi%20%5E%7B%20R%20%7D%7B%20V%20%7D%5Ccdot%20n)*n%20


All that is left to solve for jt, the magnitude of the friction, is to compute the value directly using the equations above. There are some very tricky pieces after this value is computed that will be covered shortly, so this isn't the last thing needed in our collision resolver:

(모두 jt를 구하기 위한 것으로 마찰의 크기는 위의 공식을 이용하여 직접 계산한다. 이것들은 매우 이 값은 매우 까다로운 부분이 있다. 그래서 이것은 우리의 충돌 검출의 마지막에 하는 일이 아니여야 한다.)



The above code follows Equation 2 directly. Again, it's important to realize that the friction vector points in the opposite direction of our tangent vector, and as such we must apply a negative sign when we dot the relative velocity along the tangent to solve for the relative velocity along the tangent vector. This negative sign flips the tangent velocity and suddenly points in the direction in which friction should be approximated as.

(위 코드는 식2를 직접 표현한 것이다. 다시말해서 이것은 우리의 접선 벡터 반대방향인 마찰 벡터 점들을 알아내는데 중요하고 우리는 접선 벡터와 상대 속도의 내적을 구할때 반드시 음의 부호를 붙여야한다. 이 마이너스 부호는 접선 벡터를 뒤집으면 마찰이 근사화된 방향을 가르킬 것이다.)

Coulomb's law is the portion of friction simulation that most programmers have trouble with. I myself had to do quite a bit of studying to figure out the correct way of modeling it. The trick is that Coulomb's law is an inequality.

(쿨롱의 법칙은 대부분의 프로그래머들의 문제를 갖는 마찰 시뮬레이션의 일부이다. 나는 이것을 올바르게 구현하기 위해 꽤 많이 공부해야했다. 그 비결은 쿨롱의 법칙은 불평등하다는 것이다.)


Coulomb friction states:

(쿨롱의 마찰 식:)


Equation 3 

%5Ccombi%20_%7B%20f%20%7D%7B%20F%20%7D%3C%3D%5Cmu%20%5Ccombi%20_%7B%20n%20%7D%7B%20F%20%7D%20


In other words, the force of friction is always less than or equal to the normal force multiplied by some constant μ (whose value depends on the materials of the objects).

(다른 말로 하면 마찰력은 항상 수직항력과 어떤 상수 μ(물체의 재질에 따라 다르다)과의 곱보다 작거나 동등하다.)


The normal force is just our old j magnitude multiplied by the collision normal. So if our solved jt (representing the force of friction) is less than μ times the normal force, then we can use our jt magnitude as friction. If not, then we must use our normal force times μ instead. This "else" case is a form of clamping our friction below some maximum value, the max being the normal force times μ.

(그 수직항력은 단지 우리의 이전 j 크기와 충돌 노멀을 곱한 것이다. 그래서 만약 우리가 구한 jt(마찰력을 나타냄)는 수직항력과 μ의 곱보다 작고 그것이 우리가 jt크기는 마찰의 크기가 될 것이다. 만약 그렇지 않다면 우리는 반드시 수직항력을 μ대신 곱해야한다. 이 "else"의 경우는 최대 값(수직항력과 μ의 곱) 이하로 마찰력을 클램핑한다.)


The whole point of Coulomb's law is to perform this clamping procedure. This clamping turns out to be the most difficult portion of friction simulation for impulse-based resolution to find documentation on anywhere - until now, at least! Most white papers I could find on the subject either skipped friction entirely, or stopped short and implemented improper (or non-existent) clamping procedures. Hopefully by now you have an appreciation for understanding that getting this part right is important.

(쿨룽 법칙의 전체적인 요점은 클램프를 하는 것이다. 이 클램핑 차례는 충격을 토대로한 해결책을 문서 어디에서 찾으려고 했든지간에 마찰 시뮬레이션에서 가장 어려운 부분이다 - 최소한 지금까지는 말이다! 많은 백지들을 나는 마찰 전체를 건너뛰는 주제에서 찾을 수 있거나 또는 잠깐 멈추고 부적절한 구현(또는 존재하지 않는)클램핑 절차를 찾을 수 있다. 이제 이 파트가 중요하다는 것을 이해한 것에 감사하길 바란다.)


Lets just dish out the clamping all in one go before explaining anything. This next code block is the previous code example with the finished clamping procedure and friction impulse application all together:

(끄냥 모든 것을 설명하기 전에 한번에 모든 클램핑을 하자. 이 다음 코드는 이전코드에 클램핑 절차와 마찰 충격 어플리케이션을 모두 끝낸 것이다)



I decided to use this formula to solve for the friction coefficients between two bodies, given a coefficient for each body:

(나는 이 공식을 이용하여 각각의 몸통에 계수를 가져다 주는 두 몸통 사이의 마찰 계수를 구하기로 결정했다.)


Equation 4

Friction%3D%5Csqrt%20%7B%20%5Ccombi%20_%7B%20A%20%7D%5E%7B%202%20%7D%7B%20Friction%20%7D%2B%5Ccombi%20_%7B%20B%20%7D%5E%7B%202%20%7D%7B%20Friction%20%7D%20%7D%20

I actually saw someone else do this in their own physics engine, and I liked the result. An average of the two values would work perfectly fine to get rid of the use of square root. Really, any form of picking the friction coefficient will work; this is just what I prefer. Another option would be to use a lookup table where the type of each body is used as an index into a 2D table.

It is important that the absolute value of jt is used in the comparison, since the comparison is theoretically clamping raw magnitudes below some threshold. Since j is always positive, it must be flipped in order to represent a proper friction vector, in the case dynamic friction is used.

(나는 실제로 누군가가 이것을 그들의 엔진에 넣는 것을 봤고 나는 그 결과가 좋았다. 두값의 평균은 제곱근을 없애 완벽히 찾을 것이다. 실제로 어떤 형태의 마찰 계수가 대입되어도 작동될 것이다. 이것은 단지 준비한 것이다. 다른 옵션은 2D테이블에 인덱스로 사용하는 각각의 몸통 타입의 룩업 테이블(lookup table)을 이용하는 것이다. jt의 완전한 값을 비교에 사용하는 것은 매우 중요하고 비교할 때 이론적인 클램핑된 값은 어떤 한계보다 낮다. j는 항상 양수이기 때문에 동적 마찰이 사용되는 경우에는 반드시 적절한 마찰 벡터를 뒤집어야 한다.)

In the last code snippet static and dynamic friction were introduced without any explanation! I'll dedicate this whole section to explaining the difference between and necessity of these two types of values.

(마지막 코드에 정적 마찰과 동적 마찰이 소개없이 등장하였다! 나는 이 모든 섹션의 설명을 두 종류의 값들의 필요성과 차이의 설명에 헌신할 것이다.)


Something interesting happens with friction: it requires an "energy of activation" in order for objects to start moving when at complete rest. When two objects are resting upon one another in real life, it takes a fair amount of energy to push on one and get it moving. However once you get something sliding it is often easier to keep it sliding from then on.

(마찰에 흥미로운 일이 일어난다 : 완전한 휴식상태에서 물체가 움직이도록 하려면 "활성화 에너지"를 요구한다. 실제 생활에서 두개의 물체 중 또 다른 하나의 물체가 휴식 중 일경우 그 하나를 푸쉬하고 이동시키는데 상당량의 에너지의 에너지의 양을 가져간다. 하지만 일단 당신이 뭔가를 미끄러지게 하면 그것은 보통 그때부터 미끄러지는 것을 유지하기 쉬울 것이다.) 


This is due to how friction works on a microscopic level. Another picture helps here:

(이것은 어떻게 마찰이 이뤄지는지 현미경 수준에서 그린 것이다.(물체의 마찰면을 그린것임))

Microscopic view of what causes energy of activation due to friction.
Microscopic view of what causes energy of activation due to friction.(마찰에 의한 활성화 에너지의 현미경 그림)

 

As you can see, the small deformities between the surfaces are really the major culprit that creates friction in the first place. When one object is at rest on another, microscopic deformities rest between the objects, interlocking. These need to be broken or separated in order for the objects to slide against one another.

(당신도 볼 수 있듯이 그 작은 두 표면사이의 마찰을 만드는 주된 원인은 첫번째 그림이다. 하나의 물체가 또 다른 것의 위에서 정지해 있을때 미세한 표면한 두 오브젝트 사이에서 물려 가만히 있게 한다. 서로의 물체가 미끄러지게 하려면 깨거나 갈라서게 하려면 파손 또는 분리가 필요하다.)


We need a way to model this within our engine. A simple solution is to provide each type of material with two friction values: one for static and one for dynamic.

(우리가 우리의 엔진에 이 모델을 구현할 수 있는 방법이 필요하다. 간단한 해결책은 재질의 각각의 타입을 두 마찰값에 넣는 것이다. 하나는 정적으로 그리고 다른 하나는 동적으로말이다.)


The static friction is used to clamp our jt magnitude. If the solved jt magnitude is low enough (below our threshold), then we can assume the object is at rest, or nearly as rest and use the entire jt as an impulse.

(정적 마찰은 jt의 크기를 클램프하여 사용한다. 만약 jt 크기가 충분히 작으면(어떤 한계값보다 아래) 우리는 그 물체는 정지인 것으로 추측하거나 또는 거의 정지한 상태 그리고 jt를 충격에 따라 사용한다.)


On the flipside, if our solved jt is above the threshold, it can be assumed that the object has already broken the "energy of activation", and in such a situation a lower friction impulse is used, which is represented by a smaller friction coefficient and a slightly different impulse computation.

(반대에서 보면 만약 우리가 구한 jt가 임계치 이상이면 물체가 이미 "활성화 에너지"로 (마찰이)깨졌다는 것을 추측할 수 있고 그런 상황에서는 더 낮은 마찰 충격이 사용되어 작은 마찰 계수 약간 다른 충격 계산으로 표현된다.)




Assuming you did not skip any portion of the Friction section, well done! You have completed the hardest part of this entire series (in my opinion).

(당신이 마찰 섹션을 넘어가지 않았다면 잘했다! 당신은 이 시리즈 중에서 어려운 부분을 끝냈다.(내 생각에는))


The Scene class acts as a container for everything involving a physics simulation scenario. It calls and uses the results of any broad phase, contains all rigid bodies, runs collision checks and calls resolution. It also integrates all live objects. The scene also interfaces with the user (as in the programmer using the physics engine).

(장면(Scene)은 행동하는 모든 것들을 담는 물리 시뮬레이션 시나리오이다. 이것은 어떤 광범위한 단계(broad phase)의 결과를 부르기도 하며 사용하기도 하고 모든 강체들(rigid body)을 포함하고 충돌을 실행하고 모든 함수를 호출한다. 또한 모든 살아있는 물체를 통합한다. 장면(scene)에는 또한 사용자와의 인터페이스가 있다.(프로그래머가 물리엔진에서 사용할 것))


Here is an example of what a scene structure may look like:

(여기 장면(scene) 구조체의 예제가 있다)



There is not anything particularly complex about the Scene class. The idea is to allow the user to add and remove rigid bodies easily. The BodyDef is a structure that holds all information about a rigid body, and can be used to allow the user to insert values as a sort of configuration structure.

(여기에는 장면(scene) 클래스에 대한 어떠한 부분적 결합이 없다. 이것은 사용자가 강체를 쉽게 추가하고 지울 수 있게 한다. BodyDef는 구조체로서 강체(rigidbody)의 모든 정보를 가지고 있고 사용자가 구성된 구조체 값을 삽입 할 수 있다.)

 

The other important function is Step(). This function performs a single round of collision checks, resolution and integration. This should be called from within the timestepping loop outlined in the second article of this series.

(다른 중요한 함수는 Step()이다. 이 함수는 충돌 검사를 한번만 실행하고 통합하고 해결한다. 여기에는 이 시리즈의 두번째 글에서 언급된 시간 간격 루프가 호출된다.)


Querying a point or AABB involves checking to see which objects actually collide with either a pointer or AABB within the scene. This makes it easy for gameplay-related logic to see how things are placed within the world.

(장면에서 점 또는 AABB가 실제로 충돌했는지 검사하는 것과 관련해 확인한다. 이것은 이런 것들을 월드에 배치하는데 게임플레이관련된 로직을 쉽게 만든다.)


We need an easy way to pick out which collision function should be called, based on the type of two different objects.

(우리는 두 개의 서로 다른 물체의 유형에 따라 충돌 함수가 호출되어 골라내는 쉬운 방법이 필요하다.)


In C++ there are two major ways that I am aware of: double dispatch and a 2D jump table. In my own personal tests I found the 2D jump table to superior, so I'll go into detail about how to implement that. If you're planning to use a language other than C or C++ I am sure an array of functions or functor objects can be constructed similarly to a table of function pointers (which is another reason I chose to talk about jump tables rather than other options that are more specific to C++).

(c++에서는 2가지 큰 방법이 있다는 것을 나는 알고 있다. 그건 더블 디스패치(이중 나눔, double dispatch)와 2D 점프 테이블이다. 나의 개인적인 테스트에서는 나는 2D 점프 테이블이 더 우수한 것을 발견했고 그래서 나는 그것을 어떻게 수행하는지 살펴보겠다. 만약 당신이 C나 C++이외의 언어를 사용할 계획이라면 나는 함수의 배열 또는 functor objects(함수자 개체인듯??) 는 함수 포인터의 테이블과 비슷하게 구성될 것이라고 확신한다.(내가 점프테이블에 대해서 이야기하는 것을 택한 또 다른 이유는 다른 옵션보다는 C++이 더 특별하기기때문이다.))


A jump table in C or C++ is a table of function pointers. Indices representing arbitrary names or constants are used to index into the table and call a specific function. The usage could look something like this for a 1D jump table:

(점프 테이블은 C 또는 C++에서는 함수 포인터들의 테이블이다. 임의의 이름을 나타내는 지수 또는 상수를 테이블안의 인덱스로 사용하고 그리고 특별한 함수를 호출한다. 사용법으로는 1D 점프테이블 같은 것을 볼 수 있다.)



The above code actually mimics what the C++ language itself implements with virtual function calls and inheritance. However, C++ only implements single dimensional virtual calls. A 2D table can be constructed by hand.

(위 코드는 c++ 언어의 가상 함수 호출과 상속을 모방한 것이다. 하지만 c++은 오직 1차원의 가상 호출을 구현했다. 2D 테이블은 직접 만들어질 것이다.)

Here is some psuedocode for a 2D jump table to call collision routines:

(여기 2D점프테이블이 충돌 루틴을 호출하는 것을 위해 수도코드를 작성하였다.)



And there we have it! The actual types of each collider can be used to index into a 2D array and pick a function to resolve collision.

Note, however, that AABBvsCircle and CirclevsAABB are almost duplicates. This is necessary! The normal needs to be flipped for one of these two functions, and that is the only difference between them. This allows for consistent collision resolution, no matter the combination of objects to resolve.

(그리고 우리는 이것을 가지고 있다! 각 충돌체의 실제 타입들은 2D 배열의 인덱스로 사용될 수 있고 충돌을 해결하기 위해 함수를 고른다. 하지만 주의해라, AABB vs 원 그리고 원 vs AABB 는 거의 중복된다. 이것은 필요하다! 그 노멀은 두 함수들 중에 하나에서 반대로 될 필요가 있고 그것이 그들의 유일한 차이점이다. 이것은 일관된 충돌 해결이고 물체의 결합을 해결하는 것에 문제가 되지 않는다.)



By now we have covered a huge amount of topics in setting up a custom rigid body physics engine entirely from scratch! Collision resolution, friction, and engine architecture are all the topics that have been covered thus far. An entirely successful physics engine suitable for many production-level two dimensional games can be constructed with the knowledge presented in this series so far.

Looking ahead into the future, I plan to write one more article devoted entirely to a very desirable feature: rotation and orientation. Oriented objects are exceedingly attractive to watch interact with one another, and are the final piece that our custom physics engine requires.

Resolution of rotation turns out to be quite simple, though collision detection takes a hit in complexity. Good luck until next time, and please do ask questions or post comments below!

(뭐 대충 이런거 저런거 배웠다라는 끝맺음 글)


---------------------------------------------------------------------------------------------------------

으아 3번쨰 파트도 끝났다!!!!!

중간부분에 뭔소리인지 몰라서 번역 막 한 부분이 있음;;


(네이버 블로그 - 2016.01.29. 03:37)


최근 트랙백

알림

이 블로그는 구글에서 제공한 크롬에 최적화 되어있고, 네이버에서 제공한 나눔글꼴이 적용되어 있습니다.

태그

카운터

Today : 45
Yesterday : 58
Total : 126,083