'Unity를 활용한 Parametric Design Program - Scaling 실습'에서 모델 전체 x scale을 키우는 실습을 해봤으니, 이제 주요 부품들을 늘이고 줄여보자.
https://jjuke-brain.tistory.com/70?category=923168
목차
1. 주요 부품별로 계층 생성해주기 (묶어주기)
3D CAD 파일 상에서는 부품별로 계층을 가지며 묶여있다. 예를 들면, MCT Model이라는 전체 3D 모델 안에 바깥 껍데기(?)부분, ATC 부품, Table 부품이 있고, 껍데기 안에는 도어, 메인 바디, 기름통 등의 하위 부품들이 있고, 계속 이런식으로 가다보면 결국 계층적으로 가장 하위에 있는 나사 등의 세부 부품들이 있다.
그런데 3D CAD 파일 (step파일)을 stl파일로 변환하고, blender에서 stl파일을 fbx파일로 변환하여 unity 상에 import하게 되면, 이러한 계층 구조가 아래 사진과 같이 다 사라지게 된다.
따라서, 주요 부품들의 스케일을 조정하기 위해서는 이들을 계층적으로 묶어주어야 한다.
('PiXYZ'라는 플러그인을 사용하면 CAD파일과 Unity 내부에 import할 fbx파일을 쉽게 연동할 수 있는 듯 한데, 유료니까 패스..)
1) Unpacking
먼저, 모델을 unpack해주어야 한다.
fbx파일을 처음 임포트하면 위 사진과 같이 하위 부품들이 모두 파란색으로 표시된다. 이는 패킹(packing)되어 있다는 의미인데, 이 상태에서는 모델 내부의 구조를 변경해줄 수 없다.
예를 들어 단순히 41-1 부품을 41_10-1 부품 아래에 위치시키는 작업조차 아래와 같은 오류 문구를 보이며 해줄 수 없게 된다.
unpack해주는 방법은 간단하다.
'모델 우클릭 → Prefab → Unpack Completely'를 눌러주면 아래와 같이 부품들 글씨 색이 바뀌고, 위치 이동 등이 자유로워진다.
2) 계층 생성 (묶기)
이제 부품별로 묶어주는 작업을 해야한다.
노가다가 필요한데, 원하는 부품들을 모두 찾아 새로운 Game Object에 넣어주면 된다.
우선 모델을 우클릭하여 'Create Empty'를 선택하고, 빈 Game Object를 만들어 준다.
이제, 드래그앤 드롭으로 GameObject 하위에 원하는 부품들을 넣고, GameObject의 이름을 바꿔주자
예를 들어, 41-1 ~ 41_10-1 부품까지 GameObject에 넣고, 이를 '부품1'이라고 지정해보겠다.
이렇게 묶어주면, '부품1' 전체의 위치를 변경하고, scale을 변경하는 등의 작업을 해줄 수 있다.
부품1은 여러 부품이 잘 표시되지 않아서, 다음과 같이 '부품2'를 설정하여 그 부품들만 움직여보았다.
노가다 작업을 다 끝내고, 다음과 같이 이쁘게(?) 계층을 설정해 주었다.
새로운 모델을 하단의 Project 창에 드래그앤드롭하여 다른 씬에서도 사용 가능하도록 새로운 Prefab으로 만들어주면 노가다 작업이 끝난다.
2. 투명화, 유색화 (Transparenting, Coloring)
최종적으로 부품들을 움직이거나 스케일을 조정할건데, 이놈의 껍데기때문에 부품들이 움직이는게 보이질 않는다.
따라서, 버튼 조작을 통해 관심있는 부품만 색을 표현하고, 관심 없는 부품들은 C# 스크립트에서 설정을 바꾸어 투명하게 만들어 줄 것이다.
'Unity를 활용한 Parametric Design Program - Scaling 실습'글에서 생성했던 test_parametric_design.cs 파일을 수정해보자.
먼저 기존 내용은 다음과 같다. (x축 scale 조정 함수만 있는 상태이다.)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class test_parametric_design : MonoBehaviour
{
public Vector3 shell;
public GameObject shellObjCopy;
public void ParamChange()
{
shell = shellObjCopy.transform.localScale;
shell.x = 1.5f;
shellObjCopy.transform.localScale = shell;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
1) 투명화 원리 - 변수 선언
투명하게 만들어주기 위해, gameobject의 'transform → GetComponentsInChildren<Transform>'을 통해 각 하위 부품들의 속성을 리스트에 저장하고, 'material'속성 중 'color'를 바꿔줄 것이다.
뭔소리인가 싶겠지만 코드를 보면 어느 정도 이해가 될 것이다.
먼저, 상위 부품(컴포넌트)을 받아와야 한다. 그리고 각각의 상위 부품에 대해 하위 부품들의 속성을 담을 list를 선언해준다.
위 사진과 같이 Model 내에 상위 부품이 9개 있다면 GameObject와 Transform[](list니까 [] 붙여서!) 인스턴스를 9개씩 선언해준다.
//============================================================
// 투명화
//============================================================
// 상위 컴포넌트의 색상을 투명, 유색 상태로 전환하기 위해서는 하위 컴포넌트들을 받아야 한다.
// 상위 부품 각각을 불러올 gameobject 선언
public GameObject cnc_0, cnc_1, cnc_2, cnc_3, cnc_4,
cnc_5, cnc_6, cnc_7,cnc_8; // 상위 부품 총 9개
// 상위 부품 각각에 대해 하위 부품을 받아올 list 선언
public Transform[] List_0, List_1, List_2, List_3, List_4,
List_5, List_6, List_7, List_8;
2) ChangeColor 함수
이제 속성을 받아와 리스트에 저장하고, 색상을 바꿀 수 있는 'ChangeColor'라는 함수를 선언해보자.
public void ChangeColor(GameObject Object1, Transform[] List, Render mesh_child, Material mat, float a, int mode)
{
List = Object1.transform.GetComponentsInChildren<Transform>();
if (mode == 3)
{
foreach (Transform child in List)
{
mesh_child = child.GetComponent<Render>();
mat = mesh_child.material;
mat.SetFloat("_Mode", 3);
mat.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
mat.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
mat.SetInt("_ZWrite", 0);
mat.DisableKeyword("_ALPHATEST_ON");
mat.DisableKeyword("_ALPHABLEND_ON");
mat.EnableKeyword("_ALPHAREMULTIPLY_ON");
mat.renderQueue = 3000;
Color oldColor = mat.color;
// a가 투명도 parameter
mesh_child.material.color = new Color(oldColor.r, oldColor.g, oldColor.b, a);
}
}
if (mode == 0)
{
foreach (Transform child in List)
{
mesh_child = child.GetComponent<Renderer>();
mat = mesh_child.material;
mat.SetFloat("_Mode", 0);
mat.SetInt("_SrcBlend", 1);
mat.SetInt("_DstBlend", 0);
mat.SetInt("_ZWrite", 1);
mat.EnableKeyword("_ALPHATEST_ON");
mat.DisableKeyword("_ALPHABLEND_ON");
mat.EnableKeyword("_ALPHAPREMULTIPLY_ON");
mat.renderQueue = 2000;
Color oldColor = mat.color;
mesh_child.material.color = new Color(oldColor.r, oldColor.g, oldColor.b, a);
}
}
}
- 'Object1.transform.GetComponentsInChildren<Transform>();'에서 각 상위 부품들의 하위 부품들의 Transform속성을 list에 넣어준다. Object1은 상위 부품을 의미한다.
- 'GetComponent<Render>()'을 통해 list에 받아온 Transform 속성 각각의 'Render'속성을 받아온다.
- mat 변수에 render 속성 중 material 속성을 받아와 투명화 또는 유색화를 진행한다.
3) 버튼 클릭 이벤트로 투명화할 변수와 함수 선언
그리고 버튼 클릭을 통해 특정 상위 부품만 유색화하고, 나머지는 투명화시키는 함수들을 다음과 같이 만들어주자.
// transparenting trigger, 7개 상위 부품 transparenting trigger
bool isTransparent;
bool is1stButtonClicked;
bool is2ndButtonClicked;
bool is3rdButtonClicked;
bool is4thButtonClicked;
bool is5thButtonClicked;
bool is6thButtonClicked;
bool is7thButtonClicked;
// 투명화 trigger 함수
public void StartTransparentTrigger() {
isTransparent = true;
}
public void StopTransparentTrigger() {
isTransparent = false;
}
void Transparenting() {
// 투명화 진행 시 아예 빼버릴 컴포넌트
cnc_3.SetActive(false);
cnc_4.SetActive(false);
// 처음에는 모두 투명
ChangeColor(cnc_0, List_0, Rend_0, Mat_0, 0, 3);
ChangeColor(cnc_1, List_1, Rend_1, Mat_1, 0, 3);
ChangeColor(cnc_2, List_2, Rend_2, Mat_2, 0, 3);
ChangeColor(cnc_5, List_5, Rend_5, Mat_5, 0, 3);
ChangeColor(cnc_6, List_6, Rend_6, Mat_6, 0, 3);
ChangeColor(cnc_7, List_7, Rend_7, Mat_7, 0, 3);
ChangeColor(cnc_8, List_8, Rend_8, Mat_8, 0, 3);
// 버튼 클릭에 따라 각 상위 부품만 유색화
if (is1stButtonClicked == true) {
ChangeColor(cnc_0, List_0, Rend_0, Mat_0, 1, 0);
}
if (is2ndButtonClicked == true) {
ChangeColor(cnc_1, List_1, Rend_1, Mat_1, 1, 0);
}
if (is3rdButtonClicked == true) {
ChangeColor(cnc_2, List_2, Rend_2, Mat_2, 1, 0);
}
if (is4thButtonClicked == true) {
ChangeColor(cnc_5, List_5, Rend_5, Mat_5, 1, 0);
}
if (is5thButtonClicked == true) {
ChangeColor(cnc_6, List_6, Rend_6, Mat_6, 1, 0);
}
if (is6thButtonClicked == true) {
ChangeColor(cnc_7, List_7, Rend_7, Mat_7, 1, 0);
}
if (is7thButtonClicked == true) {
ChangeColor(cnc_8, List_8, Rend_8, Mat_8, 1, 0);
}
}
void StopTransparenting() {
cnc_3.SetActive(true);
cnc_4.SetActive(true);
ChangeColor(cnc_0, List_0, Rend_0, Mat_0, 1, 0);
ChangeColor(cnc_1, List_1, Rend_1, Mat_1, 1, 0);
ChangeColor(cnc_2, List_2, Rend_2, Mat_2, 1, 0);
ChangeColor(cnc_3, List_3, Rend_3, Mat_3, 1, 0);
ChangeColor(cnc_4, List_4, Rend_4, Mat_4, 1, 0);
ChangeColor(cnc_5, List_5, Rend_5, Mat_5, 1, 0);
ChangeColor(cnc_6, List_6, Rend_6, Mat_6, 1, 0);
ChangeColor(cnc_7, List_7, Rend_7, Mat_7, 1, 0);
ChangeColor(cnc_8, List_8, Rend_8, Mat_8, 1, 0);
}
상위 부품 중 2개 (useless, 껍데기)는 scale 조정과 투명화 시 아예 빼버릴 것이다. (SetActive → false)
이에 따라 버튼을 총 9개 만들 것이다. 두 개는(버튼1, 2라 명명)는 scale 조정 및 투명화를 실행 또는 종료할 버튼, 나머지(버튼3 ~ 버튼9이라 명명)는 유색화와 scale을 조정을 적용할 상위 부품을 고르는 버튼이다.
각 버튼을 눌렀을 때 실행되는 함수와 실행될 결과는 다음과 같다.
- 버튼 1: StartTransparentTrigger()함수를 실행하여 씬이 실행된 환경 상에서 'scale 조정 모드'에 들어간다. 이때 모델 전체가 투명해지며, 부품을 보는 데 방해되는 MainBody(껍데기)와 Useless 부품들을 빼버린다.
- 버튼 2: StopTranspareentTrigger()함수를 실행하여 씬이 실행된 환경 상에서 'scale 조정 모드'를 종료하고, 처음으로 돌아간다.
- 버튼 3: 'MCT ControlPanelARM' 부품을 유색화하고, Scale 조정을 시작한다.
- 버튼 4: 'MCT ATC' 부품을 유색화하고, Scale 조정을 시작한다.
- 버튼 5: 'MCT ControlPanel' 부품을 유색화하고, Scale 조정을 시작한다.
- 버튼 6: 'MCT AxisLocation' 부품을 유색화하고, Scale 조정을 시작한다.
- 버튼 7: 'MCT ChuckColumn' 부품을 유색화하고, Scale 조정을 시작한다.
- 버튼 8: 'MCT Saddle' 부품을 유색화하고, Scale 조정을 시작한다.
- 버튼 9: 'MCT Table' 부품을 유색화하고, Scale 조정을 시작한다.
4) prefab을 찾아 변수에 할당
이제 void Start()에서 GameObject들을 unity hierarchy 상에서 찾아주는 'GameObject.Find()'함수를사용하여 상위 부품들을 찾아 변수에 할당해준다.
참고로 void Start()는 씬이 실행될 초기에 한 번 실행된다.
// Start is called before the first frame update
void Start()
{
cnc_0 = GameObject.Find("MCT ControlPanelARM");
cnc_1 = GameObject.Find("MCT ATC");
cnc_2 = GameObject.Find("MCT ControlPanel");
cnc_3 = GameObject.Find("MCT MainBody");
cnc_4 = GameObject.Find("MCT Useless");
cnc_5 = GameObject.Find("MCT AxisLocation");
cnc_6 = GameObject.Find("MCT ChuckColumn");
cnc_7 = GameObject.Find("MCT Saddle");
cnc_8 = GameObject.Find("MCT Table");
}
다음 글에서 Scaling 관련 함수를 조금 수정해주고, 결과를 살펴볼 것이다.
최근댓글