Game Develop/Physics

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


원본글은 위 링크

발번역+오역+의역 난무

개인 공부하려고 번역함


In this part of my series on creating a custom 2D physics engine for your games, we'll add more features to the impulse resolution we got working in the first part. In particular, we'll look at integration, timestepping, using a modular design for our code, and broad phase collision detection.


In the last post in this series I covered the topic of impulse resolution. Read that first, if you haven't already!

Let's dive straight into the topics covered in this article. These topics are all of the necessities of any half-decent physics engine, so now is an appropriate time to build more features on top of the core resolution from the last article.

Integration is entirely simple to implement, and there are very many areas on the internet that provide good information for iterative integration. This section will mostly show how to implement a proper integration function, and point to some different locations for further reading, if desired.

(통합은 전체적으로 구현이 간단하고 매우 많은 인터넷에서 반복적으로 나타나는 통합에 대한 좋은 정보들이 제공된다.  이 섹션은 어떻게 통합 함수를 적절하게 구현해야하는지 보여줄 것이고 일부 다른 위치의 점을 더 읽기를 위한다. 원한다면 말이다.)

First it should be known what acceleration actually is. Newton's Second Law states:

(먼저 가속도가 어떻게 되는지 알아야한다. 뉴턴의 2번째 법칙 :)

Equation 1


This states that the sum of all forces acting upon some object is equal to that object's mass m multiplied by its acceleration a. m is in kilograms, a is in meters/second, and F is in Newtons.

(이것은 어떤 물체에 작용하는 모든 힘의 합이 객체의 질량 m 과 가속도 a를 곱한 것을 말한다. 질량 m 은 kg단위이고, 가속도 a는 m/s 단위이다. 힘 F는 뉴턴 단위이다.)

Rearranging this equation a bit to solve for a yields :

(가속도를 구하기 위해 다시 식을 정리한다 :)

Equation 2



The next step involves using acceleration to step an object from one location to another. Since a game is displayed in discrete separate frames in an illusion-like animation, the locations of each position at these discrete steps has to be calculated. For a more in-depth cover of these equations please see: Erin Catto's Integration Demo from GDC 2009 and Hannu's addition to symplectic Euler for more stability in low FPS environments.

(다음 단계는 가속을 이용하여 한 지역에서 다른 지역으로 이동하는 것과 관련이 있다. 게임이 환상같은 애니메이션이 별도로 분리되어 그려지는데 이 분리된 단계들에서 서로의 위치를 계산되어야 한다. 이 이야기에 대한 자세한 이야기는 다음을 보라 : Erin Catto's Integration Demo from GDC 2009 and Hannu's addition to symplectic Euler for more stability in low FPS environments.)

Explicit Euler (pronounced "oiler") integration is shown in the following snippet, where x is position and  v is velocity. Please note that 1/m * f is acceleration, as explained above:

(명시적 오일러 통합은 x 포지션과 v속도인 다음 코드에서 보여진다. 1/m * f 가 가속도인 것을 기억하라.)

// Explicit Euler
x += v * dt
v += (1/m * F) * dt

dt here refers to delta time. Δ is the symbol for delta, and can be read literally as "change in", or written as Δt. So whenever you see dt it can be read as "change in time". dv would be "change in velocity".
(dt는 델타타임을 뜻한다. Δ는 델타를 뜻하는 기호로 "의 변화"로 읽을 수 있고 Δt라고 쓸수도 있다. 그래서 언제든지 너는 이것을 "시간의 변화"이라고 읽는다. dv는 "가속의 변화"가 된다.)
This will work, and is commonly used as a starting point. However, it has numerical inaccuracies that we can get rid of without any extra effort. Here is what is known as Symplectic Euler:
(이것은 작동 될것이고 일반적으로 시작점으로 사용된다. 하지만 이것은 어떤 추가적인 노력없이는 고칠 수 없는 부정확한 수치이다.)

// Symplectic Euler
v += (1/m * F) * dt
x += v * dt

