실전 Unity3D Engine Programing 과정 6일차 (2013.07.29(월))


Animation.pptx



금일

- 물리

- 세이더.

- 등등..



아틀라스 : 여러개의 이미지를 하나의 이미지로 모은다. 2048x2048, 안전하게 1024x1024가 좋다
드로우컬은 아틀라스의 갯수로 파악이 가능하다.

스크린 사이즈는 절대값을 넣으면 안된다.
화면의 꼭지점의 기준으로 앵커 형태로 개발해야 한다.

핫트윈, 알트윈을 돌려 보았다.

EGGUI - NGUI - TOOLGUI


## 애니메이션에 대해서
- 사용방법, 캐릭터 적용시 사용방법..

The Animation System supports
animation blending,
블랜딩: 또는 믹싱. 서서이 맞추어준다.
mixing,
믹싱: 해당 트랜스폼에 특정 애니메이션을 넣어주는 것이다. 하나만 만들면 다른 곳에도 붙인다.
additive animations,
애디팅 : .. 사용치 않는다.
walk cycle time synchronization,
애니메이션마다 재생 시간이 다르다. 이것을 노말라이즈하여서 동기화 해서 플레이 할 수 있다.
animation layers,
레이어 : 웨이트와 레이어의 비중을 많이 넣어 주면 애니메이션 썩을 때 비중으로 사용한다.
control over all aspects of the animation playback (time, speed, blend-weights),
mesh skinning with 1, 2 or 4 bones per vertex as well as supporting physically based rag-dolls and procedural animation. 
  손목.. 등 다 따라 올라 온다. 




3D애니메이션은 각 타임라인별로 포지션, 로테이션, 스케일까지 하나하나 숫자 값이 바뀌는 것이다.
숫자의 나열을 시간별로 노출 시킨다.
숫자만 뿌리면 느릴 이유가 없지만, 시작과 끝만 나열하고 나머지는 보간 처리(앞뒤것을)하기 때문이다.
CPU를 많이 잡아 먹는다. 움직이는 연산이다. 
실전에서는 많이 사용하지 않는다.



Clip < = 많이 사용한다. 
Stores keyframe based animations.
length Animation length in seconds (Read Only)
frameRate Frame rate at which keyframes are sampled (Read Only)
wrapMode Sets the default wrap mode used in the animation state.


Once
When time reaches the end of the animation clip, the clip will automatically stop playing.
한번재생
Loop
When time reaches the end of the animation clip, time will continue at the beginning.
반복재생
When time reaches the end of the animation clip, time will ping pong back between beginning and end.
왕복
Reads the default repeat mode set higher up.
Plays back the animation. When it reaches the end, it will keep playing the last frame and never stop playing
끝까지 간다.




State <== wrap 과 쌍벽

In most cases the Animation interface is sufficient and easier to use.

Variables
enabled Enables / disables the animation.
weight The weight of animation
wrapMode Wrapping mode of the animation.
time The current time of the animation
normalizedTime The normalized time of the animation.
speed The playback speed of the animation. 1 is normal playback speed.
normalizedSpeed The normalized playback speed.
length The length of the animation clip in seconds.
layer The layer of the animation. When calculating the final blend weights,   animations in higher layers will get their weights
clip The clip that is being played by this animation state.
name The name of the animation
blendMode Which blend mode should be used?





두개가 썩인다.
Void Update()
{

If(Input.GetAxis(“Vertical”) > 0.2f)

{

  animation.CrossFade(“walk”);

}else

{

  animation.CrossFade(“idle”);

}

}




필히 셋팅해야 한다. 
기본으로 Loop을 사용한다. 나머지는 하나하나 꺼내서 세팅한다. 
Void Start () {

  animation.wrapMode = WrapMode.Loop;

  animation["shoot"].wrapMode = WrapMode.Once;

  animation["shoot"].layer = 1;

  animation.Stop();  //무조건 한번 호출

}



실슴..
void Start () {

    Transform mixTransform;

    mixTransform = transform.Find("root/upper_body/left_shoulder"); animation["wave_hand"].AddMixingTransform(mixTransform);

}



애니메이션 이벤트 <== 특정함수에 특정 이벤트 호출

function PrintFloat (theValue : float) {

  Debug.Log ("PrintFloat is called with a value of " + theValue);

}


최적화

