Monday, December 30, 2019

shared_ptr


#include <iostream>
#include <vector>

using namespace std;

class MyClass
{
public:
        MyClass()
        {
               cout << "MyClass is created" << endl;
        }

        ~MyClass()
        {
               cout << "MyClass is destroyed" << endl;
        }
};

class MyParent
{
public:
        shared_ptr<char> data;
        //char* data;

        MyParent()
        {
               //data = new char[100];
               data = make_shared<char>(100);
               strcpy(data.get(), "haha");
        }

        ~MyParent()
        {
               data.reset();
               //delete data;
        }
};

void* operator new(std::size_t size)
{
        void* storage = malloc(size);
        return storage;
}

void operator delete(void* data)
{
        free(data);
}

int main() {   
        vector<MyParent> vec;

        {
               MyParent parent;                      
               vec.push_back(parent);
        }                     
        return 1;
}



when I use shared_ptr then memory variable 'data' is still alive when we are at 'return 1;'
instead raw pointer (char* data) will be deleted.

{ MyParent parent; vec.push_back(parent); }

because char* data of local variable of parent is trying to free char* data.
Personally I prefer to use raw pointer and try to avoid use value type of MyParent.
If I use a pointer type then

vector<MyParent*> vec;

unique_ptr

unique_ptr<MyClass> a = make_unique<MyClass>();
unique_ptr<MyClass> b = move(a);

Thursday, December 19, 2019

Motion Matching prototype

Recently I'm implementing a motion matching animation tech. I think use correct animation data is more important than the algorithm (of course!) 


Game AI 3rd edition... :'(

I translated game ai 2nd edition and below section got removed from the 3rd edition. :&

렌더링 하드웨어에서 작업하기
오래된 콘솔에서 작업하는데 있어 가장 큰 문제는 그래픽스를 위한 최적화 작업이다. 그래픽스는 보통 게임의 뒷편에 있는 첨단 기술의 핵심이며 한정된 리소스를 사용해 최신의 그래픽 기술을 제공하는 것을 콘솔 제작자가 강조하는 것이 당연하다.

오리지널 Xbox 설계는 최초로 PC와 같은 콘솔 아키텍처를 가진 점에 있어서 새로웠다. PC와 같이 메인 프로세서가 있고 이해 가능한 그래픽 버스, 친숙한 그래픽 칩셋을 갖추고 있었다. 다른 한쪽에서 PS2의 경우 뻔뻔하게도 그래픽스 렌더링에 최적화 되어 있었다. 하드웨어의 성능을 최대한으로 사용하려면 최대한 렌더링을 병렬로 돌아가게 만들어야 했고 이로 인해 생겨나는 동기화, 통신 이슈가 만만치 않게 어려운 작업이었다. 몇몇 개발자는 간단하게 포기하는 단계에 이르렀고 게임에 간단한 AI를 넣는 수준에서 멈췄다. 콘솔 개발을 하게 되면 AI 개발자에게 있어 눈에 가시인 크로스 플랫폼 타이틀 개발이 계속 된다. 다행히 PS3에는 멀티 코어가 있고 빠른 AI 처리를 매우 쉽게 달성할 수 있다.

렌더링 하드웨어는 파이프라인 모델로 동작한다. 데이터는 파이프의 끝에 들어가고 다양한 프로그램에 의해 계산 및 처리된다. 파이프라인의 끝에서 데이터는 화면에 그려질 준비를 마친다. 데이터는 파이프라인으로 다시 되돌릴 수 없고 데이터의 양은 보통 매우 작다. 입력 데이터를 전달 하는 것을 제외하고는 간단하고 데이터 플로우가 논리적이기 때문에 하드웨어는 이 파이프라인을 매우 효율적으로 동작하게 할 수 있다.

AI는 이 파이프라인 모델에 적합하지 않다. AI는 시간과 상관없이 다양한 종류의 코드가 동작하며 본질적으로 분기가 많다. 하나의 연산 결과가 많은 다른 객체의 입력 값이 되며 그것들의 결과 값들이 다시 처음의 입력 값으로 된다. 그리고 이것이 계속 반복된다.

