반응형

유니티 스크립트에서는 메터리얼에 담겨 있는 텍스쳐의 다양한 정보를 편집해서 사용할 수 있다.

MainTexture는 maintexture / mainTextureOffset / mainTextureScale  등을 활용하여 크기나 좌표를 편집할 수 있고,

SubTexture들은 String 값을 참조하여 편집할 수 있다.

아래의 코드를 참고하자.

 

m_Renderer.material.mainTextureOffset    = new Vector2(offset.x - ((int)offset.x), offset.y - ((int)offset.y));

m_Renderer.material.SetTextureOffset("_Alpha", offset)//_Alpha 에 담겨 있는 텍스쳐의 좌표를 편집할 수 있다.

m_Renderer.material.mainTextureScale    = m_size;

m_Renderer.material.SetTextureScale("_Alpha", m_size);

반응형
반응형

유니티의 타임 스케일을 사용할 경우 파티클 애니메이션이 터지는 문제가 종종 발생한다.

이 문제를 해결하기 위해 Time.unscaledDeltaTime 함수를 사용하면 문제를 해결할 수 있다.

타임 스케일을 무시하고 출력되도록 하는 함수다.

 

 

public class UnscaledTimeParticle : MonoBehaviour

{

 // Update is called once per frame

    void Update()

{

if (Time.timeScale < 0.01f)

{

particleSystem.Simulate(Time.unscaledDeltaTime, true, false);

}

}

}

반응형
반응형

프로젝트를 진행하면서 파티클 빌트인 셰이더들이 문제를 일으켜 일괄 변환해 줘야 하는 상황이 발생했습니다.

일일이 바꾸는 번거러움을 덜고자 제작한 스크립트 입니다.

 

 

1. 모바일 엔진 셰이더(바뀌어야할 셰이더 선택)

2. 바뀔 셰이더 선택

3. 대상 메터리얼들 선택(폴더 / 파일)

4. 대상 메터리얼중 1번과 동일 셰이더를 찾아 2번으로 바꿔줌~ 일괄 교체~

 

 

 

 

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;

public class MaterialControl : EditorWindow
{  
    public Shader shader1 = null;
    public Shader shader2 = null;

    public Color defaultColor;
    public Color tintColor = new Color(0.5F, 0.5F, 0.5F, 0.5F);

    Shader defaultShader = null;
    Shader changeShader = null;

    static float UIWidth = 500;
    static string OutputPath = string.Empty;
    
    bool IsError = false;
    List<string> tempPathList = new List<string>();
    List<string> InputPaths = new List<string>();
    
    string SearchPattern = "*.mat;*.*";


//    ShaderImporter texFormatSelected = ShaderImporter.GetAtPath;
//    TextureImporterFormat texFormatToChange = TextureImporterFormat.ETC2_RGBA8;

    [MenuItem("RK Tools/Art/MaterialControl")]
    static void InitWindow()
    {
        MaterialControl window = EditorWindow.GetWindow<MaterialControl>();
        window.position = new Rect(100f, 100f, UIWidth, 400f); //  초기 사이즈
        
        window.title = "Save Bundle";
        window.Show();        
    }
    
    void OnGUI()
    {
        FunctionManual();
        ShaderSetting();
        SelectOutPath();
        ClearSelectFolder();
        OutputSelectedFile();
        ConvertAtlasImage();
    }
    
    void FunctionManual()
    {
        GUILayout.Space(16);
        GUI.contentColor = Color.cyan;
        EditorGUILayout.LabelField("폴더를 선택해서 해당 폴더 내의 Shader를 변경합니다.");
        GUI.contentColor = Color.white;
        GUILayout.Space(8);
    }

    void ShaderSetting()
    {
        defaultShader = (Shader)EditorGUILayout.ObjectField("Original Shader", shader1, typeof(Shader));
        changeShader = (Shader)EditorGUILayout.ObjectField("Change Shader", shader2, typeof(Shader));

        defaultColor = EditorGUILayout.ColorField("Tint Color", tintColor);

        if (defaultShader != null)
        {
            shader1 = defaultShader;
            shader2 = changeShader;
            tintColor = defaultColor;
        }


    }

    string prevPath = Application.dataPath;


    void SelectOutPath()
    {
        if (GUILayout.Button("폴더 or 파일 선택"))
        {            
            GetAssetPath_Project();            
            Repaint();
        }
    }
    
    void GetAssetPath_Project()
    {        
        SelectionProcess();
        
        foreach (string path in tempPathList)
        {
            if (InputPaths.Exists(assetPath => (assetPath == path)))
                continue;
            InputPaths.Add(path);
        }        
        IsError = false;
    }
    
    bool SelectionProcess()
    {
        tempPathList.Clear();
        string AssetPath = string.Empty;
        foreach (UnityEngine.Object obj in Selection.objects)
        {
            AssetPath = AssetDatabase.GetAssetPath(obj);
            if (Directory.Exists(AssetPath))
            {
                tempPathList.AddRange(
                    AssetDatabase.FindAssets("t:Material", new string[] { AssetPath }));
                
                for (int i = 0; i < tempPathList.Count; ++i)
                {
                    tempPathList[i] = AssetDatabase.GUIDToAssetPath(tempPathList[i]);                    
                }
            }
            else if (File.Exists(AssetPath))
            {
                char[] separate = new char[] { ';', '*', '.' };
                foreach (string pattern in SearchPattern.Split(separate))
                {
                    if (AssetPath.ToLower().Contains(pattern))
                    {
                        tempPathList.Add(AssetPath.Replace(Application.dataPath, "Assets"));
                        break;
                    }
                }
            }
        }
        return true;
    }
    
    void ClearSelectFolder()
    {
        if (GUILayout.Button("선택 폴더 or 파일 해제"))
        {
            tempPathList.Clear();
            InputPaths.Clear();
        }
    }
    
    Vector2 scrollPos = new Vector2();
    void OutputSelectedFile()
    {
        EditorGUILayout.LabelField("선택 폴더");
        
        EditorGUILayout.BeginVertical("box", GUILayout.Width(UIWidth));
        scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Width(UIWidth));
        
        foreach (string path in InputPaths)
        {
            EditorGUILayout.LabelField(path);
        }
        EditorGUILayout.EndScrollView();
        EditorGUILayout.EndVertical();
    }
    
    
    void ConvertAtlasImage()
    {        
        EditorGUILayout.BeginHorizontal();

        EditorGUILayout.EndHorizontal();

        EditorGUILayout.BeginVertical("box", GUILayout.Width(UIWidth));

        if(GUILayout.Button("선택된 메터리얼을 Change Shader로 변환"))
        {
            ChangeShaderToTargetMaterial();
        }
        EditorGUILayout.EndVertical ();
    }


    void ChangeShaderToTargetMaterial()
    {
        foreach (string path in InputPaths)
        {
            AssetDatabase.ImportAsset(path);

            Material material = (Material)AssetDatabase.LoadMainAssetAtPath(path);


            if (material.shader == shader1)
            {
                material.shader = shader2;

                material.SetColor("_TintColor", tintColor);
            }         
        }
    }
}

반응형
반응형

카메라에 사용된 후처리(Post Processor / Image Effect)를 키로 제어할 수 있게 되면 다양하게 활용이 가능합니다.

 

캐릭터가 강력한 스킬을 쓸때에 블룸효과를 강하게 준다던지, 컷씬을 제작할때 순간적으로 화면을 어둡게 한다던지.

막타연출에서 모션블러나 라디알 효과등을 원하는 타이밍에 쓰기 위해서 애니메이션으로 후처리를 제어하는 방식이

가장 편하고 좋습니다.

 

또한 씬 전환 트랜지션상황에서도 유용하게 사용이 가능합니다.

 

 

1. 카메라에 다양한 후처리 적용하기

- 먼저 카메라에 사용될 다양한 후처리들을 적용하고, 비활성화 시킵니다.

- 라디알블러, 비네팅, 블룸등을 적용시켰습니다.

 

 

 

2. 스크립트 제작하기

- 카메라에 적용된 후처리들을 파싱하여 사용할 수 있도록 스크립트를 제작합니다.

- 사용된 카메라와 카메라에 사용된 후처리 스크립트를 제어하는 코드입니다.

- Animated_PostProcessor 란 이름으로 제작했습니다.

 

using UnityEngine;
using System.Collections;

public class Animated_PostProcessor : MonoBehaviour
{
    public GameObject PostProcessorCtr;  
    public RK_RadialBlur RadialBlurScript;  
    public bool isRadialBlurScript = false;
    [Range(0.0f, 5.0f)]
    public float RadialBlurStrength = 2.2f;
    [Range(0.0f, 3.0f)]
    public float RadialBlurWidth = 0.5f;


    public RK_ScreenOverlay ScreenOverlayScript
    public bool isScreenOverlayScript = false;
    [Range(0.0f, 1.0f)]
    public float ScreenOverlayintensity = 1.0f;
    public enum OverlayBlendMode2 : int
    {
        Additive = 0,
        ScreenBlend = 1,
        Multiply = 2,
        Overlay = 3,
        AlphaBlend = 4,
    }
    public OverlayBlendMode2 ScreenOverlayblendMode;

    public RK_Vignette VignetteScript;
    public bool isVignetteScript = false;
    [Range(-1.0f, 1.0f)]
    public float Vignetteintensity = 0.25f; 


    public Rk_Bloom BloomScript;
    public bool isBloomScript = false;
    [Range(0.0f, 1.5f)]
    public float BloomScriptthreshold = 0.5f;
    [Range(0.0f, 2.5f)]
    public float BloomScriptintensity = 1.0f;


    void OnEnable ()
    {
        PostProcessorCtr = GameObject.Find("PostProcessorCam");
        RadialBlurScript = PostProcessorCtr.GetComponent<RK_RadialBlur>();
        ScreenOverlayScript = PostProcessorCtr.GetComponent<RK_ScreenOverlay>();
        VignetteScript = PostProcessorCtr.GetComponent<RK_Vignette>();
        BloomScript = PostProcessorCtr.GetComponent<Rk_Bloom>();

        LateUpdate();
    }

    void LateUpdate()
    {
        //라디알 블러 처리
        if (isRadialBlurScript == true) {
            RadialBlurScript.enabled = true;
        } 
        else {
            RadialBlurScript.enabled = false;
        }
        RadialBlurScript.blurStrength = RadialBlurStrength;
        RadialBlurScript.blurWidth = RadialBlurWidth;


        //스크린 오버 레이
        if (isScreenOverlayScript == true) {
            ScreenOverlayScript.enabled = true;
        } 
        else {
            ScreenOverlayScript.enabled = false;
        }
        ScreenOverlayScript.intensity = ScreenOverlayintensity;

        if ((int)ScreenOverlayblendMode == 0) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.Additive;
        }
        if ((int)ScreenOverlayblendMode == 1) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.ScreenBlend;
        }
        if ((int)ScreenOverlayblendMode == 2) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.Multiply;
        }
        if ((int)ScreenOverlayblendMode == 3) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.Overlay;
        }
        if ((int)ScreenOverlayblendMode == 4) {
            ScreenOverlayScript.blendMode = UnityStandardAssets.ImageEffects.ScreenOverlay.OverlayBlendMode.AlphaBlend;
        }


        //비네팅 처리
        if (isVignetteScript == true) {
            VignetteScript.enabled = true;
        } 
        else {
            VignetteScript.enabled = false;
        }
        VignetteScript.intensity = Vignetteintensity;


        //블룸 처리
        if (isBloomScript == true) {
            BloomScript.enabled = true;
        } 
        else {
            BloomScript.enabled = false;
        }
        BloomScript.intensity = BloomScriptintensity;
        BloomScript.threshold = BloomScriptthreshold;

    }
}

 

 

 

3. 후처리를 제어할 오브젝트나 파티클에 스크립트와 애니메이션을 붙힙니다.

 

 

 

 

4. 애니메이션으로 후처리 효과들을 제어합니다.

 

 

 

 

5. 완료 테스트 영상

 

 

반응형
반응형

스크립트 공부중..

회사에서 캐릭터 선택창에서 사용될 카메라 회전 구조를 정리하면서 짠 초기 코드지만, 나름 유니티 스크립트 개념을 깨워준 코딩임..ㅋㅋ

 

using UnityEngine;
using System.Collections;

public class FollowCam : MonoBehaviour
{
 
 public Transform target;     //추적할 타겟 게임 오브젝트의 Transform 변수
 public float dist = 10.0f;     // 카메라와의 일정 거리
 public float height = 5.0f;     // 카메라의 높이 설정
 public float dampRotate = 5.0f;     // 부드러운 회전을 위한 변수
 public float TurnSpeed;
 public float camPos;

 Vector3 V3;
 
 private Transform tr;
 // Use this for initialization
 void Start ()
 {
  //카메라 자신의 transform 컴포넌트를 tr에 할당
  tr = GetComponent<Transform> (); 
  TurnSpeed = 2f;
  camPos = 2f;
 }

 void Update()
 {
  Vector3 PositionInfo = tr.position - target.position;     // 주인공과 카메라 사이의 백터정보
  PositionInfo = Vector3.Normalize (PositionInfo);     // 화면 확대가 너무 급격히 일어나지 않도록 정규화~

  target.transform.Rotate (0, Input.GetAxis ("Horizontal")* TurnSpeed, 0);      //마우스 입력이 감지되면 오브젝트 회전
  transform.RotateAround (target.position, Vector3.right, Input.GetAxis ("Mouse Y")* TurnSpeed);     //마우스 Y(Pitch) 움직임 인지하여 화면 회전
  tr.position = tr.position - (PositionInfo * Input.GetAxis ("Mouse ScrollWheel")* TurnSpeed);     // 마우스 휠로 화면확대 축고
 }
}

 

마우스 회전시 카메라 좌우 회전~

오브젝트에 왼쪽마우스를 찍고 돌리면 회전~

훨로 카메라 확대 축고~ 

 

 

아래는 똑같은 형식의 모바일 터치 구현 스크립트

using UnityEngine;
using System.Collections;