Note that all I did was rearrange the order of the two lines of code - see ">the aforementioned article from Hannu.

(코드 두 줄을 재배열하였다 보기 : the aforementioned article from Hannu.)

This post explains the numerical inaccuracies of Explicit Euler, but be warned that he starts covering RK4, which I don't personally recommend: gafferongames.com: Euler Inaccuracy.

(이 글은 명시적인 오일러의 부정확한 수치에 대한 설명이다. 하지만......????????)

These simple equations are all that we need to move all objects around with linear velocity and acceleration.

(여기 간단한 모든 식들은 선형 속도와 가속과 함께 주변 모든 물체들이 이동하는데 필요하다)

Since games are displayed at discrete time intervals, there needs to be a way of manipulating the time between these steps in a controlled manner. Have you ever seen a game that will run at different speeds depending on what computer it is being played on? That's an example of a game running at a speed dependent on the computer's ability to run the game.

(게임은 제어된 방식으로 이 단계들 사이에 시간을 조작하는 방법이 필요한 이산시간구간으로 디스플레이 된다. 컴퓨터에 따라서 다른 속도로 플레이되는 게임을 본적이 있는가? 게임이 돌아가는 속도가 컴퓨터의 성능에 의존되는 예이다.)

We need a way to ensure that our physics engine only runs when a specific amount of time has passed. This way, the dt that is used within calculations is always the exact same number. Using the exact same dt value in your code everywhere will actually make your physics engine deterministic, and is known as a fixed timestep. This is a good thing.

(우리는 특정한 길이의 시간이 지나갈때 우리의 물리 엔진이 안전하게 하는 방법이 필요있다. 이 방법에서 계산에 사용하는 dt는 항상 같은 수이다. 정확하게 같은 dt 값을 사용하는 것은의 코드 어디서든지 너의 물리엔진 결정적이게 만들것이고 이 것은 고정된 시간 간격(fixed timestep, 고정적인 시간 간격으로 업데이트하게 하는 기법)로 알려져 있다. 이것은 좋다)

A deterministic physics engine is one that will always do the exact same thing every time it is run assuming the same inputs are given. This is essential for many types of games where gameplay needs to be very fine-tuned to the physics engine's behavior. This is also essential for debugging your physics engine, as in order to pinpoint bugs the behavior of your engine needs to be consistent.

(결정적인 물리엔진은 매번 같은 시간에 항상 같은 입력이 가해져 실행된다고 가정한다. 이것은 게임플레이가 물리엔진의 행동으로 매우 미세한 조정이 필요한 게임들의 종류을 위해 필수적이다. 이것은 또한 버그를 파악하기 위해 당신의 엔진의 동작이 일치하는지 확인하기 위해 물리엔진의 디버깅이 필수적이다.)

Let's first cover a simple version of a fixed timestep. Here is an example:

(간단한 고정된 시간 간격를 여기 보여준다.)

This waits around, rendering the game, until enough time has elapsed to update the physics. The elapsed time is recorded, and discrete dt -sized chunks of time are taken from the accumulator and processed by the physics. This ensures that the exact same value is passed to the physics no matter what, and that the value passed to the physics is an accurate representation of actual time that passes by in real life. Chunks of dt are removed from the accumulator until the accumulator is smaller than a dt chunk.

(물리가 업데이트하는데 경과된 충분한 시간까지 게임을 렌더링하는데 기다려야한다. 이 경과된 시간은 기록되고 분리된 dt 시간 덩어리를 물리에서 진행과 축적기(accumulator, 변수임)로부터 가져간다. 이것은 정확한 같은 값이 지나가게 물리에서 아무런 문제없도록 안정을 보장하고 이 값은 실제 생활에서 지나가는 시간과 일치같다.  축적기(accumulator)가 dt 덩어리보다 작아질때까지 dt의 덩어리들은 축적기(accumulator)에서 제거된다.)