Use one Skinned Mesh Renderer
Your character should use only a single skinned mesh renderer.
한개의 스킨을 사용해야 한다. 차이들을 포함해서
Don't Use Many Materials
You also want to keep the number of materials on that mesh as low as possible.
여러개 사용하지 않는게 좋다.
Reduce Amount of Bones
Medium Desktop games use bone hierarchies with 15-60 bones. The fewer bones you use the faster; with 30 bones you can achieve very good quality on Desktop platforms and fairly good quality on Mobile Platforms..
30개의 본을 사용해라 37이상이면 성능 저하 심하게 발생 최대 35개 좋다.
발 4개 캐릭터는 매우 힘들다... 
Polygon Count
How many polygons you should use depends on the quality you require and the platform you are targeting. Anything between 300-1500 triangles on Mobile Platforms and 500-6000 triangles on Desktop Platforms is reasonable.
옛날 이야기이다. 6000개 이상 넘지 말아라.. 1500 ~ 6000개 이내
Separate Out IK and FK
Separate out inverse kinematics (IK) and forward kinematics (FK). When animations are imported, the IK nodes are baked into FK, thus Unity doesn't need the IK nodes at all.
FK는 지원하지 않는다. 계단 올라가는 뼈대... 지원하지 않는다.
Use Reusable Rigs
Create a rig which you can reuse. This allows you to share animations between different characters.
본 세팅만 같으면 남의 애니메이션을 재 사용할 수 있다. 
Name Bones Correctly

Name the bones correctly (left hip, left ankle, left foot etc.). Especially with characters, naming your bones correctly is very important.
BIP001 등 .. 이름을 바꾸지 않는다. 바이패드 이름 수정하지 마라..




퀄리티..

- Quality Settings.. 간단히 셋팅되어 있다.

- Blend Weights가 중요한 것이다.




## 애니메이션 실습을 해 보자 

1 New Project  > AnimationTest

2. 신 : test

3. 폴더: Scripts

4. AnimationExample 스크립트 만든다.

   - 함수 추가

     void EventTest(int i) 

{

Debug.Log("Event Test Click~ "+i.ToString());

}

5. 큐브 추가 

   포지션은 0.0.0  . 검개 나온다.

6. 빛 추가

   

7. Menu > Windows > Andimation 창을 연다.

- Cube를 선택하고 한다.






8. 애니메이션 창에서 Cube를 선택하고 NewAnimation를 만든다.

9. 레코드 버튼을 누르고 값을 변환해 보고 실행해 본다.


10. 아까 만든 AnimationExample 스크립틀 추가 한다. 




11. 애니메이션 창을 새로 열고 10번째 선택후 이벤트를 추가한다. (키 이벤트 삽입 버튼)

아래 이미지중 3번째 언더바가 키 이벤트 삽입 버튼 4번째 언더바가 해당 이벤트



12. 10번 프레임에서 이벤트를 클릭하면 아까지 만든 메소드명이 뜨고 그곳에 5값을 넣는다.

상기 이미지에서 4번째 언더바를 클릭하면 아래와 같은 창이 나온다.




13. 플레이 해 보면 콘솔에 다음 내용이 출력된다.

Event Test Click~ 5

UnityEngine.Debug:Log(Object)

AnimationExample:EventTest(Int32) (at Assets/Scripts/AnimationExample.cs:18)


이렇게 트랜스폼 중심으로 애니메이션과 스크립트를 만들 수 있다.


## 인터넷 유니티 사이트의 애니메이션 설명을 보자

http://docs.unity3d.com/Documentation/ScriptReference/index.html





## 캐릭터에 애니메이션 

1. New Scen > test 2

2. 오늘자 KnightandBeetle 리소스 패키지를 추가한다. 

- 기사

- 비틀이 있다.

3. 추가한 것에 Knight를 히어알키에 추가한다.

4. 스케일 값을 키우다. 10.10.10, 로테이트는 0.180.0 포지션은 0.0.-5

5. 라이트 추가

6. knight를 선택하고 menu > windodw > animation를 선택한다.

7. 각 동작별로 변경해 보며 플레이 해봐라. 애니메이션 클립 내용을 볼 수 있다.

- 32 프레임이다. 유니티는 .. 맥스랑 다르고, 언리얼은 60프레임 따라서 이창에서 확인해 보는게 좋다.


## 에니메이션과 손을 믹싱과 애드해 보자.

