본문 바로가기
Project/<team Not Same> 꿈의 왕국 : 영원한 보금자리

[PJ/문제해결] Object의 materials 바꾸기

by 왹져박사 2023. 5. 28.
728x90
    public void ChangeRoof(GameObject targetGo, Material mat)
    {
        Debug.LogFormat("<color=yellow>target : {0}, mat : {1}, mats0 : {2}, mat1 : {3}</color>", targetGo, mat, 
            targetGo.GetComponent<Renderer>().materials[0], targetGo.GetComponent<Renderer>().materials[1]);
        //targetGo.GetComponent<Renderer>().materials[1] = mat;
        Material[] materials = targetGo.GetComponent<MeshRenderer>().materials;
        materials[1] = mat;
        targetGo.GetComponent<MeshRenderer>().materials = materials;
    }

현재 프로젝트에서 구역 부활(material, postprocessing 변경)은 가장 중요한 부분이다. 

대부분의 건물은 한 sprite에 다 담겨있어 같은 스크립트로 건물과 땅만 구분해 두었다. 

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MaterialManager
{
    public static readonly MaterialManager instance = new MaterialManager();
    private MaterialManager()
    {

    }

    public void ChangeOthers(string targetTag, Material mat, Texture tex)
    {
        //mat.SetTexture("_MainTex", tex);
        Debug.LogFormat("<color=red>ChangeOthers, tag : {0}</color>", targetTag);

        GameObject[] targets = GameObject.FindGameObjectsWithTag(targetTag);
        foreach (GameObject target in targets)
        {
            Renderer renderer = target.GetComponent<Renderer>();
            if (renderer != null)
            {
                Material[] materials = renderer.materials;
                for (int i = 0; i < materials.Length; i++)
                {
                    Material materialInstance = new Material(mat);
                    materialInstance.name = "colorKingdom";
                    materialInstance.mainTexture = materials[i].mainTexture; // 이전 Material의 texture를 새로 생성한 Material에 복사
                    materialInstance.mainTexture = tex;
                    materials[i] = materialInstance;
                }
                renderer.materials = materials;
            }
        }

    }
    public void ChangeGround(GameObject targetGo, Material mat)
    {
        targetGo.GetComponent<Renderer>().material = mat;
    }

}

하지만, 실행하며 보니 몇 안되는 오브젝트들이 다른 material이 적용되어 의도한 대로 변하지 않았다. 

그렇게 퀄업하며 세세한 부분까지 조정하게 되었다. 

 

작업을 진행하며, 한 오브젝트에 두가지 material을 사용하여 위 코드를 사용하면 한 가지 material로 바뀌는 문제가 있었다. 

이를 해결하기 위하여 처음에는 material의 배열을 가져와 문제의 material만 바꾸는 방식을 적용하려 하였다. 

    public void ChangeRoof(GameObject targetGo, Material mat)
    {
        Debug.LogFormat("<color=yellow>target : {0}, mat : {1}, mats0 : {2}, mat1 : {3}</color>", targetGo, mat, 
            targetGo.GetComponent<Renderer>().materials[0], targetGo.GetComponent<Renderer>().materials[1]);
        targetGo.GetComponent<Renderer>().materials[1] = mat;
    }

하지만, 아무 변화도 없었다. 문제를 찾아보려 했지만, 위의 log로 다 찍어보아도 요소들에는 문제가 전혀 없었다. 

 

https://docs.unity3d.com/ScriptReference/Renderer-materials.html

 

Unity - Scripting API: Renderer.materials

This is an array of all materials used by the renderer. Unity supports a single object using multiple materials; in this case materials contains all the materials. sharedMaterial and material properties return the first used material if there is more than

docs.unity3d.com

공식 문서에 따르면, 첫번째 material은 위의 방법대로 수정이 가능하다고 한다. 

하지만 그 이후 배열의 material을 변경하려고 한다면, 배열의 복사본을 변경시켜 새로 적용시켜야 한다고 한다. 

위의 방법대로 시도해보았다. 

    public void ChangeRoof(GameObject targetGo, Material mat)
    {
        Debug.LogFormat("<color=yellow>target : {0}, mat : {1}, mats0 : {2}, mat1 : {3}</color>", targetGo, mat, 
            targetGo.GetComponent<Renderer>().materials[0], targetGo.GetComponent<Renderer>().materials[1]);
        //targetGo.GetComponent<Renderer>().materials[1] = mat;
        Material[] materials = targetGo.GetComponent<Renderer>().materials;
        materials[1] = mat;
        targetGo.GetComponent<Renderer>().materials = materials;
    }

성공적으로 바뀌었다. 

Renderer가 아닌 MeshRenderer component를 가져와도 가능하다. (MeshRenderer는 Renderer를 상속받기 때문)

 

728x90