캐릭터가 계속해서 움직일 때 충돌이 발생할 지점을 찾아낸다 거나 하는 간단한 AI 요청이라도 모든 지형을 검사해야 한다면 구현하는 것이 어려울 수 있다. 오래된 그래픽스 하드웨어는 충돌 처리를 제공하는 경우도 있지만 충돌을 예측하는 것은 여전히 AI 코드가 담당한다. 더 복잡한 AI는 필연적으로 CPU에서 동작하는데, 이 칩은 마지막 세대 콘솔에 비해 파워가 부족하고 그로 인해 인공 지능은 5~10년 전 PC에 제한되어 있다.

역사적으로 볼 때 동일한 처리 능력을 갖춘 PC와 비교할 때 콘솔에서 처리되는 AI의 양을 제한하는 경향이 있다.  가장 흥미로운 부분은 최근 18개월 동안 현세대 콘솔에서 PC와 같은 AI 실행이 가능하게 기능들을 제공하고 그 가능성을 보인다는 점이다.

Sunday, December 15, 2019

Representation of linear transformation of matrix

Let say there is a 3x3 matrix

[m11 m12 m13]
[m21 m22 m23]
[m31 m32 m33]

[m11 m12 m13] is a row vector

[m21 m22 m23] is a row vector

[m31 m32 m33] is a row vector

and which of above are basis vectors in 3D space. i, j, k in standard form.

[m11 m12 m13] is a row vector and i

[m21 m22 m23] is a row vector and j

[m31 m32 m33] is a row vector and k

using linear transformation we can write a vector v like down below.

v = vx*i + vy*j + vz*k

if we apply some transform(matrix) into vector V and we can visualize it.

for instance we have 

[1 0 0]
[0 1 0] == matrix A
[0 0 1]

it is an identity matrix and if we multiply vector v with matrix.

vA

we will get v because A is an identity matrix.

if matrix A is like down below.

[0.75 0.75 0]
[0 1 0]
[0 0 1]

vector v or shape of model will be scaled, shrink.