1. AnimationTest 스크립트 추가

using UnityEngine;

using System.Collections;


public class AnimationTest : MonoBehaviour {

public AnimationClip idleAnim;

public AnimationClip attackAnim;

public Transform mixingTransform;

// Use this for initialization

void Start () {


//기본적인것2개추가한다.

animation.wrapMode = WrapMode.Loop;

animation.Stop();

//mixing  해쉬맵에키값을넣으면스테이트값이나오고이것을믹싱한다.

animation[attackAnim.name].AddMixingTransform(mixingTransform);

//= animation["attack_01"] = AnimationState 

animation.CrossFade(attackAnim.name);

}

}


2.  knight에 스크립트를 추가한다.
3. knight의 애니메이션 항목을 펼치고 idle를 선택하면 좌측에 리소스가 노란색으로 노출된다. 
4. 해당 리소스를 선택해서 스크립트 해당 변수에 드래그드롭으로 붙여 준다.



5. kinght을 열어 보면 Bip001 Pelvis가 있고 이것을 knight 스크립트 믹싱 트랜스폼에 붙인다.




6. play해 본다.

7. 다른 것도 미싱트랜스폼에 넣어서 플래이 해봐라.



## Additive를 해보자

1. 스크립트를 수정하자. 이전에 코딩은 주석하고 추가한다.

using UnityEngine;

using System.Collections;


public class AnimationTest : MonoBehaviour {

public AnimationClip idleAnim;

public AnimationClip attackAnim;

public Transform mixingTransform;

// Use this for initialization

void Start () {


//기본적인것2개추가한다.

animation.wrapMode = WrapMode.Loop;

animation.Stop();

//mixing  해쉬맵에키값을넣으면스테이트값이나오고이것을믹싱한다.

//animation[attackAnim.name].AddMixingTransform(mixingTransform);

////= animation["attack_01"] = AnimationState 

//animation.CrossFade(attackAnim.name);

//additive

animation[attackAnim.name].blendMode = AnimationBlendMode.Additive;

animation[attackAnim.name].layer = 10;

animation[attackAnim.name].weight = 1.0f;

animation[attackAnim.name].enabled = true;

animation[idleAnim.name].wrapMode = WrapMode.Loop;

animation.Play(idleAnim.name);

}

}


2. knight의 Idle anim을 move 리소스를 붙여 본다.

3. play해 보면.. 뛰면서 칼을 휘두른다.

layer와 weight을 바꿔 보면 다르게 동작이 될 것이다.

save secen , save project



## RPG를 만들어 보자.

사전지식

- 지형 만들고

- 캐릭터 세우고

- 캐릭터 이동하면서 애니메이션 된다.



1. New Project > RPG

2. 신저장 > main
3. Direciton light 추가 한다.
4. menu > Terrain > create Terrain
5.menu > Terrain > set Resolution의 값을 반띵한다.
6. 포지션은 -500,0,-500
7. 앗셋에서 임포트패키지에서 터레인을 임포트한다.
8. 하이어키에서 터레인 선택하고 인스패트에서 붓모양의 아이콘을 클릭한다.
9. 애드 텍스쳐를 누른다. 그리고 셀랙트를 누른다. GoodDuct를 추가한다. 그리고  add한다.
10. 애드 텍스쳐를 누른다. 그리고 셀랙트를 누른다. Glass를 추가한다. 그리고  add한다.
11. 해당 클라스를 선택하고 신창에서 글을 써봐라. 그러면 잔디밭이 추가된다.
12. 테란을 선택하고 인스패트에서 첫번째 아이콘으로 언덕을 만든다. shit 아이콘 누르면 낮아 진다.

 


13. 터레인에서 5번째 아이콘으로 나무를 심어 보자.


Add 버튼으로 추가한후 땅을 클릭해 보면 나무가 추가된다. 



윈드로 설정할 수 있는데 


다른 아이콘은 잔디도 심을 수 있다.



##

1. KnightandBeetle 패키지 추가

2. Knight 를 추가 하낟. 포시션 0, 0, -5, 로테이션 0, 180, 0, 스케일 10,10,10

3. Kinght 선택 menu > component > phisice > charactor controler



값은  center 0, 0.1, 0  각도 0.05, 높이 0.2

4. 스크립트 추가 Charictor_control

캐릭터와 카메라의 관계에서 카메라가 바라보는 위치에 따라서 캐릭터의 방향이 달라진다.

