Material Exchange in Unity
Realtime Material Exchange in Unity
앞선 내용 참조 : http://micropilot.tistory.com/category/Unity3D%20Car/Speed%20Limit
자동차가 정상적으로 주행시에는 뒷부분의 백라이트가 모두 꺼진 상태가 되고 운전자가 브레이크를 적용하면 빨간 브레이크 등이 켜지며 후진할 때는 후진등이 켜진다.
[백라이트 실시간 교체적용의 효과]
브레이크 적용, 정지시 | 주행시 | 후진시 |
|
|
|
유니티에서 화면에 나타나는 색상이나 질감을 달리 표현할 때는 일반적으로 다른 Material 을 적용해주면 된다. 주행시의 조건에 따라서 Material 을 달리 적용해야 하기 때문에 스크립트에서 실시간으로 Material 을 변경할 필요가 있다. 이 작업은 시기에 따라서 두부분으로 나누어 볼 수 있다
[Material 실시간 교체를 위한 2단계 작업]
- 프로그램 실행 전에 유니티 에디터에서 사전에 준비해야 할 내용
- 프로그램 실행시에 스크립트에서 실시간으로 해야 할 내용
프로그램 실행 전에 유니티 에디터에서 사전에 준비해야 할 내용
- Material 을 실시간으로 교체한다는 것은 최소한 2개의 Material 이 있어야 하므로 다음과 같은 방법으로 2개의 Material 을 준비한다
- Hieriarchy 뷰에서 어떤 GameObject 에 대한 Material 을 실시간에 변경해야 하는지 확인한다
- Hierarchy 뷰에서 특정 GameObject 를 클릭하면 우측 Inspector 뷰의 Mesh Renderer 섹션에 Material 항목에서 현재 적용된 Material의 이름이 나타난다
- GameObject 에 적용된 Material 이 아직 없는 경우에는 프로젝트 뷰에서 원하는 특정 Material 을 드래그하여 할당할 수 있다
- Inspector 뷰의 Mesh Renderer의 Material 항목에 나타난 텍스쳐 이미지를 클릭하면 프로젝트 뷰의 해당 텍스쳐 이미지가 선택되어 확인된다
- 프로젝트 뷰에서 확인된 텍스쳐 이미지를 한개 더 복사하여 그림판이나 포토샵 등을 이용하여 원하는 색상으로 변경하여 다시 저장한다
- 프로젝트 뷰에서 마우스 우측을 눌러 Create > Material 을 선택하고 재질의 이름을 적절히 변경한다
- 새로 생성한 Material 을 프로젝트 뷰에서 선택하면 우측 인스펙터 뷰에서 Shader를 적절히 선택하고 Base(RGB)항목의 select 아이콘을 눌러서 원하는 텍스쳐 이미지를 Material 에 할당할 수 있고, 프로젝트 뷰에서 텍스쳐 이미지를 드래그하여 select 아이콘 위로 드래그하여 놓으면 Material 에 텍스쳐를 적용할 수 있다
- 완성된 Material 을 GameObject 에 할당하려면, Hierarchy 뷰에서 원하는 GameObject 를 선택하고 우측 Inspector 뷰의 Material 항목으로 프로젝트 뷰의 Material 을 드래그하여 할당해주면 된다
프로그램 실행시에 스크립트에서 실시간으로 해야 할 내용
위에서 준비된 2개의 Material 을 스크립트에서 특정조건이 되면 서로 교체한다는 내용을 아래와 같이 작성하고 Car 오브젝트에 드래그하여 할당한다
[Car.cs]
using UnityEngine;
using System.Collections;
public class Car : MonoBehaviour {
// 자동차 바퀴 방향조종을 위한 Transform 4개
public Transform tireTransformFL;
public Transform tireTransformFR;
public Transform tireTransformRL;
public Transform tireTransformRR;
public WheelCollider colliderFR;
public WheelCollider colliderFL;
public WheelCollider colliderRR;
public WheelCollider colliderRL;
// 바퀴 회전을 위한 Transform
public Transform wheelTransformFL;
public Transform wheelTransformFR;
public Transform wheelTransformRL;
public Transform wheelTransformRR;
// 속도에 따라서 방향전환율을 다르게 적용하기 위한 준비
public float highestSpeed = 500f;
public float lowSpeedSteerAngle = 0.1f;
public float highSpeedStreerAngle = 25f;
// 감속량
public float decSpeed = 7f;
// 속도제한을 위한 변수들
public float currentSpeed;
public float maxSpeed = 350f; // 전진 최고속도
public float maxRevSpeed = 100f; // 후진 최고속도
// 백라이트 조정
public GameObject brakeLight;
public GameObject reverseLight;
public Material backBrakeIdle;
public Material backBrakeLight;
public Material backReverseIdle;
public Material backReverseLight;
public int maxTorque = 10;
private float prevSteerAngle;
// Use this for initialization
void Start () {
rigidbody.centerOfMass = new Vector3(0,-1,0); // 무게중심이 높으면 차가 쉽게 전복된다
}
// Update is called once per frame
void FixedUpdate () {
Control ();
}
void Update() {
// 앞바퀴 2개를 이동방향으로 향하기
tireTransformFL.Rotate (Vector3.up, colliderFL.steerAngle-prevSteerAngle, Space.World);
tireTransformFR.Rotate (Vector3.up, colliderFR.steerAngle-prevSteerAngle, Space.World);
prevSteerAngle = colliderFR.steerAngle;
}
void Control() {
// 최고속도 제한
currentSpeed = 2 * 3.14f * colliderRL.radius * colliderRL.rpm * 60 / 1000;
currentSpeed = Mathf.Round (currentSpeed);
if (currentSpeed <= 0 && currentSpeed > -maxSpeed) {//전진속도 제한
colliderRR.motorTorque = -maxTorque * Input.GetAxis("Vertical");
colliderRL.motorTorque = -maxTorque * Input.GetAxis("Vertical");
} else if (currentSpeed >= 0 && currentSpeed < maxRevSpeed) {//후진속도 제한
colliderRR.motorTorque = -maxTorque * Input.GetAxis("Vertical");
colliderRL.motorTorque = -maxTorque * Input.GetAxis("Vertical");
} else {
colliderRR.motorTorque = 0;
colliderRL.motorTorque = 0;
}
BackLight ();
// 전후진 키를 누르지 않으면 제동이 걸리도록 한다
if (!Input.GetButton ("Vertical")) {
colliderRR.brakeTorque = decSpeed;
colliderRL.brakeTorque = decSpeed;
reverseLight.renderer.material = backReverseIdle;
brakeLight.renderer.material = backBrakeLight;
} else {
colliderRR.brakeTorque = 0;
colliderRL.brakeTorque = 0;
}
// 속도에 따라 방향전환율을 달리 적용하기 위한 계산
float speedFactor = rigidbody.velocity.magnitude / highestSpeed;
/** Mathf.Lerp(from, to, t) : Linear Interpolation(선형보간)
* from:시작값, to:끝값, t:중간값(0.0 ~ 1.0)
* t가 0이면 from을 리턴, t가 1이면 to 를 리턴함, 0.5라면 from, to 의 중간값이 리턴됨
*/
float steerAngle = Mathf.Lerp (lowSpeedSteerAngle, highSpeedStreerAngle, 1/speedFactor);
//print ("steerAngle:" + steerAngle);
steerAngle *= Input.GetAxis("Horizontal");
//좌우 방향전환
colliderFR.steerAngle = steerAngle;
colliderFL.steerAngle = steerAngle;
/*colliderFR.steerAngle = 17 * Input.GetAxis("Horizontal");
colliderFL.steerAngle = 17 * Input.GetAxis("Horizontal"); */
// 바퀴회전효과
wheelTransformFL.Rotate (colliderFL.rpm/60*360 * Time.fixedDeltaTime, 0, 0);
wheelTransformFR.Rotate (colliderFR.rpm/60*360 * Time.fixedDeltaTime, 0, 0);
wheelTransformRL.Rotate (colliderRL.rpm/60*360 * Time.fixedDeltaTime, 0, 0);
wheelTransformRR.Rotate (colliderRR.rpm/60*360 * Time.fixedDeltaTime, 0, 0);
}
// 브레이크 등, 후진 등 점멸제어
void BackLight() {
if (currentSpeed <= 0 && currentSpeed > -maxSpeed) { //전진시
reverseLight.renderer.material = backReverseIdle;
brakeLight.renderer.material = backBrakeIdle;
} else if (currentSpeed >= 0 && currentSpeed < maxRevSpeed) { //후진시
reverseLight.renderer.material = backReverseLight;
brakeLight.renderer.material = backBrakeIdle;
}
if (!Input.GetButton ("Vertical")) { // 브레이크 작동시
reverseLight.renderer.material = backReverseIdle;
brakeLight.renderer.material = backBrakeLight;
}
}
}
[Scene 뷰에서 특정 GameObject 를 선택하면 Hierarchy 뷰와 Inspector뷰에 그 오브젝트적용된 Material 정보가 나타난다]
GameObject 에 기 적용된 텍스쳐 이미지를 복사하여 새로운 텍스쳐 이미지 생성하기
위의 그림과 같이 인스펙터 뷰에서 Material의 select 아이콘을 클릭하면 Project 뷰에 해당 텍스쳐 이미지가 밝게 선택되어 확인된다
확인된 텍스쳐 이미지 위에서 마우스를 누르고 [Show in Explorer]를 선택하여 탐색기가 열리면 탐색기에서 그 이미지를 한개 더 복사하여 새로운 Material 에 적용할 준비를 한다
새로운 Material 을 생성하고 Material 에 텍스쳐 이미지 설정하기
프로젝트 뷰의 Material 폴더에 마우스 우측을 누르고 Create > Material 을 선택하여 새로운 Material 을 생성하고 이름을 적절히 변경한다
새로 생성된 Material을 선택하여 Inspector 뷰에 나타난 Base(RGB)항목의 select 아이콘 위에 프로젝트 뷰에 있는 텍스쳐 이미지를 드래그한다
자동차 백라이트 점멸을 표현한 4개의 Material 생성
위에서 언급한 방법에 따라서 다음과 같은 Material 을 생성한다
BackBrakeIdle : 운전자가 브레이크를 적용하지 않을 때 등이 꺼진 브레이크 라이트를 표현한 Material(어두운 적색)
BackBrakeLight : 운전자가 브레이크를 적용할 때 브레이크 등이 켜진 상태를 표현(적색)
BackReverseIdle : 후진등이 꺼진 상태. 전진주행이나 브레이크가 적용될 때 등이 꺼진 상태를 표현(오렌지색)
BackReverseLight : 후진중일 때 후진 등이 켜진 상태를 표현(흰색)
GameObject 의 Material 교체를 위해 스크립트에 선언할 참조변수
스크립트에서 위에 언급된 Material 를 교체해야 하므로 스크립트에서 이들 Material 을 변수로 선언해야 한다
그리고 Material 은 화면에 보여지는 GameObject 의 질감이나 색상의 표현에 해당하므로 Material 이 적용된 GameObject의 Mesh Render의 참조도 필요하므로 스크립트에서는 Material 이 적용될 GameObject 의 참조변수도 선언해야 한다
결국 여기서는 2개의 GameObject ( BrakeLight, ReverseLight ) GameObject 가 필요하고 4개의 Material 참조변수가 필요한 셈이다
[참조변수를 선언한 스크립트 일부분]
public GameObject brakeLight;
public GameObject reverseLight;
public Material backBrakeIdle;
public Material backBrakeLight;
public Material backReverseIdle;
public Material backReverseLight;
스크립트에 선언된 2개의 GameObject, 4개의 Material 변수에 해당 참조 할당
Hierarchy 뷰에서 Car 오브젝트를 선택하고 Car.cs 스크립트를 드래그하여 할당하고 아래의 그림과 같이 드래그하여 참조를 할당한다
스크립트에 자동차 백라이트 제어를 위한 함수 정의
아래의 코드는 자동차 모델의 상태에 따라서 if 조건문이 달라질 수 있으므로 절대적인 것은 아니다.
public GameObject brakeLight;
public GameObject reverseLight;
public Material backBrakeIdle;
public Material backBrakeLight;
public Material backReverseIdle;
public Material backReverseLight;
..........
...............
// 브레이크 등, 후진 등 점멸제어
void BackLight() {
if (currentSpeed <= 0 && currentSpeed > -maxSpeed) { //전진시
reverseLight.renderer.material = backReverseIdle;
brakeLight.renderer.material = backBrakeIdle;
} else if (currentSpeed >= 0 && currentSpeed < maxRevSpeed) { //후진시
reverseLight.renderer.material = backReverseLight;
brakeLight.renderer.material = backBrakeIdle;
}
if (!Input.GetButton ("Vertical")) { // 브레이크 작동시
reverseLight.renderer.material = backReverseIdle;
brakeLight.renderer.material = backBrakeLight;
}
}
새로 생성한 Material 을 GameObject 에 적용하기
유니티 에디터에서 GameObject 에 Material을 적용하는 것은 실시간 Material 교체라는 개념과는 다르지만 필요하다면 다음과 같이 하면 된다
Hierarchy 뷰에서 특정 GameObject 를 선택하고 우측 Inspector 뷰에 나타난 Material 항목에 Project 뷰에 있는 Material 을 드래그하여 할당하면 된다
실행 테스트
브레이크 적용, 정지시 |
주행시 |
후진시 |
|
|
|