There are a couple of problems that can be fixed here. The first involves how long it takes to actually perform the physics update: What if the physics update takes too long and the accumulator goes higher and higher each game loop? This is called the spiral of death. If this is not fixed, your engine will quickly grind to a complete halt if your physics cannot be performed fast enough.

To solve this, the engine really needs to just run fewer physics updates if the accumulator gets too high. A simple way to do this would be to clamp the accumulator below some arbitrary value.

(여기 몇가지 문제들을 해결하게 될 것이다. 먼저 얼마나 오래 실제로 물리 업데이트 작동이 걸리는지 : 만약 물리 업데이트가 너무 길고  축적기(accumulator)가 높아지고 각각의 게임 루프가 오래걸린다면? 이 것은 죽음의 수용돌이라고 불린다. 만약 이것이 고쳐지지 않으면 만약 당신의 물리가 충분히 빠르게 작동되지 않는다면 당신의 엔진은 완전히 멈춰지기 위해 빠르게 삐꺽거릴 것이다. 이것을 해결하기 위해 엔진은 축적기(accumulator)가 너무 클 경우 단지 약간의 물리 업데이트만이 필요하다. 여기 임의의 값이하로 축적기(accumulator)를 고정하는 간단한 방법이 있다.)

Now, if a game running this loop ever encounters some sort of stalling for whatever reason, the physics will not drown itself in a spiral of death. The game will simply run a little more slowly, as appropriate.

(이제 만약 게임이 이 루프를 실행하는 도중 무슨 이유이든지간에 어떤 어느정도의 지연을 맞딱드린다면 물리는 자기 자신을 죽음의 수용돌이에 빠지지 않게 할 것이다. 그 게임은 적당하도록 조금 더 느리게 간단히 실행될 것이다.

The next thing to fix is quite minor in comparison to the spiral of death. This loop is taking dt chunks from the accumulator until the accumulator is smaller than dt. This is fun, but there's still a little bit of remaining time left in the accumulator. This poses a problem.

Assume the accumulator is left with 1/5th of a dt chunk every frame. On the sixth frame the accumulator will have enough remaining time to perform one more physics update than all the other frames. This will result in one frame every second or so performing a slightly larger discrete jump in time, and might be very noticeable in your game.

(다음 문제는 죽음의 수용돌이에 비하면 꽤 작은 문제이다. 이 루프는 축적기(accumulator)가 dt보다 작아질때까지 dt 덩어리를 축적기(accumulator)로 부터 가져온다. 이건 재미있지만 여전히 약간의 남은 시간이 축적기(accumulator)에 남아있다. 이것은 문제를 야기한다. 축적기(accumulator)는 매프레임마다 dt 덩어리의 1/5가 남는다. 6번째 프레임에서 축적기(accumulator)는 모든 다른 프레임들보다 한번 더 작동할 수 있는 남은 시간을 갖게 된다. 이것은 한 프레임마다 또는 시간을 약간 더 큰 값으로 점프시키고 당신의 게임에서 매우 두드려지게 눈에 띌 수도 있다.)

To solve this, the use of linear interpolation is required. If this sounds scary, don't worry - the implementation will be shown. If you want to understand the implementation there are many resources online for linear interpolation.

(해결하기 위해서는 선형 보간(linear interpolation)이 요구된다. 이것은 무섭게 들리지만 괜찮다 보간을 보여주겠다. 만약 보간을 이해하기를 원한다면 인터넷에 많은 자료가 있을 것이다.)

Using this we can interpolate (approximate) where we might be between two different time intervals. This can be used to render the state of a game in between two different physics updates.

우리는 이것을 2개의 다른 시간 차이에 대해 보간(에 근접한)으로 사용할 수 있다. 이것으로 2개의 다른 물리 업데이트들 사이에서 게임의 상태를 렌더할수 있다.)

With linear interpolation, the rendering of an engine can run at a different pace than the physics engine. This allows a graceful handling of the leftover accumulator from the physics updates.