카메라중심으로 캐릭터를 움직여야 한다.

카메라에서부터 시작해야 한다.

카메라가 어디에 있냐. 카메라의 앞방향의 캐릭터의 앞뒤 방향.. 좌우가 .. 

이것을 정확히 90를 구분하면 좌우가 된다.

백터는 방향을 갖는 두 힘이다. 이렇게 축이 된다.

카메라 포워드 (트랜스.포워드) 를 이용해서 캐릭터의 앞뒤, 직교하는 좌우를 구한다. 

두백터를 더하면 캐릭터의 이동이 나온다.

시간에 따라 방향만 구하면 된다.

이것을 백터의 노멀라이즈라고 한다.

길이가 있는 것을 방향을 구해 준다.




void Move() 

{

//카메라를구한다.

Transform cameraTransform = Camera.mainCamera.transform;

Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);

forward = forward.normalized; //normal vector 1 vector

Vector3 right = new Vector3(forward.z, 0.0f, -forward.x);

//좌우백터.

//움직인다.

}


여기서

Vector3 right = new Vector3(forward.z, 0.0f, -forward.x); // 이것의 의미는 


A.B = 0 일려면, 

AxBx + AyBy = 0;



완성된 스크립트

public float RotateSpeed = 500.0f;

public float VerticalSpeed = 0.0f;

public float gravity = 9.8f;

private CharacterController charactercontroller;

private Vector3 MoveDirection = Vector3.zero;

private CollisionFlags collisionflags;

// Use this for initialization

void Start () {

charactercontroller = GetComponent<CharacterController>();

}

// Update is called once per frame

void Update () {

Move();

}

void Move() 

{

//카메라를구한다.

Transform cameraTransform = Camera.mainCamera.transform;

//좌우백터. 축을구한다.

Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);

forward = forward.normalized; //normal vector 1 vector

//방향을바꿔져서직교이다.

Vector3 right = new Vector3(forward.z, 0.0f, -forward.x);

//움직인다.

float v = Input.GetAxisRaw("Vertical");

float h = Input.GetAxisRaw("Horizontal");

Vector3 targetVector = v * forward + h * right;

targetVector = targetVector.normalized; // normal vector

//벡터를 방향으로옮기기 위해서 방향을바꿔준다.

MoveDirection = Vector3.RotateTowards(MoveDirection, targetVector, RotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 500.0f);

MoveDirection = MoveDirection.normalized;

Vector3 movementAmt = MoveDirection * MoveSpeed * Time.deltaTime;

collisionflags = charactercontroller.Move(movementAmt);

}

}




이동시키는 코드를 스크립트로 짠것이다.

5. knight에 방금 만든 스크립트를 추가한다.



캐릭터를 캐릭터콘트롤을 쓰는게 좋다. 그렇지만 리니지바디보다는 무겁다. 

캐릭터일 때만 사용해라..

collisionflags를 통해서 이 값이 어디에 있는지 알 수 있다.

캐릭터콘터롤러는 기본적으로 그라비티가 없기에 추가해 주어야 한다.



## 애니메이션 시켜 보자


1. 스크립트에 아래 내용을 추가한다.

//애니메이션클립을가져오기위해서퍼블릭으로했다.

public AnimationClip idleAnim;

public AnimationClip walkAnim;

public AnimationClip attackAnim;

public enum CharacterState

{

IDLE = 0,

WALK = 1,

ATTACK = 2,

SKILL = 3,

SIZE

}

상태를 바꿔가면서 애니메이션을 바꿔준다.

스크립트를 빼는 기준은 중복된 코드는 스크립트로 뺀다.

// Update is called once per frame

void Update () {

Move();

CheckState();

AnimationControl();

}

void AnimationControl() 

{

//상태별로애니메이션을변경한다.

switch(state)

{

case CharacterState.IDLE:

animation.CrossFade(idleAnim.name);

break;

case CharacterState.WALK:

animation.CrossFade(walkAnim.name);

break;

case CharacterState.ATTACK:

break;

}

}

void CheckState()

{

//캐릭터콘트롤러는움직이면속도를알려준다

//길이 루크길이.

if(charactercontroller.velocity.sqrMagnitude > 0.1f)

{

//move

state = CharacterState.WALK; 

} else 

{

// stand

state = CharacterState.IDLE;

}

}