public class TouchCameraControl : MonoBehaviour
{
 public Transform charTarget;
 private Camera cameratarget;
 private Vector2 PrevPoint;

 public float moveSensitivityX = 1.0f;
 public float moveSensitivityY = 1.0f;
 public bool updateZoomSensitivity = true;
 public float orthoZoomSpeed = 0.05f;
 public float minZoom = 1.0f;
 public float maxZoom = 20.0f;
 public float perspectiveZoomSpeed = .5f;
 private Transform tr;

 void Start ()
 {
  //카메라 자신의 transform 컴포넌트를 tr에 할당
  tr = GetComponent<Transform> ();
  cameratarget = Camera.main; 
 }

 void Update()
 {
  Vector3 PositionInfo = tr.position - charTarget.position;
  PositionInfo = Vector3.Normalize (PositionInfo);

  if (updateZoomSensitivity)
  {
   moveSensitivityX = cameratarget.orthographicSize / 5.0f;
   moveSensitivityY = cameratarget.orthographicSize / 5.0f;
  }

  Touch[] touches = Input.touches;

  if (cameratarget)
  {
   if (Input.touchCount == 1) {
    if (Input.GetTouch (0).phase == TouchPhase.Moved) {
     PrevPoint = Input.GetTouch (0).position - Input.GetTouch (0).deltaPosition;

     charTarget.transform.Rotate (0, -(Input.GetTouch (0).position.x - PrevPoint.x), 0);
     cameratarget.transform.RotateAround (charTarget.position, Vector3.right, -(Input.GetTouch (0).position.y - PrevPoint.y)*0.5f);

     PrevPoint = Input.GetTouch (0).position;
    }
   }
  }
  if (cameratarget) {
   if (Input.touchCount == 2)
   {
    Touch touchZero = Input.GetTouch(0);
    Touch touchOne = Input.GetTouch(1);

    Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition;
    Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition;

    float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude;
    float touchDeltaMag = (touchZero.position - touchOne.position).magnitude;

    float deltaMagnitudediff = prevTouchDeltaMag - touchDeltaMag;

    tr.position = tr.position - -(PositionInfo * deltaMagnitudediff * orthoZoomSpeed);
   }
  }
 }
}

반응형
반응형

제2강 - Expression 과 Script


*Expression

 

1. Expression?

- 수학적 표현을 통해서 오브젝트의 파라미터나 애니메이션을 컨트롤하는 방법이다.

- 수학을 써야 한다니 겁을 먹을수도 있지만, 일반적인 수준에서의 캐릭터 셋업은 상식적 산수만 알아도 Expression Controller의 강력한 기능을 사용하는 데에는 큰 문제 없다.

- Scrpit Controller와 상대적으로 비슷하지만, 기능은 더 적다. 하지만, 속도가 빠르다는 장점때문에 많이 이용된다.

 

2. 변수와 상수   

- 예약 변수

1) T : ticks, 맥스에서 시간은 1초에 4800틱의 해상도를 가지고 있다. , 초당 1/4800 만큼의 정밀도로 시간이 계산된다. 1초가 30프레임으로 되어 있는데 1프레임안에 160틱이 들어있는 셈이다. 그렇기에 T값을 160으로 나누면 F와 같아진다.

2) F : frames, 타임 슬라이더의 프레임 숫자를 의미한다.

3) S : secs,초 단위의 실제 시간을 의미한다. 3ds max의 디폴트 세팅에서 1초는 30프레임이므로 30프레임의 위치에서는 S 1의 값을 가지게 된다.

4) NT : normalize time, 해당 오브젝트의 애니메이션 전체 구간을 1이라고 가정했을 때 현재 시간을 의미한다. 예를 들어 애니메이션 전체 구간이 300프레임 일 때 현재 프레임이 150프레임이라면 NT 0.5값을 가지게 된다.

- 예약 상수

1) Pi : 3.14159의 값을 가지는 상수이다. ㅠ 라는 기호로 표시되고 파이라고 읽는다. 파이는 지름이 1인 원의 둘레 길이이다. 그렇기 때문에 원의 둘레를 구하는 공식이 2r이 된다. 파이와 원의 둘레를 구하는 공식은 자동차 바퀴가 굴러가는 등 둥근 물체가 자동으로 정확하게 회전하는 리깅을 위해서 꼭 필요한 공식이므로 매우 중요하다.

2) E : 2.71828의 값이고 자연로그의 밑이 되는 자연상수이다. 미분이나 적분 계산에 매우 자주 사용되는 상수이며 자연에서 발견되는 다양한 성장, 감소현상의 계산에 사용된다.

3) TPS : 4800의 값을 가지는 상수이다. 3ds max 1초에 4 8백번의 틱을 생성하는데 내부적으로 애니메이션을 계산하는 가장 기본 단위가 된다.

- 스칼라 변수와 벡터 변수의 개념 깨우치기

X y 좌표에 (2,3)에 표시될 때 2 3은 각각 스칼라이지만, 그래프상 (2,3)은 벡터이다.

크기만 있고 방향이 없을 때 스칼라라고 표기하고, 크기와 방향을 모두 가지고 있을 때 벡터라고 표기한다.

  • Tick Offset : 특정 오브젝트에 시간차를 두고 오브젝트가 따라다니게끔 설정하는 기능. 예를 들어 게임의 검기가 Tick Offset기능을 활용하여 제작이 가능하다.

 

3. 연산자

- 더하기, 빼기, 곱하기, 나누기를 연산자라고 한다. 하지만 Expression에는 이외에도 다양한 연산자가 존재한다. 공식 레퍼런스를 참조해서 연산자의 종류를 분류해보면 다음과 같다.

1) 스칼라 산술 연산자

연산자

예제

설명

+

P + q

더하기

-

P ? q

빼기

-

-p

마이너스 부호

*

P * q

곱하기

/

P / q

나누기

^

P ^ q

P q제곱

**

P ** q

P q제곱, ^연산자와 같음

 

2) 벡터 컴포넌트 연산자

예제

설명

V.x

벡터의 첫 번째 컴포넌트(X)

V.y

벡터의 첫 번째 컴포넌트(Y)

V.z

벡터의 첫 번째 컴포넌트(Z)

 

3) 스칼라 관계 연산자와 논리 연산자

연산자

예제

설명

=

P = q

P q는 같음.

P < q

P q보다 작다.

P > q

P q보다 크다.

<=

P <= q

P q보다 작거나 같다.

>=

P >= q

P q보다 크거나 같다.

|

P | q

논리 OR로서 pq 둘중에 하나라도 0이 아니면 1인된다.

&

P & q

논리 AND로서 pq 둘다 동시에 0이 아니면 1인된다.


 

4) 벡터 산술 연산자

연산자

예제

설명

+

V + W

벡터 더하기

-

V ? W

벡터 빼기

*

P * V

벡터에 스칼라 곱하기

*

V * P

벡터에 스칼라 곱하기

*

V * W

벡터의 내적 연산

X

V x W

벡터의 외적 연산

/

V / p

벡터에 스칼라 나누기


            V W는 벡터이고, p는 스칼라 즉, 숫자이다.         

            위 도표에서 모든 연산의 결과는 다시 벡터가 된다. , V+W를 연산한 결과 역시 벡터라는 뜻이다. 하지만 벡터의 내적 연산만 결과가 스칼라가 된다.

 

        5) 연산의 우선 순위

            R * 0.5 + B + 0.5 (R * 0.5) + (B * 0.5)에서 처럼 괄호로 연산 순서를 묶어주지 않더라도 연산의 우선순위가 정해져 있기 때문에 덧셈을 가장 마지막에 연산하게 된다.

            Expression에서 사용되는 연산의 우선순위는 다음의 도표를 참조하도록 하자.

연산자

우선 순위 설명

-+

예를 들어 -8이나 +25에서 처럼 양수와 음수를 뜻하는 기호

.

벡터의 컴포넌트 연산, 예를 들어 V.x

**^

제곱 연산

X

벡터의 외적(cross)연산

*/

곱셈과 나눗셈

+-

덧셈과 뺄셈

=<> <= >=

관계 연산자

|&

논리 연산자

 

 

4. 벡터의 내적과 외적

    1) 내적 ? 공간상의 각도를 계산하기 위해 사용되는 기능.

    A B 두 개의 벡터가 있을 때 내적을 이용해서 각도를 계산하는 공식은 다음과 같다.

    Acos(unit(A) + unit(B))

    이 공식을 Max Script로 표현하면 acos(dot mormalize(A) normalize(B)) 두 경우 모두 계산 결과는 각도 단위로 계산된다.


    2) 외적 ? 특정 평면의 수직 벡터를 계산하는데 자주 사용. B벡터R벡터가 있을 때 B * R 연산을 한 결과가 W이다. 여기서 W B와도 직각이고 R과도 직각이다. 외적 연산은 이러한 특징에 의해서     평면의 노말(Normal) 방향을 알아내는데 사용되기도 한다.

 

 