Using this representation, we can guess what the shape will look like when we apply some transformations. (Sorry! I'm not good at drawing)

Representation of vector and multiplication.

There are two ways to represent of vector.

row vector and column vector.

[x y z] is a row vector

[x]
[y]
[z]

is a column vector.

When we multiple a vector with matrix, should be careful.

For instance we want to apply matrix A, B then C in order and there is a vector 'v'
depending on the representation of vector, we use it differently.

if the v is a row vector then we should use vABC.
if the v is a column vector then we should use CBAv.

Many books and game engine uses differently. so you should be careful when you use it.

1. Check representation of vector.
2. Check an order of matrix and then apply it to the vector carefully.

Wednesday, December 4, 2019

about vector interpolation

Many of you guys already know that vector interpolation might have different result than you think.

As you can see the below image, red arrow is a forward vector and green arrow is a right vector of the character.

If you interpolate forward vector to right vector, you will get below image.


This is because I didn't account of angle of vector. If I account of angle of vector then I'll get different result like down below.


In unreal engine 4, There are related functions exist.

FMath::RInterpTo is for linear interpolation.
FQuat::Slerp is for spherical linear interpolation.

Friday, November 29, 2019

Animation programming in UE4 and about GetEvaluateGraphExposedInputs

My input data was missed in my custom AnimNode and find out that I missed a call function.

GetEvaluateGraphExposedInputs().Execute(Context);

What GetEvaluateGraphExposedInputs().Execute(Context) does is copy all the input data into AnimNode. (That's why there is some cost...)

If you look at the AnimNodeBase.cpp and line 675 there are function FExposedValueHandler::Execute function.

Wednesday, November 27, 2019

Applying a transform into Normal vector.


Applying a transform into normal vector
When we apply a transform into normal vector, we can't use N * M. Because we don't want scale effect like below.


We represent basic transform like below. 




We want to apply R(rotation) only not S(scale). Our expected transform needs to be like below.



If we take inverse of rotation matrix and then take transpose, result matrix will be same as original rotation matrix. so we can represent above formula like below.


As we know, scale transform is a diagonal matrix. If we take a transpose of it, result will be same as original scale transform.


Our expected matrix can be like this.

In the transpose matrix, there is a property.


matrix can be represented like below.


In the inverse matrix, there is a property.


matrix can be represented like below.


R1 * S * R2 is a transform matrix M. As a result, we can have a matrix down below.


The transform matrix what we want is Mwant and it is a inverse of original matrix M and take transpose.

I'm making a motion matching solution.

Motion Matching is very popular now a days. I think motion matching is very similar as feature match system in Game AI field. I applied this system to FIFA when I was in EA Canada. CPU AI could use skill when they find similar situations. I'm not an animation engineer but I'm trying to implement it for fun. :)


Tuesday, November 26, 2019

Use Ue4's DrawDebugSphere in AnimNode

When we use DrawDebugSphere function for debugging, it is working well but when you are trying to use it in anim node's function it will be a problem.

Basically AnimNode will be updated multithreaded so if you want to use DrawDebugSphere in AnimNode then you should use AnimDrawDebugSphere instead.

It will reserve all the command in local TArray and then processed correctly.


Context.AnimInstanceProxy->AnimDrawDebugSphere(outTransform.GetLocation(), 3.f, 32, FColor::Green, false, 1.0f);


Use like above.

Sunday, November 17, 2019

C++ 11 features

This is auto translation of what I summarized.

auto
The auto keyword allows the type of the lvalue to be determined by the type of the rvalue. When using STL, mainly vector <int> :: iterator iter = vectorData.begin (); I had to code it this way, but now I can easily code it with auto iter = vectorData.begin ();


constexpr
constexpr gives you a hint that an expression can be determined at compile time, allowing you to write code that couldn't be optimized or used previously. For example, for arrays, the size must be determined by the compilation type. For example, the following code was not possible.

int array [getPlayerCount () + 1];

At this time, even if getPlayerCount function is a constant expression, it could not be compiled.

int getPlayerCount ()
{
    return 3;
}

However, you can use the above syntax by using the constexpr keyword to give the compiler a hint that this function can be determined at compile time. Like this


constexpr int getPlayerCount ()
{
    return 3;
}

This allows you to use a syntax like int array [getPlayerCount () + 1]. Also as square or cubic

constexpr int cubic (int x)
{
    return x * x * x;
}

In this case, cubic (2) can be optimized because the cubic result is determined by the compilation type and can be directly assigned.

initializer list
The initialization list is the use of {}.
int myArray [3] = {1, 2, 3};

vector <int> myVector = {1, 2, 3}; <-Can be initialized like this.

To use in a function

void foo (const initializer_list <int> & v)
{
    for (auto iter = v.begin (); iter! = v.end (); ++ iter)
    {
        // can access the contents of v with iter
    }
}

uniform initialization
extended curly brace initialization

dog d {3}; If you use, you will find the first choice below first, and if not, it will look in the order of 2 and 3.

class dog {
public:
    int age; // 3rd choice

    dog (int a) // 2nd choice
    {
    }

    dog (const initializer_list <int> & vec) {// 1st choice
    }
};

foreach
In c ++ 11, you can use the following syntax for foreach:

vector <int> myVector = {1, 2, 3};
for (auto element: myVector)
{
    // element is an element of myVector
}

nullptr
The old NULL was equal to zero. Previously, I was using NULL, but I wonder why nullptr appeared as a keyword. When there are two functions as follows:

void foo (int a);
void foo (char * p);

foo (NULL); <-Function calls like this can be ambiguous.

in c ++ 11

foo (nullptr); It can be understood as calling void foo (char * p) function.

enum class
Since the enum itself was an int it could cause problems in the comparison syntax. For example

enum playerState {first, second};
enum itemState {itemA, itemB};

playerState A = first;
itemState B = itemA;

if (A == B) <-true even though it is of a different type.

c ++ 11 has enum class

enum class playerState {first, second};
enum class itemState {itemA, itemB};

When there is

The following syntax if (A == B) causes a compilation error unless you define the == operator of playerState, which allows for stronger type checking.

static_assert
You can use the asset at compile time. For example

static_asset (sizeof (int) == 4); This can be checked at compile time.

delegating constructor

In the case of constructors, there was a pattern of creating and calling a function when there was a common part. For example

class Player
{
public:
    Player () {
    }

    Player (int age)
    {
    }

    Player (int age, int height)
    {
    }
};

If you need common code in the constructor, create a function called init or base to call the common part of each constructor.

    Player () {

        init ();

    }



    Player (int age)

    {

        init ();

    }



    Player (int age, int height)

    {

        init ();

    }


In this pattern, a function called init is a generic function and can be called at other times than at creation time. (You can call it even if you hide it as private.)

c ++ 11 supports constructor delegates.

Player (int age): Player () {… };

Can be called: This way, you can keep the base code in Player () and take advantage of the constructor delegates. And since this is not a regular function, it cannot be called at any other time.

override
In c ++ 11, the keyword override is added, and if you want to override a parent class's function in a child class, you can explicitly specify override to avoid ambiguity.

class player {
    virtual void A (int);
    virtual void B () const;
};

class footballPlayer: public player {
    virtual void A (float) override; <-Compile Error
    virtual void B () override; <-Compile Error
};

final
You can make a class non-inheritable. For example

class Player final
{
};

In this case, the Player class cannot be inherited.

class FootballPlayer: public Player
{
};

Can not. Can be applied to functions

class Player
{
    virtual void foo () final; <-This function cannot be overridden.
};

default constructor
If you define the constructor of the class after that, if you do not create a default constructor separately, an error occurred. You can avoid the error without writing the default constructor by

class Player
{
    Player (int age);
    Player () = default; <-This syntax tells the compiler to create a default constructor.
};

delete
There is an implicit cast in C ++, which can lead to function calls that contain unwanted implicit casts.

class Player
{
    Player (int age);
};

Player player 10;
Player player (3.1415); <-Available.

To prevent this

class Player
{
    Player (int age);
    Player (double) = delete; <-Now Player player (3.1415); An error occurs at
};

lambda
[] (int x, int y) {… };

==============================================

auto
auto 키워드는 rvalue의 타입에 따라 lvalue의 타입이 결정될 수 있도록 한다. STL을 사용할 때 주로 vector<int>::iterator iter = vectorData.begin(); 이런식으로 코딩을 해야 했었는데 이제는 다음과 같이 auto iter = vectorData.begin();으로 쉬운 코딩이 가능하다.

constexpr
constexpr은 expression이 컴파일 타임에 결정될 수 있다는 힌트를 주어 최적화 또는 기존에 사용할 수 없었던 코드를 작성할 수 있도록 해준다. 예를 들어 배열의 경우 사이즈는 컴파일 타입에 결정되어야 한다. 예를 들어 다음과 같은 코드는 불가능했었다.

int array[getPlayerCount() + 1];

이때 getPlayerCount 함수가 다음과 같이 상수식이어도 컴파일이 불가능했다.

int getPlayerCount()
{
    return 3;
}

하지만 constexpr 키워드를 사용해 컴파일러에게 이 함수가 컴파일 타임에 결정될 수 있다는 힌트를 주면 위 구문을 사용할 수 있다. 다음처럼

constexpr int getPlayerCount()
{
    return 3;
}

이렇게 하면 int array[getPlayerCount() + 1]과 같은 구문 사용이 가능하다. 또한 square 또는 cubic과 같이

constexpr int cubic(int x)
{
    return x * x * x;
}

이때 cubic(2)라고 하면 cubic의 결과값이 컴파일 타입에 결정되어 바로 대입 가능하므로 최적화가 될 수 있다.

initializer list
초기화 리스트는 { }을 사용하는것을 말한다. 

int myArray[3] = { 1, 2, 3 };

vector<int> myVector = { 1, 2, 3 }; <- 이렇게 초기화 가능하다.

함수에서 사용하기 위해서는 

void foo(const initializer_list<int>& v)
{
    for ( auto iter = v.begin(); iter != v.end(); ++iter )
    {
        // iter로 v의 내용 접근이 가능하다.
    }
}

uniform initialization
curly brace initialization을 확장 했다.

dog d{3}; 을 사용하면 아래에서 가장 먼저 1st choice를 찾고 못찾으면 순서대로 2, 3순서대로 찾는다.

class dog {
public:
    int age;    // 3rd choice

    dog(int a) // 2nd choice
    {
        
    }

    dog(const initializer_list<int>& vec) {  // 1st choice
    }
};

foreach
c++ 11에서는 foreach를 위해 다음과 같은 구문 사용이 가능하다.

vector<int> myVector = {1, 2, 3};
for ( auto element : myVector )
{
    // element는 myVector의 요소    
}

nullptr
기존 NULL은 0과 같았다. 기존에 NULL을 사용해서 잘 사용하고 있었는데 왜 nullptr이 키워드로 등장했는가 의문이 들 수 있는데 다음과 같이 함수가 두 개 있을 때

void foo(int a);
void foo(char* p);

foo(NULL); <- 이와 같은 함수 호출은 모호할 수 있다.

c++11에서는 
foo(nullptr); 로서 호출하며 이때 호출은 void foo(char* p) 함수를 호출하는 것으로 이해할 수 있다.


enum class

enum 자체가 int 였기 때문에 비교 구문에서 문제가 생길 수 있었다. 예를 들어 

enum playerState { first, second };
enum itemState { itemA, itemB };

playerState A = first;
itemState B = itemA;

if ( A == B ) <- 실제로 다른 타입임에도 불구하고 true가 된다.

c++11에는 enum class가 있으며

enum class playerState { first, second };로 할 수 있으며
enum class itemState { itemA, itemB };

가 있을 때

다음과 같은 구문 if  (A == B)는 playerState의 == 연산자를 정의하지 않은 이상 컴파일 오류가 발생하게 되어 좀 더 강한 타입 검사를 할 수 있게 된다.


static_assert
컴파일 타임에 asset를 사용할 수 있게 된다. 예를 들어

static_asset( sizeof(int) == 4 ); 와 같이 컴파일 타임에 검사 할 수 있도록 해준다.


delegating constructor
생성자의 경우에 공통 부분이 있을 경우에 따로 함수를 만들어서 호출하는 패턴이 있었다. 예를 들어

class Player
{
public:
    Player() {
    }

    Player(int age)
    {
    }

    Player(int age, int height)
    {
    }
};

가 있을 때 생성자에서 공통의 코드가 필요하면 init 혹은 base라는 함수를 만들어 각 생성자에서 호출하여 공통 부분을 호출했다.

    Player() {
        init();
    }

    Player(int age)
    {
        init();
    }

    Player(int age, int height)
    {
        init();
    }

이 패턴에는 init이라는 함수가 일반 함수이며 생성 타임이 아닌 다른 경우에도 호출될 수 있다는 점이다. (private으로 가려놓아도 호출할 수 있긴 하다.)

c++11에는 생성자 델리게이트를 지원한다.

Player(int age) : Player() { … };

와 같이 호출할 수 있다. 이렇게 되면 기본 코드는 Player()에 넣어놓고 생성자 델리게이트 기능을 활용해서 베이스 코드를 유지할 수 있다. 그리고 이것은 일반 함수가 아니므로 다른 타임에 호출될 수 없다.


override
c++11에는 override라는 키워드가 추가되었고 자식 클래스에서 부모 클래스의 함수를 오버라이드 하고 싶은 경우에 명시적으로 override를 적어 주어 모호함을 피할 수 있다.

class player {
    virtual void A(int);
    virtual void B() const;
};

class footballPlayer : public player {
    virtual void A(float) override; <- 컴파일 에러 발생
    virtual void B() override;  <- 컴파일 에러 발생
};


final
클래스를 상속 불가능하게 만들 수 있다. 예를 들어

class Player final
{
};

의 경우에 Player 클래스를 상속할 수 없다.

class FootballPlayer : public Player
{
};

를 할 수 없다.

함수에도 적용할 수 있는데

class Player
{
    virtual void foo() final; <- 이 함수는 override할 수 없다.
};


default constructor
클래스의 생성자를 정의하게 되면 그 이후부터 기본 생성자를 따로 생성하지 않으면 오류가 발생했는데 다음과 같이 작성하면 기본 생성자를 작성하지 않고도 오류를 피할 수 있다.

class Player
{
    Player(int age);
    Player() = default; <- 이 구문으로 컴파일러에게 기본 생성자를 만들도록 지시할 수 있다.
};


delete
C++에는 암시적 형변환이 있는데 이것 때문에 원하지 않는 암시적 형변환이 포함된 함수 호출이 이루어질 수 있다.

class Player
{
    Player(int age);
};

Player player(10);
Player player(3.1415); <- 가능.

이것을 막기 위해

class Player
{
    Player(int age);
    Player(double) = delete;   <- 이제 Player player(3.1415); 에서 에러가 발생한다.
};


lambda
[](int x, int y) { … };

Task in UnrealEngine

 https://www.youtube.com/watch?v=1lBadANnJaw