총..

using UnityEngine;

using System.Collections;


public class Charictor_control : MonoBehaviour {

public float MoveSpeed = 5.0f;

public float RotateSpeed = 500.0f;

public float VerticalSpeed = 0.0f;

public float gravity = 9.8f;

private CharacterController charactercontroller;

private Vector3 MoveDirection = Vector3.zero;

private CollisionFlags collisionflags;

//애니메이션클립을가져오기위해서퍼블릭으로했다.

public AnimationClip idleAnim;

public AnimationClip walkAnim;

public AnimationClip attackAnim;

public enum CharacterState

{

IDLE = 0,

WALK = 1,

ATTACK = 2,

SKILL = 3,

SIZE

}

private CharacterState state = CharacterState.IDLE;

// Use this for initialization

void Start () {

charactercontroller = GetComponent<CharacterController>();

animation.wrapMode = WrapMode.Loop;

animation.Stop();

}

// Update is called once per frame

void Update () {

Move();

CheckState();

AnimationControl();

}

void AnimationControl() 

{

//상태별로애니메이션을변경한다.

switch(state)

{

case CharacterState.IDLE:

animation.CrossFade(idleAnim.name);

break;

case CharacterState.WALK:

animation.CrossFade(walkAnim.name);

break;

case CharacterState.ATTACK:

break;

}

}

void CheckState()

{

//캐릭터콘트롤러는움직이면속도를알려준다

//길이 루크길이.

if(charactercontroller.velocity.sqrMagnitude > 0.1f)

{

//move

state = CharacterState.WALK; 

} else 

{

// stand

state = CharacterState.IDLE;

}

}

void Move() 

{

//카메라를구한다.

Transform cameraTransform = Camera.mainCamera.transform;

//좌우백터. 축을구한다.

Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);

forward = forward.normalized; //normal vector 1 vector

//방향을바꿔져서직교이다.

Vector3 right = new Vector3(forward.z, 0.0f, -forward.x);

//움직인다.

float v = Input.GetAxisRaw("Vertical");

float h = Input.GetAxisRaw("Horizontal");

Vector3 targetVector = v * forward + h * right;

targetVector = targetVector.normalized; // normal vector

//벡터를 방향으로옮기기 위해서 방향을바꿔준다.

MoveDirection = Vector3.RotateTowards(MoveDirection, targetVector, RotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 500.0f);

MoveDirection = MoveDirection.normalized;

Vector3 movementAmt = MoveDirection * MoveSpeed * Time.deltaTime;

collisionflags = charactercontroller.Move(movementAmt);

}

void OnGUI()

{

GUI.color = Color.red;

GUI.Label(new Rect(10,10,100,20),"state : "+state.ToString());

GUI.Label(new Rect(10,30,100,20),"flag : "+collisionflags.ToString());

}

}



그리고 knight의 각각의 스크립트의 animation에 물리항목을 붙이도록 한다.

완성된 화면이다.


오른쪽에 state는 방향이고 flag는 땅의 상태를 나타낸다.


## 캐릭터의 움직임의 변환 처리
바디디랙션
1. 스크립트에서 
// Update is called once per frame
void Update () {
//아래내용은순서대로한것이다.
Move ();
CheckState();
AnimationControl();
BodyDirection();
}
void BodyDirection()
{
//벨로시티는속도이면서방향이다.
Vector3 horizontalVelocity = charactercontroller.velocity;
horizontalVelocity.y = 0.0f;
if(horizontalVelocity.magnitude > 0.0f)
{
Vector3 trans = horizontalVelocity.normalized;
Vector3 wantedVector = Vector3.Lerp(transform.forward, trans, 0.5f);
if(wantedVector != Vector3.zero)
{
transform.forward = wantedVector;
}
}
}

이렇게 추가하면 방향으로 속도로 애니메이션을 보간한 것이다.
캐릭터가 확돌다가 천천히 돌것이다. move디렉션으로 바디디렉션으로 처리한 것이다. 

120줄에 이동하면서 애니메이션 되는 것은 유니티만 가능한 것이다.

오늘 복습
클립을 가져와서 블랜딩한다.

캐릭터를 띄우기 위해서 카메라

카메라 값을 가져와서 캐릭터를 돌렸다.



내일 할일...
와우카메라. 스프링 카메라..
몬스터 띄우서 몬스터 잡아 보자.