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.
Friday, November 29, 2019
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.
Use like above.
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) { … };
Subscribe to:
Posts (Atom)
Task in UnrealEngine
https://www.youtube.com/watch?v=1lBadANnJaw
-
Unity released very good FPS example for people and I decided to analysis how they make this. Personally I wanted to show you how I analys...
-
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...
-
If you press a key 'L' in the jupyter notebook then you can see the line number in the editor.