5. 함수 응용하기

    -일반적으로 함수를 y = f(x)라는 식으로 표현하는데 빵 제조기에 이런 표현을 적용해 보면 빵 = 빵제조기(밀가루)라고 표현할 수 있다.

    Max 함수는 두 숫자를 입력받아서 둘중에 큰 숫자를 출력하는 함수이고 y = max(a,b)라는 식으로 표현할 수 있다. Max 함수에 의해 a b를 비교하고 더 큰 값이 y에 전달된다

    

    1) 삼각 함수

  • 주로 원운동을 하는 경우에 어김없이 등장한다. 예를 들어 삼각 함수를 통해서 피스톤의 왕복 운동을 애니메이션 할 때 피스톤의 크랭크축의 각도라든지 거리를 계산할 수 있다. 지수함수는 그래프의 특성상 천천히 감속하거나 가속하는 특성을 표현할 수 있다.

  • 삼각함수에 아크(arc)가 붙으면 역삼각함수(Inverse Trigonometric Function)이 된다. 역함수의 대표적인 예는 제곱근이다. 3을 제곱하면 9이고 9를 제곱근하면 3이 된다. 역삼각함수 역시 같은 개념이다. Sin(90) = 1이고 asic(1) = 90 이다.

  • Acos(x), asin(x), atan(x), cos(x), cosh(x), sin(x), sinh(x),tan(x), tanh(x) Expression에서 지원하는 9가지 삼각함수이다.

    

    2) 지수 함수, 로그, 자연로그

  • Y = exp(x) 함수는 지수 함수(Exponential Function)이다.  Y=log(x)함수는 로그함수이고, y = ln(x)는 자연로그 함수이다.

     

        

        3) 라디안과 각도 변환 함수 

      • 3dx max에서 pi3.141592.. 의 값을 가지는 상수인데 이 값이 라디안 개념으로는 180도 각도에 해당된다. 다시 말해서 360도 각도는 라디안 단위로는 6.28319..에 해당된다. 라디안과 각도는 이처럼 각도를 표시하는 단위의 차이이기 때문에 마치 인치와 센티미터으 차이와도 비슷하다.

      • 라디안을 각도로 변환해 주는 함수는 radToDeg()이다. 예를 들어 radToDeg(pi)라는 Expression 180을 리턴한다. 반대로 degToRad()함수는 각도를 라디안으로 변환해 주는 함수이다.  degToRad(180) 3.14159 값을 리턴한다.

         

            

            4) 소수점 올림과 버림 함수

        • Ceil() 함수와 floor()함수는 입력된 숫자에 대해서 무조건 소수점 이하 자리가 사라진다. 예를 들어 버림 함수인 floor에 대해서 floor(1.3)이라고 하면 0.3이 사라지고 1.0의 값이 리턴된다. Ceil() 함수는 천장을 의미하는 올림함수, floor()함수는 바닥을 의미하는 내림함수이다.

            

            5) 일반적인 함수

        • Pow는 제곱함수이다. Pow(p ,q) p^q와 동일한 결과가 된다. Pow(2,3) 8이다.

          Maxscript에서는 pow 2 3 이라고 쓴다. Expression maxscrpit에서 다소 결과값이 다르게 나오는데, 이유는 Expression은 부동소수(float) 연산을 하지만, Max Script는 입력되는 값에 의해서 정수(integer)연산을 할 수도 있다는 점을 조심해야 한다.

        • Sqrt(p)

          sqrt함수는 제곱근 함수이고 square root라는 뜻이다. Sqrt(9)를 연산하면 3이 반환된다. 이 함수는 Max Script Expression에서 동일한 사용이 가능하다.

        • abs(p)

         abs함수는 절대값이라고 부른다. P에 입력된 값이 양수이면 그대로 p를 반환하지만 음수인 경우에는 p를 양수로 변환한 뒤 변환(return)한다. abs(8) abs(-8)은 둘다 8을 리턴한다.

        • min(p,q) , max(p,q)

          min함수와 max 함수는 함수 이름에서 역할을 쉽게 짐작할 수 있다. Min은 최솟값이고 max는 최대값이다. 예를 들어 min(3,4) 3을 리턴하고 max(3,4) 4를 리턴한다.

          Max Script에서는 amin , amax 라는 함수가 유사한 기능을 한다.

          myMin1 = amin # (5,1,4,2,8)

          myMin2 = amin 5 1 4 2 8

        • mod(p ,q)

         이 함수는 p q로 나눈 나머지 값을 리턴하는 함수이다.

        P

        Q

        Mod(p, q)

        설명

        13

        1

        0

        13 / 1 =13,나머지 0

        13

        2

        1

        13 / 2 =6,나머지 1

        13

        3

        1

        13 / 3 =4,나머지 1

        13

        4

        1

        13 / 4 =3,나머지 1

        13

        5

        3

        13 / 5 =2,나머지 3

        13

        6

        1

        13 / 6 =2,나머지 1

        13

        7

        6

        13 / 7 =1,나머지 6

        13

        8

        5

        13 / 8 =1,나머지 5

         

         

           

              6) 조건 함수 

            • If 함수

              If(p ,q, r)을 풀어서 이야기 하면 p를 검사해서 맞으면 q이고 틀리면 r이다. 라고 이해하면 된다.

            • 논리 연산자

              P | q : 논리 OR로서 p q 둘중에 하나라도 0이 아니면 1이 된다.

              P & q : 논리 AND로서, p q 둘 다 동시에 0이 아니면 1이 된다.

              논리 OR은 한글 표현으로는 논리 합이라고 부른다. 그리고 논리 AND논리 곱이라고 부른다. 다시 풀어서 쓰자면..

              P | q : p q 둘중에 하나라도 참(true)이면 1이 된다. - OR

              P&q : p q 둘다 참(true)이면 1이 된다. ? AND

            • vif 함수

              이 함수의 사용법은 vif(c, v1, v2)이다. If 함수와 매우 유사한 함수로서 c가 참이면 V1이 결정되고 거짓이면 V2로 결정된다. 이 때 V1 V2에는 벡터가 사용된다는 점이 if 함수와의 결정적인 차이점이다.

               

               

                  7) 벡터 함수 

                • Length(v)

                  Length함수는 벡터의 길이를 리턴하는 함수 인데 원점으로부터 해당 오브젝트까지의 길이(length)를 리턴한다. 리턴되는 값은 벡터가 아니라 스칼라(숫자)라는 점을 조심해야 한다. Length([10,0,0])의 값은 Length([10,0,0])이 되고, length([10, 10, 0])의 결과는 14.1421이 된다. X , y의 위치의 대각선 길이 값을 구하게 된다. 그런데 이 함수는 무조건 월드 중심으로 계산하기 때문에 활용 범위가 그다지 많지는 않다. 하지만 이런경우에 length(오른손 위치 ? 왼손 위치)를 해주면 오른손과 왼손의 길이를 알 수 있다. 벡터의 뺄셈에 의해서 두 오브젝트의 거리에 해당하는 새로운 벡터를 만드는 것.

                • Comp(V , i)

                  컴포넌트 함수는 V 벡터의 i번째 컴포넌트를 리턴한다. I 0이나 1, 그리고 2의 값을 입력받는다. 예를 들어서 A라는 벡터 변수에 [10,20,30]이라는 값이 들어 있다고 할 때, comp(A , 0) 이라고 연산을 하면 10의 값이 리턴된다. Comp(A , 1)이라고 연산을 하면 20의 값이 리턴된다. Comp(A , 2)이라고 연산을 하면 30의 값이 리턴된다.

                • Unit(V)

                  벡터 V의 방향은 유지한 채 길이가 1인 벡터를 리턴한다. 다시 말해서, 벡터의 길이를 1로 변경해 주는 함수인 것이다. 이 녀석은 말로 설명이 잘 안되니, 개념을 잡자_049.Max 파일을 참조하길 바란다.(동영상 개념을 잡자_동영상_014.wmv)
                   

                 


                **Max Script**

                1. 스크립트 리스너

                - 간단한 Script 구문을 실행하고 리턴되는 값을 모니터링 하는 기능

                - Print format 등 출력에 관계되는 함수를 사용할 때 출력될 스트림을 지정하지 않으면 Script Listener로 출력된다.

                - 디버깅 툴

                   


                   2. as 

                    - 형 변환을 시켜주는 코드

                    - Ex> 1.4 as integer -> 1   ,   3 as float -> 3.0    ,   $.pos as string -> “(12,15,0)”

                    - 데이터 형 변환 외에도 컬렉션 타입 변환에도 사용된다. 예를 들어 a = geometry as array 라는, Script geometry라는 오브젝트 셋 컬렉션을 배열 형태의 컬렉션으로 변환시켜 준다.

                       


                      3. 매크로 스크립트

                       - 이 기능을 통해서 키보드 단축키, 툴 바, 쿼드 메뉴, 일반 메뉴 등에 등록해서 편하게 사용할 수 있다.

                      - 스크립트 레퍼런스 문서 어떻게 읽는가?

                      문자

                      영문 표기

                      한글 표기

                      의미

                      […]

                      Bracket

                      대 괄호

                      선택적, 사용해도 되고 안해도 됨

                      {…}

                      Brace

                      중 괄호

                      사용하지 않거나 여러 번 사용 가능

                      {…}+

                      Brace +

                      중 괄호 +

                      최소 한번 이상, 여러 번 사용 가능

                      ( )

                      Parenthesis

                      둥근 괄호

                      묶어주는 기능

                      <rule></rule>

                      Angile Bracket

                      꺽쇠 괄호

                      규칙, 예를 들어<string></string>은 문자열을 의미

                      |

                      Vertical Bar

                      수직선

                      수직선으로 분리된 아이템중 하나를 선택

                       

                      - MacroScript BoxTest category : “My Category” tooltip : “Default Box” (box () )

                      라고 리스너에서 실행하면 Default Box라는 이름의 Macro Script가 등록된다.

                      - Macro Script의 문법

                      • Name : macro Script를 정의할 때 구분짓는 이름이다. 일반적으로 함수나 롤아웃 등을 정의할 때 함수나 롤아웃의 이름은 변수의 속성을 가지고 있어 롤아웃 외부에서 내부로접근이 용이하다.

                      • Category : customize user interface 창에서 구분되는 카테고리의 이름이다.

                      • ButtonText : 버튼에 표시될 텍스트이다.

                      • Icon : 버튼에 표시될 아이콘이다.

                      • Tooltip : 버튼의 툴팁이다. Customize User Interface 창에서 이 이름으로 보여지게 된다.


                       

                           4. 예약어

                           

                            - Max Script에는 특수한 기능을 하는 명령어들이 미리 만들어져 있는데 이것을 예약어라고 한다.

                            - 예약어는 크게 3종류로 나눌 수 있다.

                            • Language Reserved Keywords (Script 언어를 구성하는 예약어)

                            • Punctuation and Symbols (구분과 기호)

                            • Reserved Global Variables (글로벌 예약 변수들)


                             

                                 5. 변수(variable)

                                 

                                  - 말 그대로 변할 수 있는 수이다. 다음문구를 예로 들어보자.

                                  - “오늘 바람이 유난히 많이 부는군요. 세계 기록 수립에는 바람이 변수 입니다.”

                                  • 경기장에 부는 맞바람이 초속 0~10m 사이, 맞바람이 초속 1m가 강해질 때마다 선수들의 100m 달리기 기록이 0.01초씩 늦어진다고 가정했을 때 의 공식

                                  • (달리기 기록) = (선수 최고 기록) + (wind * 0.1)


                                  - 이름(Names)

                                    • 첫 문자는 영어 알파벳과 “_” 문자로 시작되어야 한다.

                                    • 두 번째 이후 문자에는 영어 알파벳과 “_” 문자와 숫자를 사용할 수 있다.

                                    • 영어 알파벳은 대소문자 구분을 하지 않는다.

                                    • 잘못 사용된 예 

                                              1) 1objet : 첫 문자가 영어가 아님

                                                2) Pressed? : 특수문자 ?가 사용되었음.

                                                3) a big number : 이름에는 공백을 사용할 수 없음     

                                     4) seven(7) : “(“ 등의 문자를 사용할 수 없음;.

                                   

                                    - 변수의 종류 

                                                1) 일반 변수 : a = “hello” , a = 1 , a = [10,20,30]  등등..

                                     2) 배열 변수 : 배열의 개념을 설명하기 위해 지하실 락커를 예를 들어보자.

                                     1번락커에 가방, 2번락커에 도시락, 3번락커에 우산, 4번 락커에 신발을 넣었다. 락커[1]은 가방, 락커[2]는 도시락, 락커[3]은 우산, 락커[4]는 신발이 되었다.

                                             락커.count 4가 된다.

                                             비워라 락커 명령은 전체 락커를 비우게 된다.

                                             비워라 락커[3] 명령은 3번의 우산만 비우는 명령이 된다.

                                     Append 락커 코끼리 라고 치면 코끼리가 들어있는 락커 하나가 뒤에 추가된다.

                                     

                                                            2-1) 배열의 사용

                                     

                                      380P~382P를 집중적으로 읽으며 이해하자. tempPos 를 이용한 배열변수 사용.


                                     

                                         

                                        6. 구조체(Structure) 

                                          • Show $.material 이라고 치면 material 의 다양한 프로퍼티들이 나온다. 그중에 디퓨즈맵이 있는데 show $.material.diffusemap 이라고 치면 디퓨즈맵에 대한 프로퍼티를 볼 수 잇다.  이처럼 특정 오브젝트를 정의하는 수 많은 특징들을 계층 구조 형태로 구성한 것을 클래스라고 부른다. 실제로 클래스는 단순히 프로퍼티 뿐 아니라 해당 오브젝트와 관련된 함수도 포함되는 개념이다. 383~385페이지를 정독하기!!

                                           

                                           

                                             

                                            7. 기준 좌표계와 Max Script 

                                              Script

                                              설명

                                              $.pos

                                              선택된 오브젝트의 월드 포지션이 리턴된다.

                                              $.transform.pos

                                              선택된 오브젝트의 월드 포지션이 리턴된다. 바이패드 오브젝트에도 사용할 수 있다.

                                              $.transform.controller.Position

                                              선택된 오브젝트의 로컬 포지션이 리턴된다.

                                              • Max Script에서 바이패드의 로컬 트랜스폼을 ExposeTransform 헬퍼의 도움 없이 알아내기 위해서는 matrix3라는 행렬 데이터를 사용해야 한다.

                                              • Matrix3라는 행렬 데이터는 오브젝트의 위치, 회전, 스케일 정보를 모두 가지고 있는 데이터 형태이다.

                                              • 부모 역할을 P 오브젝트(parent)가 있고, 자식 역할을 하는 C 오브젝트(Child)가 있을 때 C의 로컬 트랜스폼을 알아내는 공식은 다음과 같다.

                                                C의 로컬 트랜스폼 = $C.transform * (inverse $P.transform)

                                                월드 좌표(월드로 부터의 거리)와 로컬 좌표(부모로부터의 거리)에 대해서 확실히 알고 넘어가자!!

                                                 

                                                 

                                                8. 데이터 형(Data type) 

                                                  - 숫자(Number Values)

                                                  Number 형은 우리가 익히 알고 있는 숫자 형태이다.  기본적인 사칙 연산과 제곱 연산이 ‘^’ 연산이 가능하다.

                                                   

                                                              1) Integer : 소수점이 없는 정수형

                                                           2) Float : 소수점으로 표현되는 부동소수형

                                                   

                                                  - 문자열(String Values)

                                                  • 문자 형태의 데이터. Messagebox 1은 에러나지만, messagebox “1”은 정상 출력된다.

                                                    1 as string -> “1”

                                                    1 as integer -> 1

                                                  ​- Point3 , Point2 Vales


                                                  Point3 x,y,z 세 개의 축으로 표현되는 3차원 공간의 한 점을 의미한다. 그리고 point2 x,y 두 개의 축으로 표현되는 2차원 공간의 한 점을 의미한다. 예를 들어 $.pos 등에 의해서 리턴되는 포지션 값이 Point3 데이터이다.

                                                  Point3 데이터의 특이한 점은 Color 데이터 형과 형 변환이 된다는 점이다.

                                                  (color 255 0 0) as point3 [255, 0 ,0]으로 리턴된다.


                                                  - Matrix3 Values ? 중요!

                                                  Matrix3 데이터는 리깅을 하기 위해서 필요한 Script 지식의 정점에 있는 데이터 형이다. 벡터나 Point3 데이터는 공간상의 위치만을 표현하는 데이터지만, Matrix3는 위치, 회전, 스케일을 모두 포함하는 데이터이다.

                                                  • 모든 오브젝트의 위치, 회전, 스케일 정보는 Matrix3에 모두 들어있다.

                                                  • 특정 오브젝트의 트랜스폼(Transform) Matrix3를 곱하면 위치, 회전, 스케일을 변경할 수 있다. 이 때 곱하는 앞 뒤 순서가 중요하다.

                                                  • Matrix3 데이터는 오브젝트 자신의 위치, 회전, 스케일을 표현하는데 사용되기도 하지만, 자기 자신의 각도나 위치 등을 다른 오브젝트에 반영하는데 사용되기도 한다.

                                                  • Matrix 연산법 숙지하기(행렬연산)

                                                  - ​행렬 연산

                                                  • 행렬 표기에서 언제나 행이 첫 번째, 그 다음이 열이다.

                                                  • 게임 프로그래머를 위한 기초수학과 물리에서 제5장 행렬연산을 공부할 것!

                                                     

                                                   


                                                   

                                                     

                                                    9. 쿼터니언과 오일러

                                                     

                                                    쿼터니언과 오일러는 3D 공간에서 물체의 회전 정보를 표시하는 방법이고 서로 장단점을 가지고 있다.

                                                     

                                                    - 오일러

                                                    • 기준 좌표계 

                                                    Script

                                                    기준 좌표계

                                                    바이패드 가능 여부

                                                    읽기

                                                    쓰기

                                                    기타

                                                    $.Position

                                                    World

                                                    X

                                                    O

                                                    O

                                                    $.Pos로 생략 가능

                                                    $.transform.Position

                                                    World

                                                    O

                                                    O

                                                    X

                                                     

                                                    $.tranform.controller.Position

                                                    Local

                                                    X

                                                    O

                                                    O

                                                    사용 권장

                                                    $.Rotation

                                                    World

                                                    X

                                                    O

                                                    O

                                                    값이 뒤집힌다.

                                                    $.transform.Rotation

                                                    World

                                                    O

                                                    O

                                                    X

                                                     

                                                    $.transform.controller.Rotation

                                                    Local

                                                    X

                                                    O

                                                    O

                                                    사용 권장

                                                     

                                                    • 계층구조에 속해 있는 오브젝트를 월드 좌표계 형식으로 회전시켜주는 함수

                                                      Function setWorldEuler obj euler =

                                                      ( var = $B.transform

                                                      $B.transform = (eulerAngles 90 0 0) as matrix3

                                                      $B.pos = var.pos)

                                                      위와 같은 함수를 쓰고 setWorldEuler $B (eulerAngles 90 0 0) 라고 실행하면 계층구조나 이전 방향에 상관없이 월드 좌표계를 기준으로 x축으로 회전된 방향이 된다.


                                                    - 쿼터니언연산과 slerp(Spherical Linear Interpoltion)함수

                                                    쿼터니언은 수학적으로 쉽지 않은 개념이고 관련된 명령어들도 쉽지 않은 것들이 많다. 하지만 리깅을 위해서 쿼터니언과 관련 명령어들을 모두 알고 있을 필요는 없고 몇 가지 필요한 것들만 알고 있으면 된다. 그 중에 가장 핵심적인 명령어가 slerp이다.

                                                    Slerp : 두 개의 쿼터니언 각도의 중간 각도를 계산해주는 명령어이다. 예를 들어서 캐릭터의 팔꿈치나 무릎에 있는 중간 각도의 본을 Script로 제어하기 위해서는 필수적인 명령어이다.

                                                    쿼터니언은 개념적으로 위치 벡터를 이용해서 회전 각도를 표현하는 방식인데 부적절한 쿼터니언 값을 사용해서 slerp 계산을 하게 되면 중간 회전 각도를 계산할 때 가까운 쪽이 아니라 더 먼쪽으로 계산을 하게 된다.

                                                     slerp함수를 제대로 쓰기 위해서는 아래의 함수가 정의 되어야 한다.

                                                    Function MakeClosest quat1 quat2 =

                                                    (     Local dot = quat1.x * quat2.x + quat1.y * quat2.y + quat1.z*quat2.z + quat1.w+quat2.w

                                                    If (dot < 0.0) do (quat2.x = -quat2.x ; quat2.y = -quat2.y ; quat2.z = -quat2.z ; quat2.w = -quat2.w)

                                                    Quat )

                                                    • 쿼터니언은 길이가 1인 공간 벡터 형태로 회전 방향을 표현하게 되는데 모든 방향을 다 표현하면 반지름이 1인 구 형태가 된다. 그리고 slerp함수는 가상의 최단거리에서 정확하게 중간 위치를 알아내게 된다.

                                                       

                                                       

                                                      10. 함수(Function) 

                                                        - ‘함수? ‘특정 기능을 하는 명령어라고 할 수 있다. 예를 들어 abs라는 함수는 절대값을 계산해 주는 함수인데 abs -5를 실행하면 마이너스가 사라지고 절대값(absolute) 5가 리턴된다.

                                                        함수 예제 코드

                                                        fn Factorial n =(  K = 1

                                                                              for i=1 to n do (K=K*i)

                                                                              return K)

                                                        Factorial 10

                                                        결과값은 3628800


                                                        - Return


                                                        함수’를 종료할 때 사용되는데, 많이 생략되어 사용된다.

                                                        종종 예외 상황에 대한 처리로 사용되기도 한다. 예를 들어 Factorial 8.1 이라든지 심지어는 Factorial “가 나 다” 이런식으로 정수 값이 아닌 다른 데이터 형이 입력되면 Factorial 함수는 비정상적인 상황을 맞이하게 된다. 특히 ‘가나다’가 입력된 경우는 파라미터 ‘가나다’가 for 명령어에서 사용되면서 Script 에러가 발생된다.


                                                        - 함수의 문법과 파라미터(Parameter)


                                                        함수라는 것 자체가 중요하기도 하지만 공식 Max Script 레퍼런스를 보는 방법도 매우 중요하기 때문에 이 문법이 도대체 어떤 뜻인지 하나씩 자세히 살펴보도록 하자.


                                                        The syntax for <function_def></function_def> is:

                                                        [mapped] ( function | fn) <name> </name>{ <parameter> </parameter>} = <expr> </expr>

                                                        in which <name></name> is the name of the function.    

                                                        The optional sequence of <parameter></parameter> can be one of:

                                                        <name></name>
                                                        <name></name>: [<operand>] --keyword parameter with optional default value  

                                                         

                                                          • [mapped] ? 함수의 파라미터에 objects 라든지 배열 등 컬렉션을 적용할 경우 mapped function… 이런 식으로 함수를 정의해서 사용해 줘야 한다. Mapped는 대괄호 ‘[ ]’로 묶여 있는데 대괄호는 선택적(optional)이라는 뜻이다. 그렇기 때문에 mapped 없이 그냥 function 명령어를 사용해도 무방하다. Mapped는 상당히 전문적인 개념이라서 대충의 의미 정도만 파악하고 있어도 된다.

                                                          • <name>- </name>함수 이름을 뜻한다. Script Controller변수편에서 설명된 이름(Names)의 규칙대로 함수의 이름을 만들어야 한다. 대체로 예약어만 조심한다면 크게 문제 되지 않는다.

                                                          • {<parameter></parameter>} ? 중괄호 ‘{ }’로 표기 되었다. Script 문법에서 중괄호로 표기된 내용은 여러 개 중복해서 사용될 수 있다는 뜻이다. 함수의 내용에 따라서 얼마든지 늘어날 수 있고, 없을 수도 있다.

                                                          • ‘=<expr>’</expr>은 실제 함수 내용에 해당된다.

                                                            Fn Factorial n =

                                                            Fn Factorial n:10 =

                                                            Fn Factorial n: =

                                                          • “:” 콜론없이 사용한 방식이 일반적인 방식이고, 순서 방식의 파라미터이다. 두 번째와 세 번째 방식은 콜론(‘ : ’)을 사용함으로써 키워드 방식의 파라미터가 되었다.


                                                        - 변수의 스코프

                                                        변수 마다의 활동 영역을 말한다. 즉, A 영역에서 활동하는 변수와 B 영역에서 활동하는 변수의 이름이 같아도 영역이 다르면 서로 다른 변수로 취급된다는 뜻이다. 상황에 따라 로컬 변수로 선언할지 글로벌 변수로 선언할지 잘 선택해야 한다.

                                                        상위 레벨의 스코프에서 생성된 변수는 하위 레벨의 스코프에서 자동으로 인식이 된다.

                                                        • 스코프의 레벨 ? 새로운 스코프가 생성되는 경우들 

                                                                    1) Sript 파일이나 Listner에서 최상위 레벨(Top-level)의 소괄호 ‘(‘ 열기

                                                                  2) 함수 본체(Function body)가 시작될 때

                                                                  3) For 반복문이 시작될 때

                                                          ​4) 유틸리티(utility), 롤아웃(rollout), 우클릭 메뉴, Macro Script 등이 시작되거나 선언될 때

                                                                  5) When 구문이 시작될 때 

                                                        • Lexical Scoping

                                                          Lexical Scoping은 하위 레벨의 스코프에서 local을 명화하게 명시함으로써 동일한 이름의 변수를 하위 레벨 전용으로 사용할 수 있게 해 주는 기능이다.

                                                        • 알고 있어야할 스코프의 개념 

                                                         1) 함수에서 사용된 변수는 로컬 변수이기 때문에 서로 다른 함수간에 변수 이름이 중복되더라도 상관없다.

                                                                 2) 변수가 최초 사용할 때 가급적이면 앞에 local 키워드를 삽입한다.

                                                                 3) 글로벌 변수는 되도록이면 사용을 자제한다.

                                                          

                                                           

                                                          11. Script Controller는 함수(Function)이다.

                                                           

                                                          -Script Controller는 함수와 거의 비슷한 개념이다. 스코프에 의해서 로컬 변수가 사용되는 점이라든지 최종적으로 리턴되는 방식 역시 함수와 동일하다.

                                                           

                                                          - 자세한 내용은 책과 예제를 참조하자! (443P~447P)

                                                           

                                                          반응형
                                                          반응형

                                                           회사 모델러들의 요청으로 모델링 관리를 펴하게 해주는 툴을 제작해 봤습니다.

                                                           

                                                          이 툴에서 사용할 수 있는 기능들 간단 요약

                                                          1. 파일 서치 기능

                                                          2. 맥스파일을 열어보지 않고 고퀄의 프리뷰와 다양한 파일 정보(갯수, 크기, 버텍수등..) 로 미리 확인 가능

                                                          3. 다중 파일을 지정된 폴더에 동시 익스포트 가능

                                                          4. 다중 선택 파일을 지정한 폴더에 자동으로 익스포트 가능

                                                          5. FBX를 맥스로 맥스를 FBX로 변환이 매우 간단함(여러파일 동시에도 가능)

                                                          6. 대규모 파일관리와 여러 프로젝트를 동시에 관리하게 용이함



                                                          * 간단한 기능 설명

                                                          제일 먼저 대표로 사용될 폴더를 지정해 줍니다.

                                                          모델링 라이브러리 SVN 폴더를 지정하시면 됩니다.

                                                           

                                                          (1) 간단한 익스포트

                                                          -단일 파일 익스포트 방식

                                                          익스포트 폴더를 지정하시고 난후 오브젝트를 선택하거나 파일을 선택한후, 혹은 Export나 ExportSelected 버튼을 눌러주시면

                                                          지정한 익스포트 폴더에 바로 익스포트가 진행됩니다.

                                                           

                                                           

                                                           

                                                          ** 익스포트 폴더를 Export Path로 지정하지 않고, 폴더 리스트중에 선택하셔서 지정하실 수도 있습니다.

                                                          Path Clean 버튼을 눌러 Export Path를 초기화 한후 New Folder로 원하시는 폴더를 만들고 폴더를 선택하신 다음 Export 버튼을 누르면 해당 폴더에 익스포트 됩니다.

                                                          --->

                                                           

                                                          -- 다중 익스포트 방식

                                                          파일 리스트에서 익스포트를 원하는 파일들을 모두 선택후 Export Path로 경로를 설정하시면 선택한 파일들 모두 Export가 한방에 진행됩니다.

                                                           

                                                           

                                                           

                                                           

                                                          (2) 간단한 파일 서치와 편리한 프리뷰 기능

                                                          예 -> ART에 사용된 나무 데이터만 추려서 보고 싶을때..

                                                          ART 폴더 지정 -> tree 키워드 입력후 엔터 -> 파일에 대한 정보 출력.

                                                          검색된 파일의 Open, Merge, Export 등이 가능합니다. 

                                                           

                                                           

                                                           (3) 간단한 파일변환 FBX -> MAX   or  MAX -> FBX

                                                          FBX를 MAX로 변환할 파일들을 리스트뷰에서 선택한 후 SAVE 버튼을 누르면 FBX가 있는 폴더에 그대로 MAX 로 저장되면서 파일이 생성됩니다.

                                                           

                                                           

                                                          (4) 맥스에서 씬 배치후 씬 그대로 유니티나 언리얼로 옮겨오기가 간편함

                                                          맥스상에서 터레인과 오브젝트등을 배치한 후 전부 선택한 Export Selected 버튼을 누르면 그대로 각 오브젝트별로 익스포트를 진행해 줍니다.

                                                          FBX  이름은 각 오브젝트 이름으로 지정됩니다.

                                                           

                                                           

                                                          위 과정을 거쳐 익스포트 하시면 Export Path 로 지정한 폴더에 각 이름별로 알아서 FBX 파일이 뽑히게 됩니다.

                                                          그후에 아래 파일들을 유니티로 그대로 임포트해오면 맥스 씬에 있는 그대로 불러와지게 됩니다.  

                                                           

                                                           

                                                           

                                                           

                                                          ModelingLibrary.mse

                                                          반응형
                                                          반응형

                                                          1. 먼저 Newtonsoft.dll 파일을 구해서 원하는 폴더에 넣어 놓습니다. Dll 이 있어야 편하게 파싱이 가능합니다.

                                                          - 처음에 DLL이 없다보니까 텍스트의 라인과 위치까지 세면서 코드를 짜느라 굉장히 애먹었는데, DLL로 파싱하니 굉장히 간단하게 코드가 마무리되었습니다.

                                                          구글에 치시면 금방 찾으실 수 있습니다.

                                                           

                                                          2. 사용될 스크립트 코드에 DLL 을 로드 하는 구문을 넣어 줍니다.

                                                          위 경로에 DLL을 넣고 아래 코드를 넣어주면 DLL을 로드해 옵니다.

                                                           

                                                           

                                                           

                                                          3. JSON이 사용될 부분에서 파싱한다는 코드를 넣어줍니다.

                                                            local data ="" 

                                                            if filePath == undefined then
                                                             return 0

                                                            fs=openFile filePath mode:"r"

                                                            while not eof fs do
                                                            ( 
                                                             jsonString = readline fs
                                                             append data jsonString   ---> 제이슨 스트링을 data 라는 텍스트 어레이 변수에 담으면 제이슨을 읽어옵니다.
                                                            )

                                                            o = JObj.parse data -> 읽어온 제이슨 데이터를 파싱해주는 구문입니다.

                                                           

                                                           

                                                          4. 파싱이 완료되면 아래같은 간단한 코드로 원하는 부분의 텍스트 정보를 읽어오게 됩니다.

                                                             sidelength = ((o.item["gridCells"].item[1].item["sideLength"].value) as integer)
                                                          --> 제이슨 데이터의 GridCells의 첫번째 아이템에서 sidelength의 값을 읽어오라는 코드입니다.




                                                          위 과정을 통해 유니티의 그리드 정보를 json으로 읽어와서 그대로 맥스 스크립트로 옮겨올 수 있었습니다.

                                                           

                                                          test.json

                                                          UnityGridViewer.mse

                                                           

                                                           

                                                          반응형
                                                          반응형

                                                          회사 모델러들이 맥스에서 엔진 버텍스를 바로 보고 싶다는 의견이 있어 혼자서 고민하며 만들어봤습니다.

                                                          여러가지 이유로 엔진과 동일한 수는 얻어 올 수 있지만, 아래와 같은 방법으로 비슷한 수치는 얻어 올 수 있었습니다.

                                                          첨부파일을 받으시면 사용하실 수 있습니다.



                                                          1. 모델링 버텍스가 아닌 언렙 버텍스를 계산하라!

                                                          언렙을 사용하면 한 버텍스에 두개의 UV정보를 가지게 되는 경우가 생기므로 이 때 버텍스가 증가하게 됩니다.

                                                           

                                                           

                                                          따라서 6200개의 버텍스의 모델링이

                                                           

                                                          언렙된 버텍스의 수를 계산하면 8500여개가 됩니다.

                                                           

                                                          따라서 언렙전과 언렙후에 엔진에서는 버텍스수가 달라지게 됩니다.

                                                          스크립트를 사용할 때도 반드시 언렙후에 사용해야 좀더 정확한 수치를 알게 됩니다.

                                                           

                                                           

                                                           

                                                          2. 연속성이 떨어지는 메쉬를 재 연산하라.

                                                          엔진에서 불 연속성의 메시라고 파단될 경우 2배로 곱해져서 버텍스가 연산된다.

                                                          근데 그 기준을 잡기가 매우 애매하다.. 그래서 불연속성이 많이 발생할 것으로 예상되는 아웃라인 쪽의 메시를 한번더 연산했다.

                                                          선택하기가 매우 까다로워 약간의 꼼수를 사용했기 때문에 정확한 갯수는 집계가 어렵다.

                                                          현재는 이 두가지의 버텍스를 카운트 하여 제법 근사치에 가까운 결과를 얻었습니다.

                                                          유니티 9120 - 맥스 6248 = 2872 차이에서

                                                          유니티 9120 - 맥스 스크립트 9086 = 34 개 차이가 남


                                                          위 모델링 외에 5개를 더 테스트해봐도 꾀 만족스러운 결과를 얻었습니다.

                                                          테스트캐릭터   맥스 버텍스 엔진 버텍스 스크립트 사용시
                                                          samuro04  6248 (3000차이) 9120 9086 (40 차이)
                                                          Achilleus  699 (500차이) 1157 1155 (2 차이)
                                                          plane03  822 (700차이) 1568 1422(140 차이)
                                                          agentsmire  711 (400차이) 1162 1160 (2 차이)
                                                          akedb  685 (500차이) 1201 1152(50 차이)
                                                          alfina  783 (400차이) 1179 1203(20 차이)


                                                          하지만, 이 외에도 노멀벡터와 라이팅 등에 의해서 재 연산되는 엔진 버텍스를 정확히 재정의하는것은 무리가 있습니다.

                                                          위 정보에 따른 버텍스는 언리얼과 유니티도 버텍스수가 다릅니다.

                                                          EngineVertexCount.mse

                                                           


                                                           

                                                          반응형
                                                          반응형

                                                          제작한 스크립트를 메뉴에 등록하지 않으면 실 작업자들이 실제로 사용하는데 많은 제약이 따릅니다.

                                                          그런 문제가 없기 위해 제작한 스크립트는 반드시 메뉴에 등록을 해줘야하는데, 그 방법에 대한 가이드입니다.



                                                          맥스 스크립트 메뉴 등록 가이드

                                                          1. 맥스 스크립트 상단메뉴에 들어가려면 반드시 메크로 스크립트로 등록된 스크립트만 사용이 가능 합니다.

                                                          • 현재 사내 매크로 스크립트는 맥스 설치폴더\\MacroSciprs\\Nlabs 폴더에 모여 있습니다.

                                                          • 스크립트는 MacroScript 폴더에 모여있는 매크로 스크립트와 Script 폴더에 모여있는 보통 스크립트로 나뉘어 집니다..

                                                          • 두 개의 차이점 : 

                                                                      (1) 매크로는 간단하게 실행가능한 원클릭 스크립트에 대부분 사용된다.  매크로는 맥스가 실행될께 함께 실행 되기 때문에 덩치가 커서는 안됩니다.

                                                                      (2) 일반 스크립트는 시퀀스 매니저나 애니메이션 라이브러리 같이 덩치가 큰 스크립트에 사용된다.

                                                                          내가 실행을 해야만 작동하기때문에 덩치가 커도 무리가 없습니다.

                                                           

                                                           

                                                          2.  매크로 스크립트를 만들기

                                                          - 현재 사내에 사용중인 매크로 스크립트들은 메뉴 등록에만 사용되고, 실제 만들어진 덩치큰 스크립트를 실행해주는 교두보 역할을 해주고 있습니다.

                                                          - 예) SequenceManeger가 메뉴에 등록될때는 매크로가 사용되고, 메뉴 버튼을 누르는 순간 실제 스크립트가 실행됩니다.

                                                           

                                                          **사내에서 사용중인 본 메이커의 실행 매크로 스크립트

                                                          macroScript BoneMaker       --> 매크로 등록
                                                          category:"Nlabs"                    --> 카테고리 등록
                                                          buttonText:"Bone Maker"        --> 메뉴 버튼 이름 등록
                                                          tooltip:"Bone Maker"            --> 툴팁 등록
                                                          (
                                                           on execute do
                                                           (
                                                             include "Nlabs/BoneMaker.ms"  --> 매크로 스크립트에 실제 스크립트가 실행되도록 연결해 줍니다.
                                                            )
                                                          )



                                                           

                                                           

                                                          3. 위 매크로 스크립트를 메뉴에 등록시키기 위한 코드

                                                          - 아래 코드를 만든 후 Scripts\\Startup 폴더에 저장하시면 맥스가 실행될때 항상 메뉴가 나오게 됩니다.

                                                          스타트업에 들어간 스크립트는 맥스가 실행될때 항상 같이 실행되오니 꼭 필요한 것들만 넣어야 합니다.

                                                           

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

                                                          -- MainMenuClass

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

                                                          struct MainMenuClass

                                                          (

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

                                                           -- FindMenu

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

                                                           fn FindMenu menuName = 

                                                           (

                                                                       local menu = menuMan.findMenu menuName -- 없으면 undefined

                                                                       return menu

                                                           ),

                                                           

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

                                                           -- AddMenu

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

                                                           fn AddMenu menuName =

                                                           (

                                                                       local newMenu

                                                                      

                                                                       -- 중복 추가 방지 --

                                                                       if FindMenu menuName != undefined then

                                                                        return undefined

                                                                      

                                                                       -- Menu 추가 --

                                                                       newMenu   = menuMan.createMenu menuName

                                                                       mainMenu  = menuMan.getMainMenuBar()

                                                                       subMenuItem = menuMan.createSubMenuItem menuName newMenu

                                                                       subMenuIndex = mainMenu.numItems() + 1

                                                                       mainMenu.addItem subMenuItem subMenuIndex

                                                                      

                                                                       return newMenu

                                                           ),

                                                           

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

                                                           -- AddItem

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

                                                           fn AddItem menuName item =

                                                           (

                                                                       local newIndex

                                                                      

                                                                       menu = FindMenu menuName

                                                                      

                                                                       -- Menu가 없으면 패스 --

                                                                       if menu == undefined then

                                                                        return undefined

                                                                      

                                                                       newIndex = menu.numItems() + 1

                                                                       menu.addItem item newIndex

                                                                      

                                                                       return newItem

                                                           ),

                                                           

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

                                                           -- RemoveMenu

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

                                                           fn RemoveMenu menuName =

                                                           (

                                                                       menu = menuMan.findMenu menuName

                                                                      

                                                                       if menu != undefined do

                                                                        menuMan.unRegisterMenu menu

                                                                      

                                                                       return ok

                                                           ), 

                                                           

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

                                                           -- UpdateMenuBar

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

                                                           fn UpdateMenuBar =

                                                           (

                                                                       menuMan.updateMenuBar()

                                                                      

                                                                       return ok

                                                           ), 

                                                           

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

                                                           -- CreateActionItem

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

                                                           fn CreateActionItem macroScriptName categoryName =

                                                           (

                                                            local actionItem

                                                           

                                                            actionItem = menuMan.createActionItem macroScriptName categoryName

                                                           

                                                            return actionItem

                                                           )

                                                          )

                                                                    

                                                          (

                                                                     menuName    = "Test"

                                                                     macroScriptName = "TestItem"

                                                                     categoryName   = "Nlabs"

                                                           

                                                                     MainMenu = MainMenuClass()

                                                           

                                                                     -- menu 만들기 --

                                                                     MainMenu.AddMenu menuName

                                                           

                                                                     -- Item 만들기 --

                                                                     item = MainMenu.CreateActionItem  macroScriptName categoryName

                                                           

                                                                     -- menu Item 등록 하기 --

                                                                     MainMenu.AddItem menuName item 

                                                           

                                                                     -- 화면 갱신 하기 --

                                                                     MainMenu.UpdateMenuBar()

                                                          )



                                                          위 코드를 실행하면 아래 처럼 맥스 메인 메뉴에 원하는 스크립트가 등록이 됩니다.

                                                           


                                                          위 상태에서 BoneMaker를 실행하시면 본 메이커 스크립트가 실행됩니다.

                                                           

                                                          출처 - ​ http://hwanggoon.tistory.com/212

                                                          반응형
                                                          반응형

                                                          회사에서 맥스 스크립트를 많이 쓰게 되면서 스크립트 관리포인트가 상당히 많이 생겼습니다.

                                                          그러다보니 여기저기 버그도 발생하고, 누가 쓰고 있는지 알기도 힘들고, 업데이트 마다 mzp 파일 배포하는 것도 피곤하고..

                                                          그래서 SVN이 도입되어 사용되어 왔습니다. 제 선임이 멋지게 구축해 놓은걸 저는 인계받아 쓰고 있는데요

                                                          맥스 스크립트에서 SVN에 접근하는 방식에 대한 내용 정리입니다.

                                                          출처 -  http://hwanggoon.tistory.com/109

                                                           

                                                           

                                                          1. SVN Command Line 설치하기 

                                                          다운로드 경로 : http://tortoisesvn.net/downloads.html 

                                                          SVN 설치시에는 반드시 Comand 라인을 설치해 줘야만 맥스 설치폴더에서 접근할 수 있게 됩니다.

                                                          Command Line 이란? Dos 명령어를 사용해 Svn을 작동 시켜주는 방법입니다.

                                                          맥스도 Dos 명령어를 사용할 수 있기 때문에 Command Line을 설치함으로SVN을 맥스에서도 쓸 수 있게 됩니다.

                                                           

                                                           

                                                          2. 맥스에서 SVN 사용하기 

                                                          1) HiddenDOSCommand 

                                                          Dos 명령어를 사용하는 방법은 HiddenDOSCommand 함수를 사용하는 것이 일반적 입니다.

                                                          Dos 창이 보이지 않지만 Dos 명령어는 실행 되니깐 즐겨 사용 하는 방법 입니다.

                                                          그런데 HiddenDOSCommand는 기능 상 한계가 있는데요.

                                                          Log같은 정보를 받을 수 없습니다.

                                                          (return 되는 exitCode는 성공, 실패 같은 간단한 정보만을 보여줍니다.)

                                                           

                                                           

                                                          2) dotNet Process 

                                                          위와 같은 경우는 dotNet을 사용하면 해결 할 수 있습니다.

                                                           

                                                          <예제 코드>

                                                          commandString = "info \"" + thePath + "\"" -- SVN 파일 경로

                                                          -- StartInfo -------------------------------------

                                                           dno_ProcessStartInfo = dotNetObject "System.Diagnostics.ProcessStartInfo"
                                                           dno_ProcessStartInfo.CreateNoWindow = true
                                                           dno_ProcessStartInfo.UseShellExecute = false
                                                           dno_ProcessStartInfo.RedirectStandardOutput = true
                                                           dno_ProcessStartInfo.FileName = "svn"
                                                           dno_ProcessStartInfo.Arguments = commandString
                                                           ------------------------------------------------
                                                           -- Process 적용 --------------------------------
                                                           dnc_Process = dotNetClass "System.Diagnostics.Process"
                                                           process = dnc_Process.Start dno_ProcessStartInfo
                                                           process.WaitForExit()

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

                                                          infoLine = process.StandardOutput.ReadLine()

                                                          -- infoLine : svn info 정보를 String으로 받아 볼 수 있음

                                                           

                                                          dotNet Process를 사용해서 Dos 명령어를 실행 하는 방법입니다.

                                                          WaitForExit는 써주는 것이 좋은데요.

                                                          이걸 하지 않으면, Process가 끝나기 전에 MaxScript코드가 실행됩니다.

                                                          오류가 날 확률이 있으니 미리미리 방지해 봅니다.

                                                           

                                                           

                                                           

                                                          3. User Name 찾기 

                                                           

                                                          캐싱파일 분석하기 

                                                          SVN을 MaxScript로 만들다 보면 사용자 이름이 필요한 경우가 발생하는데요.

                                                          (사용자 정보를 수집할 때 필요하죠.)

                                                          SVN 명령어로 사용자 이름을 알 수는 없을 겁니다.

                                                          이럴 경우 캐싱 된 SVN파일을 열어 분석해줘야 하는데요.

                                                           

                                                          SVN 사용자 정보

                                                          경로 : C:\Users\HwangGoon(개인마다 다름)\AppData\Roaming\Subversion\auth\svn.simple

                                                          안에 GUI로 되어 있는 파일이 있습니다.

                                                          이 파일을 텍스트 편집기에서 열어보면

                                                          다음과 같이 나오게 됩니다.

                                                           

                                                          K 8
                                                          passtype
                                                          V 8
                                                          wincrypt
                                                          K 8
                                                          password
                                                          V 372
                                                          AQAAANCMnd8BFdERjHoAwE/ClK 15+.....
                                                          svn:realmstring
                                                          V 40
                                                          <http://100.100.100.100:80> VisualSVN Server
                                                          K 8
                                                          username
                                                          V 9
                                                          hwanggoon
                                                          END


                                                           

                                                          svn:realmstring 값이 내가 사용하는 Url과 같은지 비교하는 것이 우선이 되겠죠.

                                                          (SVN을 2개 이상 사용하는 경우도 많기 때문에)

                                                          username 하위에 보시면 hwanggoon이 SVN username입니다.

                                                           - K 8과 같은 코드는 무시하는 것이 좋습니다. 사용자마다 같다는 보장을 할 수 없어요.

                                                           

                                                            

                                                          3. SVN 설치 유무 알아내기 

                                                          1) TortoiseSVN 설치 알아내기 

                                                          특정 프로그램이 설치되어 있는지 확인하는 방법은 윈도우 레지스트리에서 찾을 수 있는데요. 

                                                          예제 코드를 보겠습니다.

                                                          dnc_Registry = dotNetClass "Microsoft.Win32.Registry"
                                                          registryKey = dnc_Registry.LocalMachine.OpenSubKey "SOFTWARE\\TortoiseSVN"

                                                           

                                                          위와 같이 찾으면 TortoiseSVN이 설치 되어 있지 않다면 registryKey값은 undefined로 나오게 됩니다.

                                                           

                                                          2) Command Line SVN 설치 알아내기 

                                                          TortoiseSVN이 설치되어 있어야 Command Line이 있을 수 있겠죠.

                                                          그렇다면 위에서 찾은 registryKey를 가지고 한번 더 하위를 찾아 봅니다.

                                                           

                                                          dir = registryKey.GetValue "Directory"
                                                          svnFile = dir + "bin\svn.exe"

                                                           

                                                          이제 svnFile이 있는지 여부만 판단하면 Command Line 설치를 확인이 가능해 지겠죠.

                                                          반응형
                                                          반응형

                                                          최근 다관절 셋팅을 하면서 컨트롤러 셋팅을 많이 하게 되는데, 맥스의 컨트롤러 뷰어는 불편한 점이 많아서 서포트 툴을 하나 제작하게 됐습니다.

                                                          특히 LookAtConstraint나 Orientation Controller같이 다른 헬퍼 본과 연계되서 사용할 경우 연계된 본이 어떤건지 구분하기도 힘들고 선택하기도 힘들어 자주쓰는 노드들과 연계하기 편하도록 제작해 봤습니다.


                                                           


                                                          이번 툴을 제작하면서 공부한 내용

                                                          1. Struct로 따로 분리하여 기능 별로 함수 관리하기.

                                                          - 닷넷에 사용하는 트리뷰와 리스트뷰기능만을 구조체로 따로 뺀뒤 기능 함수를 호출해서 사용하는 방식에 대해서 공부하고 숙지했습니다.

                                                          기능 구현에만 집중해서 코딩하다 보면 나중에 손댈 수 없는 지저분한 코딩이 될 수 있어 미리미리 코드 정리하는 습관이 중요함을 알게됐습니다.

                                                           

                                                          2. 재귀함수의 사용법 다시 한 번 숙지

                                                          - 아트직업군에 오래 머물러 있다보니 논리적 사고가 부족해 재귀함수의 흐름을 익히는데 어려움이 많이 있습니다.

                                                          지난번 페이스 셀렉트 툴에서도 여러번 익히며 사용법을 완전 숙지했다고 생각했으나 이번 툴을 만들면서 아직 개념이 들 잡혀있음을 알게 되었고, 좀더 연습할 수 있는 시간이었습니다. 좀 더 많은 코딩을 통해 계속해서 숙지해야 할 필요성을 느끼게 됐습니다.

                                                           

                                                          ControllerNodeViewer2.mse

                                                           

                                                          반응형
                                                          반응형

                                                          기존에 제작한 은면제거 방식은 벡터의 내적이라는 수학 공식을 활용하여 카메라와 대치되는 각을 계산하여 면을 제거하는 방식이었습니다.

                                                          하지만 이 방식은 몇가지 단점이 존재합니다.


                                                          1. 각도를 계산해서 하다보니 카메라에 안잡히는 면도 각도조건만 맞으면 남아있게 된다.

                                                          2. 면이 깔끔하게 지워지지 않는다. 가령 면은 지워졌는데, 버텍스가 남는다던지..

                                                           

                                                          등등.. 여러번 시뮬레이션을 돌려보면 금방 알 수 있는 단점들이 존재합니다.

                                                          하지만, 이번에 제작한 Hidden Surface 방식은 렌더링 된 G-Buffer의 값을 얻어와 지오메트리의 렌더링된 면을 메모리에 기억하여 삭제하는 방식이라 더 깔끔하게 면들을 정리해줍니다.

                                                          단, 계산시간이 오래 걸릴수 있다는 단점이 있습니다. 이 부분도 차후에 개선할수있도록 해보겠습니다.


                                                          이 스크립트의 구동방식을 간단히 살펴보면

                                                          1. 먼저 대상이 될 오브젝트의 면들을 전부 디테치 한 후 메모리에 저장한후 각 면마다 오브젝트를 생성해 줍니다.

                                                          -여기서 먼저 대상이 될 원본 오브젝트를 하이드 시켜 줍니다.(G-Buffer값 구할때 방해되는 요소)


                                                           



                                                          2. 디테치된 면들의 렌더링 된 채널값에서 G-Buffer(지오메트리버퍼) 값을 구해온다.

                                                          G-Buffer의 개념 - http://en.wikipedia.org/wiki/Deferred_shading


                                                          3. 렌더링 버퍼의 값을 구해서 원본 모델링에 저장이 됐으면 이제 각 면들은 필요없어 졌으니 전부 지워버린다.


                                                          4. 원본 면의 페이스 정보들을 비트어레이에 담고 G-Buffer에 담긴 값들만 False로 선언해준다.

                                                          5. 이제 원본 오브젝트의 비트어레이에 담긴 면들을 삭제하라는 명령을 실행하면 false로 제외된 값들을 빼고 삭제를 하게 된다.



                                                          벡터의 내적 방식과 Hidden Surface 방식의 비교 샷


                                                          백페이스 방식- 면이 지저분하게 정리된다.  


                                                           

                                                           히든 서페이스 방식 - 면이 깔끔하게 정리된다.

                                                           

                                                           

                                                          이번 과제를 통해 알게 된 내용

                                                          1. G-Buffer의 개념과 렌더링에 대한 기초

                                                          2. 원본에 있는 면을 뜯어내서 메모리에 저장시킬 수 있는 기능

                                                          3. finditem을 이용하여 비트어레이의 값을 조절할수 있는 기능

                                                          반응형
                                                          반응형

                                                          이 스크립트는 최적화를 위한 툴로서 카메라에 보이지 않는 면들을 제거하여 카메라렌더링에 대한 연산을 최소화

                                                          시키지 위한 툴입니다.

                                                           

                                                          이번 과제를 해결하기 위해서는 삼각함수의 기본 원리와 벡터의 내적을 구하는 공식에 대한
                                                          이해가 필요했습니다.

                                                          카메라와 오브젝트간 벡터의 내적이 0보다 큰 수의 면만 선택하여 삭제하는 공식을 이해하는데

                                                          많은 시간이 필요했습니다.

                                                          카메라가 A이고 오브젝트의 한 단면이 B 이고 살리고 싶은 면이 C일때

                                                          C = a b cos@를 이용한 벡터의 내적을 이용하여 cos@가 0보다 큰면은 카메라가 바라보는 방향과

                                                          같은 방향을 바라보기 때문에 카메라가 잡히지 않는 구간입니다.

                                                          따라서 0보다 작은 마이너스 구간을 살리고 0보다 큰 플러스 구간은 삭제하면 됩니다.

                                                           

                                                          이 공식을 이용하여 스크립트를 짜게 되면 영상과 같은 결과가 출력됩니다.


                                                           


                                                          스크립트

                                                          Global backFaceDeleter


                                                          --======================================================================================
                                                          -- DestroyDialog
                                                          --======================================================================================
                                                          try (DestroyDialog backFaceDeleter) catch()

                                                          --==========================================================================================================

                                                          -- rollout backFaceDeleter

                                                          --==========================================================================================================
                                                          rollout backFaceDeleter "백페이스 방식 삭제"
                                                          (
                                                           local mainCamera  -- 메인 카메라 선언
                                                           
                                                           --======================================================================================
                                                           -- struct
                                                           --====================================================================================== 
                                                           struct strt_objinfo   --max 스크립트는 변수 선언에 형식의 제한이 없다. 모든 값을 넣을 수 있음(오브젝트형식)
                                                           (
                                                            obj,     -- 오브젝트 정보
                                                            faces = #(),    -- 전체 페이스 정보
                                                            faceobjs = #()   --  참인 값의 페이스 정보
                                                           )
                                                           ------------------------------------------------------------------------
                                                           -- CameraFilter
                                                           ------------------------------------------------------------------------
                                                           fn FilterCam cam =   --카메라 아니면 선택되지 않게 설정
                                                           (
                                                            if iskindof cam camera then
                                                             return true
                                                            else
                                                             return false
                                                           )
                                                           --======================================================================================
                                                           -- UI
                                                           --======================================================================================
                                                           pickbutton ptn_camera "Pick" filter:FilterCam
                                                           button btn_BackFace "BackFace"
                                                            
                                                            
                                                           --======================================================================================
                                                           -- Fn
                                                           --======================================================================================

                                                           ------------------------------------------------------------------------
                                                           -- FindBackface
                                                           ------------------------------------------------------------------------ 
                                                           fn BackFaceinfo obj camLookPos =     ---- 백페이스 정보와 오브젝트와 카메라의 바라보는 뷰를 변수 선언
                                                           (
                                                            local backFaces = #{}      ----백페이스 관련 좌표와 벡터값을 얻어내기 위해 비트 어레이 변수 선언
                                                                                               
                                                            faceNum = getNumFaces obj        --- 페이스 넘버는 곧 오브젝트의 페이스 넘버다
                                                            for i = 1 to faceNum do                           ----- 1번부터 전체 페이스 넘버를 돌면서 아래를 실행
                                                            (
                                                             facePos = meshop.getFaceCenter obj i        ---- 한 페이스의 중앙 점 좌표를 camLookPos이라는 변수에 대입
                                                             lookV = facePos - camLookPos                            ---- 위에서 구한 중앙 좌표에서 카메라의 위치값을 빼서 lookV에 넣는다. 그래야 벡터의 내적을 구하니까
                                                             
                                                             faceNormal = getFaceNormal obj i        --- 한 페이스가 바라보는 벡터값을 faceNormal 이라는 변수값에 대입
                                                             if dot lookV faceNormal > 0 then       --- 그래서 페이스에서 카메라위치값을 뺀 벡터와 한 페이스의 벡터값을 뺀것의 내적이  0보다 클경우 참.  참인면을 최종적으로 지울것   바라보는 각을 지우고 반대쪽을 바라보는 각을 살리기 위해
                                                              backfaces[i] = true                   --- 비트어레이 backfaces의 페이스 넘버의 참과 거짓을 가림
                                                            )
                                                            
                                                            return backFaces     --- 백페이스 정보 리턴
                                                           )
                                                           
                                                           --======================================================================================
                                                           -- UI Control
                                                           --======================================================================================
                                                           ------------------------------------------------------------------------
                                                           -- ptn_camera
                                                           ------------------------------------------------------------------------ 
                                                           on ptn_camera picked cam do    --- 카메라를 클릭했을때 이름 보여줌
                                                           (
                                                            ptn_camera.text = cam.name
                                                            mainCamera = cam
                                                           )
                                                           
                                                           ------------------------------------------------------------------------
                                                           -- btn_DeleteBackface
                                                           ------------------------------------------------------------------------
                                                           on btn_BackFace pressed do
                                                           (
                                                            local meshObj = $
                                                            local cams = mainCamera

                                                            convertToMesh meshObj  ---메시 형태가 아니면 폴리 넘버를 알수 없다.
                                                            backfaces = BackFaceinfo meshObj cams.pos  ---bacakfaces에 오브젝트와 카메라의 포지션을 넣는다.
                                                            objinfo = strt_objinfo meshObj backfaces   --struct함수로 선언한 세 변수에 각각 값을 집어넣는다. obj에 선택한 오브젝트, face에 backfaces(참인 면)

                                                            --obj : 선택한 오브젝트      faces : 참인 면들의 배열(비트어레이)
                                                            
                                                            print objinfo
                                                            print  objinfo.faces
                                                            
                                                            if objinfo.faces.numberset < getNumFaces meshObj then   -- numberset은 비트어레이 배열안에 몇개의 수가 있는지 알려줌, struct안에 배열의 수가 선택한 메시 수보다 작을경우 선택한 메시의 struct 변수에 넣은
                                                              meshop.deleteFaces meshObj objinfo.faces             ---참인면들을 지워라!
                                                             
                                                            deselect $
                                                            select meshObj
                                                           )
                                                          )

                                                          CreateDialog backFaceDeleter width:100 height:50

                                                           

                                                           

                                                          이번 과제는 저에게 큰 벽이었습니다. 중 고딩때 수학공부를 게을리한 내 자신이 이렇게 미울수가 없었네요..ㅠ

                                                          지난 한주간 용인 사는 누나댁을 오가며 열심히 원리를 깨우쳤습니다. 수학과 나온 누님이 저에게 도움 되는 날이

                                                          올줄 몰랐어요..ㅎㅎ   어렵지만, 이해하고 나니 정말 극 쾌감이 몰려오네요~^^ 

                                                          근데 백페이스 방식은 여러가지 단점이 있어 HIdden 방식을 써야 하는 경우가 생깁니다.

                                                          그 방식에 대해서는 다음에 다뤄보겠습니다.


                                                          참고 사이트 황군 - http://hwanggoon.tistory.com/118

                                                          반응형
                                                          반응형

                                                          맥스 스크립트와 캐릭터 셋업의 정석인 이상원님의 '캐릭터 셋업 테크닉'을 오랜기간 정독중에 있습니다. 1차로 정리한 내용을 올려볼까 합니다.





                                                          캐릭터 셋업 책 리포트

                                                          Seccion1 . 기초다지기> 개념을 잡자!(34p~291p)

                                                           

                                                          1. 축의 개념 - 뷰, 로컬, 월드, 페어런트의 정확한 개념 이해하기

                                                                     (1) 부모자식간의 개념 확실히 이해하기

                                                                     - 링크관계일때와 아닐때의 위치 좌표의 변화

                                                                     (2) 좌우 대칭이 되는 Point Helper 만들기

                                                                     - 모델링 맵핑과 마찬가지로 좌우 대칭의 개념을 아는 것은 매우 중요하다.

                                                                     로컬 트랜스폼에 대한 개념을 깨우치자.

                                                           


                                                          2. 본에 대해서 숙지하기

                                                                     (1) 본 오브젝트는 위치, 회전, 스케일 정보만 가지고 있는 헬퍼라고 생각하는게 좋다.

                                                                     (2) 본의 Mirror와 일반 Mirror는 완전다르다. 일반 미러는 스케일값을 반전 시키기때문에

                                                                     Y혹은 Z축이 뒤집히게 되면서 다양한 문제를 발생시킨다.

                                                                     (3) scale형식과 squash형식 이해하기

                                                                     (4) Auto-Align 의 기능 살펴보기(자식본을 바라보느냐 안하느냐)

                                                           


                                                          3. 오일러와 쿼터니언

                                                                     (1) Roll , Pitch, Yaw 숙지하기.

                                                                     (2) 짐벌락에 대해 이해하고, 짐벌락을 피해가는 방식을 고려해 본다.

                                                                     -가령 사람의 척추는 Y,Z축으로는 많이 움직이지만, X축움직임이 거의 없기 때문에

                                                                     YXZ ZXY로 회전순서를 설정하면 짐벌락의 현상을 최소화 시킬수 있다.

                                                           (3) Script Controller에서 F(frame), NT(normalized time), S(secs), T(ticks) 의 개념 이해하기.

                                                           (4) 쿼터니언은 3개의 방향을 가지고 있는 백터와 그 벡터의 바라보는 위치값을 결정하는 w값에 의해서 최종 회전 방향이 결정된다.

                                                           

                                                           

                                                          4. Pivot 관련 개념 잡기

                                                                     (1) Adjust Pivot, Working Pivot, Adjust Transform 개념 잡기

                                                                     (2) Link Info 개념잡기

                                                                     - Lock 롤아웃 : 애니메이터가 잘못된 축을 이용하지 못하도록 원천적으로 막아주는 기능.

                                                                     - Inherit 롤아웃 : Inherit의 개념 정확히 이해하기~ 상속의 개념

                                                                     (3) Reset Stretch

                                                                     - Max Script Stertch   = objectoffsetTM * stretchTM * nodeTM

                                                           - 한글로 = 오브젝트의 트랜스폼 = 오프셋 값과 Stretch 값과 노드 값이 모두 반영되어서 결정됨

                                                                     - 상품의 가격 = 소매점 마진 + 유통 마진 + 생사자 원가


                                                           

                                                          5. 본의 IK 이해하기

                                                          (1) HI Solver

                                                          - 캐릭터 애니나 길이가 긴 애니메이션 추천. 이 방식은 계층 구조 내에서 여러개의 IK Chain을 동시에 사용할 수 있는데,예를 들어서 캐릭터의 다리를 만들때 엉덩이로부터 발목까지를 하나의 체인으로 구성하고 뒤꿈치에서 발가락까지 또 다른 체인으로 구성할 수 있다.

                                                          전체 애니메이션 내용과 무관한 알고리즘으로 작동하기 때문에 애니메이션 길이가 얼마나 길게 만들어졌는지에 상관없이 빠른 연산 속도를 유지한다. , 전체 애니메이션 길이가 2000프레임으로 되어 있는 경우와 10프레임으로 되어 있는 경우가 모두 같은 속도로 작동한다. 또한 뷰포트에서 지글거리는 증세가 적고 안정적인다.

                                                          - HI IK Solver에는 IK Solver Plane이라는 개념이 사용되고 있는데 Swivel Angle이라는 값에 의해서 IK Solver Plane이 제어된다. Swivel Angel값은 직접 애니메이션 되거나 타깃 오브젝트를 통해서 애니메이션 되는 값이다.

                                                           

                                                          (2) HD Solver

                                                          - HD Solver Interactive IK와 같은 기능이 있다. 그렇기 때문에 Hierachy 판넬의 IK 버튼에 각종 롤아웃의 기능들, Terminator 라던가 Bind to Folow 라던가 Precedence 등의 기능이 동일하다.

                                                          HD Solver Interactive는 대체로 기계를 움직일 때 적합한 방식이다. 특히 IK 애니메이션 특성에 의해서 미끄러지는 특성을 가진 기계에 적합하다.

                                                          (3) Ik Limb Solver

                                                          - 본이 두개인 경우에만 사용된다. 캐릭터의 팔과 다리에 쓰기에 적합한 방식. 이 녀석을 쓰기 위해서는 최소한 세 단계 이상의 본이나 오브젝트로 구성된 계층구조가 필요하다. 그 외에는 HI SOlver와 같은 방식으로 기능한다.

                                                          (4) Spline IK Solver

                                                          - Spline Ik Solver는 스플라인을 이용해서 여러개의 본이나 링크로 이어진 오브젝트를 부드럽게 휘어지도록 제어한다.

                                                           

                                                           

                                                          6. Controller 이해하기.

                                                                     -3DS MAX를 처음 설치 했을 때 오브젝트에 적용되는 Default Controller는 다음과 같다.

                                                                     위치 : Position XYZ

                                                                     회전 : Euler XYZ

                                                                     스케일 : Bezier Scale

                                                                     -맥스의 대부분의 애니메이션은 Bezier Controller에 의해서 제어된다.

                                                            - Controller에 가능한 것들 : 애니메이션 키값 저장, 절차적인(Procedual) 애니메이션 설정 , 애니메이션 키 사이의 보간(Interpolation)

                                                                     - 트랙뷰에서 컨트롤러 접근이 가능하다.

                                                                     (1) 컨트롤러의 분류와 구조

                                                                     - Single-Parameter(단일) Controller : 단순히 한 가지 값이 애니메이션 되는 경우이다.

                                                           - Compound Controller : 애니메이션 되는 값이 하나가 아니고 여러 개인 경우이다. 쉬운 예가 Euler XYZ Rotation Controller인데XYZ의 각 축 방향마다 서로 다른 Controller를 적용할 수 있다. 이런 경우 외에도 PRS, Transform Scrip, List Controller등 상위 레벨의 Controller 또한 Compound Controller 이다.

                                                                   (2) 일반적인 목적의 Controller

                                                            - Bezier Controller : 가장 자주 사용되는 컨트롤러이고, 애니메이션 키와 키 사이사 보간할 때 스플라인 커브 방식으로 보간 된다Normilize Time 숙지 필요.

                                                           - TCB Controller : 커브 기반의 애니메이션 컨트롤러지만 커브를 제어하기 위해서 탄젠트를 사용하지 않는다. 대신에 Tension, Continuity, Bias라는 값을 사용한다. Rotaion WindUP 기능에 대해서 아는게 좋음.(180도이상 돌지 못하는 TCB 360도까지 돌게 하는 기능. 하지만여러가지 문제가 많아 지향하는 방식은 아님)

                                                                    

                                                           - Linear Controller : 애니메이션 키와 키 사이를 일정한 간격으로 보간(Interpolation)한다.

                                                           - Noise Controller : 불규칙적이고 랜덤한 애니메이션 값을 계산적으로 만들어내는 컨트롤러. Ignore 방식은 전체 프레임에서 발동하고 Respect 방식은 보여주는 키프레임안에서만 발동한다.

                                                                    

                                                          - XYZ Controller :

                                                          1) Position XYZ : X,Y,Z축으로 분리되어 있어 각 축마다 서로 다른 Controller를 지정할 수 있다

                                                           2) Euler XYZ : Position XYZ와 비슷하며, 회전을 제어하는 컨트롤러중에서는 유일하게 커브 편집이 가능하다.

                                                                     - Audio Controller

                                                           

                                                          (3) 특수한 목적의 Controller

                                                          - List Controller : List Controller는 여러 개의 Controller를 혼합해서 최종 결과를 만들어 내는 Controller이다. 적용방향은 위에서부터 아래쪽으로 순차적으로 적용 된다.

                                                          리스트 컨트롤러의 세부조절 설명

                                                            1. Editable Name Field : 그림의 빨간색 박스를 통해서 현재 활성화된 Controller의 이름을 변경할 수 있다.

                                                            2. Set Active : 어떤 Controller가 활성화 되는지를 결정하는 버튼인데 Controller 이름에서 더블 클릭을 통해서도 활성화 지정이 가능하다.

                                                            3. Delete : Controller를 삭제한다.

                                                            4. Cut/Paste : 선택된 Controller를 삭제하고 클립보드에 기억시킨다.

                                                            5. Weight : Controller의 효과가 과장되거나 작게 줄어들게 조절할 수 있다. 기본 값은 100인데 100이상의 값도 가능하다.

                                                            6. Average Weight : 이 옵션은 Position List Scale List에만 있는 옵션이다. 이 옵션이 켜지면 모든 Weight값을 비율로써 계산하게 된다.

                                                            7. Pose TO Pose : Rotation List에 쓰임. 예제 34 파일을 참고. 말로 설명이 어려움.

                                                           

                                                          (4) Zero Transform

                                                          - Freeze Tranform이나 Freeze Rotation을 오브젝트에 적용한 뒤에 애니메이션 작업 도중에 Tranform to Zero 혹은 Rotation To Zero를 적용하면 Freeze를 했던 순간의 트랜스폼으로 되돌아가게 된다.

                                                          (5) Parameter Wiring

                                                          - Parameter Wire는 두 오브젝트간 Parameter가 연동되도록 연결하는 기능으로서 리깅 작업뿐 아니라 전반적인 3D 작업을 위해서 매우 요긴한 기능이다.

                                                          리깅을 예로 들어 새가 날개짓을 하는 애니메이션을 할 때 한 쪽 날개만 움직여도 다른 쪽 날개가 똑같이 움직이도록 연결하거나 페이셜 애니메이션을 위해서 표정제어를 위한 각종 Manipalutor를 설치해서 슬라이더 하나만 움직여도 다수의 본이 동시에 움직여서 웃는 표정을 짓는다거나 하는 작업에 활용될 수 있다.

                                                            • 마우스 우클릭의 wire parameter를 이용하여 사용할 수 있고, Animation 메뉴를 통해서도 접근할 수 있다.

                                                            • 과도하게 사용될 경우 CPU 연산 부하량이 많아 최대한 낮은 CPU 비용으로 간결하고 직관적으로 셋업하는 것이 훌륭한 셋업이다.

                                                           

                                                          (6) Reaction Controller

                                                          - 오브젝트가 가까이 가면 자동으로 라이트가 켜진다거나 근육이 부풀어 오른다거나 공이 땅에 닿으면 가로로 찌그러진다거나 하는 설정을 할 수가 있다. 또한 파티클을 발생시키는 트리거로도 사용될 수 있고 몰핑의 퍼센트 조절을 해줄수도 있다.

                                                          Maya Set Driven Key 기능과 매우 유사하다.

                                                          , 버그가 미친듯이 많아서 사용을 권장하지는 않는다.

                                                           

                                                          (7) 트랜스폼 제어

                                                          - Position , Rotation, Scale의 세정보가 합쳐져서 트랜스폼이 된다. 지금까지 설명했던 각종 Animation Controller는 모두 트랜스폼을 제어하는 Position / Rotation / Scale Controller의 하위 Controller였다.


                                                          1) Link Constraint - 0프레임은 월드에 1프레임은 오브젝트에 30프레임은 본오브젝트에 링크하듯이 프레임마다 다양한 속성으로 링크가 가능하다.

                                                          단점은, 애니메이션의 저장과 불러오기가 불가능하다.


                                                          2) Transform Script Controller

                                                          - 포지션,  로테이션, 스케일을 Script로 표현하는 Controller이다. 일반적인 Scrpit Controller와 대부분 동일하지만 리턴 값이 Matrix3 형태여야 하는 점이 다르다.

                                                           

                                                          7. Animation Constrints(애니메이션 컨스트레인트)

                                                                     - 가장 대표적인 것으로는 LookAt Orientation Constraints가 있고 포지션에 대해서

                                                                     Path Position Constraint가 있다.

                                                            • 모든 컨스트레인트는 다른 오브젝트를 참조해서 자신의 포지션이나, 로테이션 혹은 전체 트랜스폼을 결정하게 된다. 예를 들어 룩앳 컨스트레인트는 하나이상의 다른 오브젝트들을 바라봄으로써 자신의 로테이션이 결정된다.

                                                          (1) LookAt Constraint

                                                            • 다른 물체를 바라보게 함으로써 자신의 Rotation이 결정되도록 하는 Controller.

                                                          (2) Orientation Contraint

                                                            • 기본적인 목적은 다른 오브젝트의 Rotation을 그대로 따라하는 기능인데 여러 오브젝트를 지정해서 평균적인 회전 방향을 사용하거나 가중치를 다르게 지정하는 것도 가능하다.

                                                          (3) Path Constraint

                                                            • Spline Path 를 이용해서 오브젝트의 위치를 제어하는 Contraint이다.

                                                          (4) Position Constraint

                                                            • 다른 오브젝트의 위치를 참조해서 자신의 위치를 결정하는 역할을 하는데, 하나 이상의 오브젝트를 참조할 수 있기 때문에 두 오브젝트의 중간 위치를 얻어낼 때 자주 사용된다.

                                                          (5) Attachment Constraint

                                                            • 오브젝트를 다른 오브젝트의 메쉬에 부착시키는 역할을 한다.

                                                          (6) Surface Constraint

                                                            • 어태치먼트는 접착제로 부착하는 느낌이라면 Surface는 타깃 오브젝트의 표면을 미끄러지듯이 이동하기 위한 목적에 주로 사용된다. 매우 제한적으로 사용할 수 있고, 사용할 수 있는 오브젝트 타입도 제한적이다.

                                                            • Sphere , Cone, Cylinder, Torus, Quad Patches, Loft object, NURBS object에만 사용할 수 있다. 이 오브젝트들의 공통점은 수학적으로 표현되는 오브젝트라는 점이다.

                                                           

                                                          8. 기타 Controller


                                                          (1) Limit Controller

                                                          - 오브젝트의 움직임에 한계값을 지정하는 Controller이다. 예를 들어 손가락 방향으로는 90도 정도의 회전을 하지만 손등 방향으로는 거의 꺽이지 않는 한계 각도가 있다. 이런 특징을 가지고 있는 손가락 관절에 Limit Controller를 적용하게 되면 지정된 각도 이상으로 관절이 꺽이지 않도록 강제도 막아줄 수 있다.


                                                          (2) Spring Controller

                                                          - 마치 보이지 않는 고무줄에 매달려 있는 것처럼 탄력적으로 흔들리는 움직임으로 특성이 바뀐다. 이렇게 되기 위해서는 미리 Position Animation이 적용되어 있어야 하는데, 오브젝트 자신이 움직여도 되고 오브젝트 부모가 움직여도 된다.

                                                          그런데 현실에서의 Spring이나 고무줄 움직임을 시뮬레이션 하기에는 많이 부족한 기능이라서 본 오브젝트에 간단히 사용해서 응용하는 방향으로 주로 사용되며, 우리 회사에서도 세컨더리 애니메이션으로 많이 사용되고 있다.

                                                            1. Mass : 오브젝트의 무게 설정. 이 값이 증가하면 모션이 과장된다.

                                                            2. Drag : 공기 저항. 이 값을 높이면 물속에 있는 거처럼 큰 저항을 받게 된다.

                                                            3. Add / Remove : Add 버튼에 의해서 다른 오브젝트를 Spring으로 추가할 수 있고, Remove 버튼에 의해서 제거할 수 있다. 하지만 Self Influence는 제거할 수 없다.

                                                            4. Tension : 얼마나 팽팽하게 당겨지는지에 대한 강도를 조절한다. 이 값이 작아지면 잘 늘어는 고무줄이 되고 높아지면 뻣뻣해서 잘 늘어나지 않는 고무줄이 된다.

                                                            5. Damping : 얼마나 빨리 안정화되는지를 결정한다. 탄력이 줄어드는 정도 혹은 감쇄되는 정도의 역할이다.

                                                            6. Relative / Absolute : 이 선택에 의해서 달라지는 것은 Tension Damping의 값을 입력하는 방식이 달라지게 된다. Relative Absolute중에서 어떤 것을 선택하는가에 의해서 Spring 움직임에 직접적인 변화는 전혀없다.

                                                            • 스프링 컨트롤러의 단점인 Loop가 안되는점을 보완하기 위해 지글 본 방식을 선호한다. 지글 본은 덜렁거리는 본인데 3ds max에서는 대부분 본이 Spring을 바라보게 해서 덜렁거리도록 리깅을 하는 경우가 많다.

                                                            • 많이 사용하면 느려지는 문제가 있다. 이것을 보완하기 위해서 Spring Quick Edit 옵션을 켜면 Spring에 관련된 연산이 조금 빨라진다. 대신 연산의 정확도가 낮아진다.

                                                            • X / Y / Z Effect 값을 Wire Parameter로 스위치에 연결해서 스위치를 켜면 전체 Spring Effect가 정상적인 값이 되고 스위치를 끄면 전체 Spring Effect 0의 값이 되도록 설정한다.

                                                          (3) Waveform Controller

                                                          - Wave 형태의 파형을 만들어주는 Controller 이다. 거의 쓰이지 않는다.


                                                          (4) LookAt Controller

                                                          - 룩앳 컨스트레인트와 매우 비슷한 룩앳 컨트롤러이다. 예를 들어 타깃 카메라 오브젝트를 생성하면 카메라는 자동으로 카메라 타깃을 바라보게 되는데 이 때 자동으로 지정되는 컨트롤러가 룩앤 컨트롤러이다.

                                                          (5) Smooth Rotationg Controller

                                                          - 키위 위치를 옮겨줌으로서 타이밍을 바꿔줄 수 있을 뿐인 컨트롤러이며, 자주 사용되지 않으며 설명할 내용도 없는 컨트롤러


                                                          (6) On / Off Controller, Boolean Controller

                                                          - 0이나 1 둘 중의 한 가지 값만 가질 수 있는 Controller이다.

                                                          (7) Layer Controller

                                                          - Animation Layers 툴 바(Tool bar)를 중심으로 작업되는 애니메이션 레이어 기능이다.

                                                          - 페이셜 리깅에 활용하기 좋다. 캐릭터의 얼굴에 표정 연출을 위한 다수 본들이 배치되어 있고, 그 본들의 웃는 표정을 위한 본들의 Transform(포지션, 로테이션, 스케일) 전체를 Smile이라는 이름으로 Animation Layer로 만들 수 있다.Smile Layer에는 Transform 값이 변하는 애니메이션 키는 적용되지 않지만 Transform 정보가 웃는 표정이기 때문에 Smile Layer Weight 값을 0에서 100으로 증가시킬수록 웃는 표정을 만들어 낼 수 있게 된다. 비슷한 방식으로 입을 벌린다거나 눈을 깜빡이는 등의 타깃 표정들을 Layer에 추가하면 다양한 표정들이 서로 자연스럽게 섞이는 표정 애니메이션이 가능하다.


                                                          - 캐릭터 리깅에 다수의 Animation Layer가 적용되면 3ds max가 생각 이상으로 느려지는 문제가 발생한다. 

                                                           

                                                          반응형
                                                          반응형

                                                          참고 자료

                                                          [데브루키/141206 박민근] 유니티 최적화 테크닉 총정리

                                                          http://www.slideshare.net/agebreak/unite2015-47100325?related=1

                                                           

                                                          유니티 그래픽 최적화, 어디까지 해봤니

                                                          http://www.slideshare.net/ozlael/graphics-opt-ndc?related=2

                                                           

                                                          최적화 내용 간단 정리

                                                          ** 가장 중요한 것은 병목 지점 파악~(메모리인지, 콜인지, CPU인지, 버텍스연산인지.. 아니면 다함께..)

                                                          ** 리소스 아껴 쓰기

                                                          ** 드로우콜 관리하기

                                                          ** 모바일 사운드는 모노로 사용하기~

                                                          ** 가비지 컬렉터 관리~~

                                                          ** 스크립트 함수에 무거운 함수 쓰지 않기~

                                                          ** 셰이더에 무거운 함수 사용 줄이기~

                                                          ** 물리 사용은 최소로~

                                                           

                                                          1. 프로그램 최적화

                                                          * 스크립트 최적화

                                                          --- 유니티 객체들을 변수에 저장하고, 캐싱해서 사용하는 것이 좋다.

                                                          --- FindObject 계열 함수들은 매우 느리다. (미리 찾아서 캐싱)

                                                          --- Update 함수 보다는  Coroutine을 활용한다.

                                                          --- 박싱과 언박싱은 부하가 큰 작업이다.

                                                          --- 나눗셈보다 곱셈이 몇십배 빠르다.

                                                          --- 삼각함수의 값은 상수로 저장하고, 사용하는 것이 좋다.

                                                          --- 문자열은 readonly 혹은 const 키워드를 사용하여, 가비지 컬렉션으로부터 벗어나도록 한다.

                                                          * 문제의 원인 : 가비지 컬렉터

                                                          --- Mono의 동적 메모리 관리 때문에, 메모리 해제를 위해 GC가 자동 호출 된다.

                                                          --- GC는 언제 일어날지 모른다.

                                                          --- 오브젝트(or 프리팹)의 동적생성과 해제는 부하가 크다.

                                                          --- 오브젝트 풀링 사용은 선택이 아닌 필수!

                                                          --- 문자열 병합은 StringBuilder

                                                          --- foreach 대신에 for문 사용 (foreach는 한번 돌때마다 24Byte의 쓰레기 메모리를 생성)

                                                          --- 태그 비교에는 compareTag() 사용

                                                          --- 데이터 타입에는 Class 대신 구조체 사용

                                                          --- 즉시 해체할 때는 Dispose 수동 호출

                                                          --- 임시 객체들을 만들어내는 API들을 조심하라.

                                                          * C++ <-> C# 오버헤드

                                                          --- 객체의 변경 사항을 캐싱

                                                          --- 컴포넌트 참조를 캐싱

                                                          --- 빈 콜백 함수는 제거

                                                           

                                                           

                                                          2. 그래픽 최적화

                                                          * 텍스쳐 최적화

                                                          --- 권장 압축 사용하기 : 아이폰 -> PVRTC   ,  안드로이드(Tegra) -> DXT , 안드로이드(Adreno) -> ATC , 안드로이드(공통) -> ETC1 / ETC2

                                                          --- 텍스쳐 사이즈는 무조건 2의 제곱이어야 한다. POT(Power of Two) 아닐 경우 무조건 POT로 강제 변환함

                                                          --- 텍스쳐는 묶어서 사용하는게 이득이다. 한 화면에 나오는 것끼리~ 같은 재질의 오브젝트끼리~ 알파가 있는것과 없는것끼리

                                                          --- 32bit 텍스쳐보다는 16bit를 큰 텍스쳐로 쓰는게 이득이다.

                                                          --- 모바일뷰에서 가장 최적화된 해상도를 찾는데 주력한다. 이거저거 다해봐도 개개의 소스를 절약하는 방식이 최고임.

                                                          * 메쉬 최적화

                                                          --- Import시에 언제나 "Optimize Mesh" 사용 - 버텍스 캐쉬를 최적화 해준다.

                                                          --- 언제나 Optimize Mesh Data 옵션을 사용한다. 사용하지 않는 버텍스 정보들을 줄여준다.

                                                          --- 사용하지 않는 버텍스 정보들을 줄여 준다.

                                                          * 드로우 콜

                                                          --- 적절한 DP 는 100이하를 추천, 보통 70~100 정도가 일반적

                                                          * CULLING

                                                          ---- 각 Layer 별로 컬링 거리를 설정해 준다. 중요도가 낮은 오브젝트의 컬링커리를 짧게 설정한다.

                                                          ---- 오클루젼 컬링을 활용하여 카메라 밖은 잘라내도록 한다.

                                                          * 오브젝트 통합

                                                          ---- 성질이 동일한 오브젝트들은 하나의 메쉬와 재질을 사용하도록 통합

                                                          *Batch

                                                          ---- 스태틱 배치와 다이내믹 배치의 적절한 조합

                                                          * 라이팅

                                                          ---- 라이트맵과 라이트렌더 모드 활용

                                                          * OverDraw

                                                          --- 한 픽셀에 두 번 이상 그리게 되는 경우 OVERDRAW 문제가 발생한다.

                                                          --- 기본적으로 앞에서 뒤로 그린다. Depth testing으로 인해서 오버드로우를 방지한다. 알파 블렌딩이 있을경우 소팅 문제 발생

                                                          --- 반투명 오브젝트의 개수의 제한을 건다. 뒤에서 앞으로 그려야 함. 반투명 오브젝트 갯수가 늘어날수록 퍼포먼스 직결~!

                                                           

                                                           

                                                          3. 사운드 최적화

                                                          --- 모바일에서 스테레오 사용은 퍼포먼스에 큰 영향을 끼친다. -> 되도록이면 모두 92 kb, 모노로 인코딩

                                                          --- 사운드 파일을 임포트하면 디폴트로 3D 사운드로 설정 -> 2D 사운드로 변경

                                                          --- 압축 사운드(mp3. ogg) , 비압축 사운드(wav) 구별.    압축 사운드-> 순간적인 효과음, 이펙트등..      비압축사운드 -> 배경 음악 

                                                           

                                                           

                                                          4. 폰트 리소스 최적화

                                                          --- Packed Font - R,G,B,A channel에 각각 글자의 형태를 저장하는 방법. 메모리 용량을 1/4로 절약

                                                          --- 리소스 기타 - ResourceLoadAsync() 함수는 엄청 느리다.

                                                           

                                                          5. 셰이더 최적화

                                                          --- 기본 셰이더를 사용할 경우, 모바일용 셰이더 사용 Movile -> VertexLit 가장 빠른 셰이더

                                                          --- pow, exp, log, cos, sin, tan 같은 수학 함수들은 고비용이다.

                                                          --- 텍스쳐 룩 업 테이블을 만들어서 사용하는 것도 좋다.

                                                          --- 알파 테스트 연산(discard)은 느리다. 무조건 최소로..

                                                          --- 라이트맵 활용은 필수.

                                                          * 실수 연산

                                                          --- float : 32bit -> 버텍스 변환에 사용, 아주 느린 성능 (픽셀 셰이더에서 사용은 피함)

                                                          --- Half : 16bit -> 텍스쳐 uv에 적합, 대략 2배 빠름

                                                          --- fixed : 10bit -> 컬러, 라이트 계산과 같은 고성능 연산에 적합, 대략 4배 빠름]

                                                           

                                                          6. 물리 엔진 최적화

                                                          --- FixedUpdate()는 Updata와 별도로 주기적으로 불리며, 주로 물리 엔진 처리

                                                          --- Default는 0.02초, 게임에 따라 0.2초 정도로 수정해도 문제 없음

                                                          --- 물리 엔진이 적용되지 않는 오브젝트는 Static으로 설정

                                                          --- 리지드 바디가 없는 고정 충돌체를 움직이면, CPU 부하 발생 - 물리 월드 재구성 - 이럴경우 isKinematic 옵션 사용

                                                          --- Maximum Allowed timestep 조정하여 물리 계산을 건너뛸 수 있는 부분은 무조건 건너 뛴다.

                                                          --- EDIT -> Project Setting -> Physics 에서 Solver Iteration Count 조정. 높을수록 정교하므로 낮게 설정한다.

                                                          --- Sleep 조절 -> 리지드 바디의 속력이 설정된 값보다 작을 경우, 휴면상태에 들어감.

                                                          --- Physics.Sleep() 함수를 이용하면, 강제 휴면 상태로 만듬.

                                                          --- 래그돌 사용 최소화

                                                          --- 태그 대신 레이어 활용 - 물리처리에서 레이어가 훨씬 유리, 성능과 메모리에서 장점을 가진다.

                                                          --- 메쉬 콜리더는 절대 사용 금지.

                                                          --- 레이캐스와 Sphere Check 같은 충돌 감지 요소를 최소화

                                                          --- Tilemap Collision Mesh -- 2D 게임에서 타일맵의 Collison Mesh를 최적화 하라.

                                                           

                                                          반응형

                                                          + Recent posts