(선형 보간은 함께, 엔진의 렌더링이 물리엔진과 다른 속도로 실행할 수 있다. 이것을 허용하면 물리업데이트에서의 축적기(accumulator)가 과도하게 남은 것을 정상적으로 처리 할 수 있다.)

Here is a full example:

Here, all objects within the game can be drawn at variable moments between discrete physics timesteps. This will gracefully handle all error and remainder time accumulation. This is actually rendering ever so slightly behind what the physics has currently solved for, but when watching the game run all motion is smoothed out perfectly by the interpolation.

(여기 모든 오브젝트들은 별개의 물리 시간 간격사이에서 다양한 순간들이 그려질 것이다. 이것은 모든 에러와 남은 시간의 축적에 대해 매우 정상적으로 다뤄질 것이다. 이것은 실제로 물리가 일어난 시점 약간 뒤에 그리지만 게임을 보고 있을때는 모든 모션들은 보간에 의해 부드럽고 완벽하게 보인다.)

The player will never know that the rendering is ever so slightly behind the physics, because the player will only know what they see, and what they'll see is perfectly smooth transitions from one frame to another.

(플레이어는 그들이 보는 것과 그들이 보는 것은 프레임과 또 다른 프레임 사이의 완벽하고 부드러운 움직임이기 때문에 플레이어는 물리가 약간 뒤에 그려지는지 전혀 알지 못한다.

You may be wondering, "why don't we interpolate from the current position to the next?". I tried this and it requires the rendering to "guess" where objects are going to be in the future. Often, objects in a physics engine make sudden changes in movement, such as during collision, and when such a sudden movement change is made, objects will teleport around due to inaccurate interpolations into the future.

(당신은 이러한 의문을 가질 수 있다 "왜 우리는 보간을 현재 위치로부터 다음 위치로 하지 않지?". 나는 이것을 시도했었고 이것을 렌더링하기 위해서는 다음프레임에 어디에 있을지에 대한 추측이 요구된다".  때때로 물리엔진의 물체들은 충돌하는 동안 갑자기 움직임을 바꾸고 갑자기 움직임이 바뀔때 물체들은 미래에 부정확한 추측으로 인해 부정확한 보간이 일어나 갑자기 순간이동을 하게 될 것이다.)

There are a few things every physics object is going to need. However, the specific things each physics object needs may change slightly from object to object. A clever way to organize all this data is required, and it would be assumed that the lesser amount of code to write to achieve such organization is desired. In this case some modular design would be of good use.

Modular design probably sounds a little pretentious or over-complicated, but it does make sense and is quite simple. In this context, "modular design" just means we want to break a physics object into separate pieces, so that we can connect or disconnect them however we see fit.

(여기 모든 물리적인 물체가 작동하기 위해 필요한 몇 가지 것들이 있다. 하지만 그 특정한 것들은 각각의 물리적인 물체가 물체에서 물체로 약간 바뀌는 것이 필요할수도 있다. 이 교묘한 방법은 필요한 모든 데이터를 조직화하고 적은 양의 코드조직하기 위해 작성하는 것으로 가정한다. 지금의 경우에는 어떤 모듈 디자인은 잘 활용 될 것이다. 모듈 디자인은 가식적이거나 또는 지나치게 완벽하게 들리지만 이것은 이해하기 쉽게 하고 이것을 꽤 간단하게 만든다. 이 "모듈 디자인"문맥은 우리가 물리적인 오브젝트를 별도의 조각들로 깨는 것을 원하기에 우리가 그것들을 적절히 연결하고 연결해제한다.)

A physics body is an object that contains all information about some given physics object. It will store the shape(s) that the object is represented by, mass data, transformation (position, rotation), velocity, torque, and so on. Here is what our body ought to look like:

(물리 바디는 어떤 물리 물체에 대한 모든 정보를 포함 오브젝트입니다. 이것은 물체가 표현되는 모양, 질량 데이터, 변환(위치, 회전), 속도, 회전력 등을 저장한다. 여기 우리의 바디를 볼 것이다)

This is a great starting point for the design of a physics body structure. There are some intelligent decisions made here that tend towards strong code organization.

(이것은 물리 바디 구조체를 설계하기에 좋은 시작이다. 이 정보들은 코드를 조직적으로 단단하게 만들게 할 것이다.)

The first thing to notice is that a shape is contained within the body by means of a pointer. This represents a loose relationship between the body and its shape. A body can contain any shape, and the shape of a body can be swapped around at will. In fact, a body can be represented by multiple shapes, and such a body would be known as a "composite", as it would be composed of multiple shapes. (I'm not going to cover composites in this tutorial.)

(첫번째 일은 포인터로 바디에 포함되어 있는 모양(shape)을 선언하는 것이다. 이것은 바디와 그것의 모양 사이의 느슨한 관계를 보여준다. 바디는 어떤 모양이든지 포함 할 수 있고 그 바디의 모양은 바꿀 수 있다. 사실 바디는 여러 모양들로 보여줄 수 있고 각각의 바디는 "컴포지트"라고 알려져 있고 이것을 여러형태로 구성할 것이다. (이 튜토리얼에서 컴포지트를 다루지 않을 것이다.))

Body and Shape interface.
Body and Shape interface.

The shape itself is responsible for computing bounding shapes, calculating mass based on density, and rendering.

The mass_data is a small data structure to contain mass-related information:

(모양은 자기 자신의 경계 모양을 계산 하는 것을 책임지고 밀도를 기반으로 질량을 계산하며 그린다. mass_data는 작은 구조체로 된 데이터로 질량 관련 정보를 포함한다) 

It is nice to store all mass- and intertia-related values in a single structure. The mass should never be set by hand - mass should always be calculated by the shape itself. Mass is a rather unintuitive type of value, and setting it by hand will take a lot of tweaking time. It's defined as:

(이것은 단일 구조체에 질량과 관성을 모두 저장하는 멋진 구조체이다. 질량은 절대로 직접 손으로 값을 넣지 않고 모양이 스스로 계산 할 것이다. 질량은 직관적이지 않은 유형의 값이고 직접 손으로 입력하면 조정시간을 많이 잡아먹는다.)

Equation 3


Whenever a designer wants a shape to be more "massive" or "heavy", they should modify the density of a shape. This density can be used to calculate the mass of a shape given its volume. This is the proper way to go about the situation, as density is not affected by volume and will never change during the runtime of the game (unless specifically supported with special code).

Some examples of shapes such as AABBs and Circles can be found in the previous tutorial in this series.

(언제든지 디자이너는 모양이 좀더 "거대한" 또는 "무거워"지길 바라고 그들은 모양의 밀도를 수정해야 한다. 이 밀도로 부피가 주어진 모양의 질량을 구할 수 있다. 이것은 이 상황으로 갈 수 있는 적절한 방법으로 밀도는 부피의 영향을 받지 않고 밀도는 게임이 실행되는 동안 절대로 바뀌지 않는다.(특별한 코드가 특별히 지원하지 않는 경우) AABB과 원같은 모양에 대한 몇가지 예를 이 시리즈의 이전 튜토리얼에서 찾을 수 있다.)

All this talk of mass and density leads to the question: Where does the density value lay? It resides within the Material structure:

(모든 질량과 밀도의 이야기는 이러한 의문을 가져온다 : 어디에서 밀도값을 마련하지? 그것은 재질 구조체에 존재한다.)

Once the values of the material are set, this material can be passed to the shape of a body so that the body can calculate the mass.

(재질의 값이 설정되면 이 재질은 바디가 질량을 계산할 수 있도록 모양의 바디에 전달된다.)

The last thing worthy of mention is the gravity_scale. Scaling gravity for different objects is so often required for tweaking gameplay that it is best to just include a value in each body specifically for this task.

(마지막 것(restitution변수)은 중력 스케일을 의미한다. 물체별로 중력을 스케일링하는 것은 각각의 몸통이 이 작업에 가장 나은 값을 갖도록 게임 플레이에 자주 값 조정이 필요하다.)

Some useful material settings for common material types can be used to construct a Material object from an enumeration value:

(몇가지 쓸만한 일반적인 종류의 재질들의 값들이 여기 있다)

There is one more thing to talk about in the body structure. There is a data member called force. This value starts at zero at the beginning of each physics update. Other influences in the physics engine (such as gravity) will add Vec2 vectors into this force data member. Just before integration all of this force will be used to calculate acceleration of the body, and be used during integration. After integration this force data member is zeroed out.

(몸체 구조체에 한가지 더 있다. 이 데이터는 힘이라고 부른다. 이 값은 각각의 물리 업데이트를 시작할때 0을 갖고 시작한다. 물리엔진에서의 다른 영향(중력같은)을 받아 Vec2 벡터를 이 맴버 데이터에 더한다. 단지 통합 이전에 모든 힘은 몸체의 가속을 계산하는데 쓸 것이고 통합시에 사용할 것이다. 통합 이후에 이 힘 맴버 데이터는 삭제된다.)

This allows for any number of forces to act upon an object whenever they see fit, and no extra code will be required to be written when new types of forces are to be applied to objects.

(이것은 맞붙을때마다 물체에 작용하는 힘의 갯수가 몇 개이든 허용되고 새로운 종류의 힘을 물체에 적용할때 더 이상 코드를 쓰는 것이 요구되지 않는다.)

Lets take an example. Say we have a small circle representing a very heavy object. This small circle is flying around in the game, and it is so heavy that it pulls other objects towards it ever so slightly. Here is some rough pseudocode to demonstrate this:

(예제를 보자. 작은 원이 매우 무거운 물체를 표현한다. 이 작은 원은 게임에서 날아가는데 그것은 꽤 무거워 다른 물체를 끈다. 여기 간단한 수도코드가 있다.)

The function ApplyForcePullOn() could perhaps apply a small force to pull the body towards the HeavyObject, only if the body is close enough.

(ApplyForcePullOn()함수는 오직 몸통이 충분히 가까우면 어쩌면 몸통를 HeavyObject쪽으로 당기는 작은 힘을 적용할 것이다.

Two objects pulled towards a larger one. The pull force is dependent upon distance.
Two objects pulled towards a larger one moving pasted them. The pull forces are dependent upon their distance to the larger box.(두개의 오브젝트가 큰 것으로 당겨진다. 당겨지는 힘은 큰 박스와의 거리에 따라 달라진다.)







It doesn't matter how many forces are added to the force of a body, as they will all add up to a single summed force vector for that body. This means that two forces acting upon the same body can potentially cancel each other out.

(얼마나 큰 힘이 몸통에 추가되든 상관없고 그것들은 몸통에 하나의 더해진 벡터가 될것이다. 이것은 동일한 몸통에 작용하는 두 힘 잠재적으로 서로 상쇄할 수 있다는 것을 의미한다.)

In the previous article in this series collision detection routines were introduced. These routines were actually apart of what is known as the "narrow phase". The differences between broad phase and narrow phase can be researched rather easily with a Google search.

(이 시리즈의 이전 글에서 검출 루틴이 소개됬었다. 이 루틴들은 "좁은 단계(narrow phase)"라고 알려져있다. 광범위한 단계(broad phase)와 좁은 단계(narrow phase)와의 차이는 구글 검색으로 쉽게 찾을 수 있다)

(In brief: we use broad phase collision detection to figure out which pairs of objects might be colliding, and then narrow phase collision detection to check whether they actually are colliding.)

(간단히 : 우리는 물체가 한 쌍의 물체가 출돌할 수 있는 것을 알아낼 수 있는 광범위한 단계(broad phase) 충돌 검출를 사용하고 그 때 좁은 단계(narrow phase) 충돌 검출로 실체 충돌을 검출한다.)

I would like to provide some example code along with an explanation of how to implement a broad phase of O(n^2) time-complexity pair calculations.

(나는 몇 가지 예제 코드와 O(n^2)의 시간 복잡도로 어떻게 구현하는지에 대한 설명을 제공하고 싶다.)

O(n^2) essentially means that the time taken to check every pair of potential collisions will depend on the square of the number of objects. It uses Big-O notation.

(O(n^2)는 매쌍의 잠재적인 충돌을 체크하는데 걸리는 시간을 의미하고 이것은 물체 숫자의 제곱에 따라 바뀐다. 이것은 빅오 표기법을 이용한다.) 

Since we're working with pairs of objects, it will be useful to create a structure like so:

(여러 쌍의 물체들이 실행하기 때문에 이것은 구조체를 만들어 유용하게 할 것이다)

A broad phase should collect a bunch of possible collisions and store them all in Pair structures. These pairs can then be passed on to another portion of the engine (the narrow phase), and then resolved.

Example broad phase:

(광범위한 단계(broad phase)는 가능한 충돌 무리를 얻어야 하고 그것들을 Pair 구조체에 저장한다. 이 쌍들은 엔진의 다른 부분으로 보내진다(좁은 단계(narrow phase) 그리고 해결된다.)

The above code is quite simple: Check each body against each body, and skip self-checks.

(위 코드는 매우 간단하다. 각각의 몸통은 각각의 몸통에 대하여 검사하고 셀프 체크를 넘긴다.

There is one problem from the last section: many duplicate pairs will be returned! These duplicates need to be culled from the results. Some familiarity with sorting algorithms will be required here if you do not have some sort of sorting library available. If you're using C++ then you're in luck:

(마지막 섹션으로부터 문제 하나가 있다. 많은 똑같은 쌍이 돌아오게 될 것이다! 이 중복들은 결과로부터 잘라질(컬링이 될)필요가 있다. 만약 당신이 정렬 알고리즘을 가지고 있지 않다면 정리 친숙함과 함께 정렬 알고리즘은 요구될 것이다. 만약 당신이 C++을 사용한다면 당신은 운이 좋다.) 

After sorting all the pairs in a specific order it can be assumed that all pairs in the pairs container will have all duplicates adjacent to one another. Place all unique pairs into a new container called uniquePairs, and the job of culling duplicates is finished.

The last thing to mention is the predicate SortPairs(). This SortPairs() function is what's actually used to do the sorting, and it might look like this:

(특정 순서의 모든 쌍을 정렬한 이후에 한 컨테이너(정보를 담는 공간 정도로 생각하면 될 듯)의 모든 쌍 쌍들은 서로 인접한 중복이 있을 것이라고 가정할 수 있다. 모든 고유의 쌍들을 uniquePair라고 부르는 새로운 컨테이너에 중복 컬링 작업을 끝낸다. 마지막으로 언급할 것은 SortPair()이다. 이 함수는 실제로 정렬을 하는데 사용한다.)

The terms lhs and rhs can be read as "left hand side" and "right hand side". These terms are commonly used to refer to parameters of functions where things can logically be viewed as the left and right side of some equation or algorithm.
(lhs와 rhs는 각각 "좌변" 그리고 "우변"으로 읽을 수 있는 규칙이 있다(그냥 쉽게 왼쪽, 오른쪽으로 읽어도 될듯). 이 규칙은 일반적으로 함수의 파라미터를 표현하는데 어떤 식이나 알고리즘의 왼쪽 오른쪽에 있는 값을 뜻한다.)

Layering refers to the act of having different objects never collide with one another. This is key for having bullets fired from certain objects not affect certain other objects. For example, players on one team might want their rockets to harm the enemies but not each other.

레이어링은 다른 다른 물체와 절대로 충돌을 하지 않도록 설정하는 것이다. 이 것은 총알들이 특정 물체들에서 발사되어 다른 물체들에게 영향주지 않도록 하도록 할 수 있는 방법이다. 예를 들어 플레이어가 있는 팀은 그들의 로켓들이 그들의 적을 해치길 바라지만 같은 팀 서로를 해치고 싶어하지는 않는다.) 

Representation of layering; some object collide with one another, some do not.
Representation of layering; some object collide with one another, some do not.(레이어링의 그림; 어떤 물체는 다른 것과 충돌하지만 어떤것은 그렇지 않다)




Layering is best implemented with bitmasks - see A Quick Bitmask How-To for Programmers and the Wikipedia page for a quick introduction, and the Filtering section of the Box2D manual to see how that engine uses bitmasks.

Layering should be done within the broad phase. Here I'll just paste a finished broad phase example:

(레이어링은 비트마스크와 함께 최고의 구현이다( A Quick Bitmask How-To for Programmersthe Wikipedia page의 빠른 소개를 보아라 그리고 어떻게 엔진에서 비트마스크를 사용하는지 보기위해 the Box2D manual섹션을 필터링하여라. 레이어링은 광범위한 단계(broad phase)가 끝나있어야 한다. 여기 나는 광범위한 단계(broad phase)를 그냥 붙여넣기만 한다)

Layering turns out to be both highly efficient and very simple.

(레이어링은 고효율적이고 매우 간단하다)

A halfspace can be viewed as one side of a line in 2D. Detecting whether a point is on one side of a line or the other is a pretty common task, and should be understood thoroughly by anyone creating their own physics engine. It is too bad that this topic isn't really covered anywhere on the internet in a meaningful way, at least from what I've seen - until now, of course!

The general equation of a line in 2D is:

(절반 공간은 2D공간의 한쪽에서 볼 수 있다. 선 또는 다른 것 위의 점 여부를 검출하는 것은 매우 일반적인 작업이고 자신들이 만든 물리엔진을 충분히 이해해야 한다. 내가 여태까지 본 것으로는 이것은 인터넷 어디에서든지 잘 다루지 않아 안타깝다. 이것은 2D공간에서의 일반적인 직선의 식이다.)

Equation 4



Note that, despite its name, the normal vector is not necessarily normalized (that is, it doesn't necessarily have a length of 1).

To see whether a point is on a particular side of this line, all that we need to do is plug the point into the x and y variables in the equation and check the sign of the result. A result of 0 means the point is on the line, and positive/negative mean different sides of the line.

(알아야하는 것이 노멀 벡터는 그런 이름을 가지고 있지만 반드시 정규화 될 필요는 없다(즉, 길이를 1로 만들 필요가 없다.) 점이 선의 한쪽 면 있는지 여부를 확인하려면 우리는 그 식에서 x와 y값에 점의 위치를 넣어주고 결과의 부호를 확인한다. 결과가 0으로 나오면 선위에 있다는 뜻이고 양수/음수로 선의 다른 쪽에 있다는 것을 의미한다.)

That is all there is to it! Knowing this the distance from a point to the line is actually the result from the previous test. If the normal vector is not normalized, then the result will be scaled by the magnitude of the normal vector.

(즉 이겁니다! 점으로부터 선까지의 거리를 알려면 실제로 이전 테스트에서 결과가 나타난다. 만약 노멀 벡터가 정규화 되지 않았다면 그 결과는 노멀벡터의 크가가 조정될 것이다.)

By now a complete, albeit simple, physics engine can be constructed entirely from scratch. More advanced topics such as friction, orientation, and dynamic AABB tree may be covered in future tutorials. Please ask questions or provide comments below, I enjoy reading and answering them!


오랜만에 번역 완료 힣
이제 반을 번역했는데 배우는게 많아서 좋음
한국어로 표기하기 힘든 용어들을 억지로 한국어로 썼는데 걍 영어로 읽는게 더 나은듯
그나저나 이 글은 나만 읽기 편하다는게 함정 힣

(네이버 블로그 - 2016.01.17. 17:35)

최근 트랙백


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



Today : 45
Yesterday : 58
Total : 126,083