물 쉐이더 만들기 튜토리얼을 기반으로 만들고, 파문(Ripple)효과를 추가하였습니다.
유니티 씬 내에서 Instantiate()함수로 필요한것을 인스턴스화 하듯이 쉐이더 내에서도 Ripple을 Instantiate할 수 있지 않을까? 하며 검색하니 그런 내용은 없었습니다.
결론적으로 쉐이더 그래프에서 하나의 쉐이더로 다중 Ripple Water Effect를 어떻게 만들까 고민하던 중 유튜브의 한 튜토리얼 영상에서 Multiple Ripple을 구현하기 위해서 쉐이더 안에 여러개의 Ripple 효과에 대한 것을 준비시켜놓고 진행중이지 않은 Ripple을 재생하는 방법으로 구현한것을 발견하여 쉐이더 그래프에서도 마찬가지로 구현하도록 하였습니다.
구현 아이디어?
1. Time에서 지속적으로 파도, 물흐름 효과를 노멀맵과 Position에서 y축으로 이동하도록하여 메시의 벡터들이 움직이도록 한다.
2. Ripple Sub Shader를 메인 쉐이더(WaterShader)에 불러오고, 메시 내의 포지션에서 Ripple을 시작할 Vector2와 정해진 시간에 재생하기위한 RippleCurrentTime 변수를 선언하고 대기시킨다.
3. 트리거 등 특정 조건이 발생하면 해당 위치를 쉐이더에 넘겨주고 RippleCurrentTime( 0 ~ 1 )을 일정량 증가시켜 Ripple 효과가 나타나게 한다.
4. 활성화된 Ripple 효과가 일정 시간이 지나면 다시 초기화되어 사용 대기상태로 만든다.
5. 3->4 과정을 반복한다.
위 사진에서 대기열에 있는 Ripple들을 모두 더하여 노멀맵으로 넣어주고, y축에 대한 position으로도 추가하여 Output에 연결시킨다.
물 쉐이더 그래프를 적용한 Plane에서 Ripple 효과를 재생하기위해 스크립트를 작성하고, 특정 조건에서 Ripple효과를 재생하도록 구현한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WaterRipple : MonoBehaviour
{
//현재 대기열에 있는 Ripple의 개수(현재 12)
[SerializeField] private int mRippleLength;
//현재 사용중인 머터리얼
private Material mMaterial;
//오브젝트의 양 대각선 위치 좌표
private Vector3 mZeroPos, mOnePos;
private void Start()
{
mMaterial = GetComponent<MeshRenderer>().material;
//임시로 박스 콜라이더를 만들고 한변의 길이를 구한다.(정사각 Plane을 사용하기 때문)
BoxCollider tempCol = gameObject.AddComponent<BoxCollider>();
float radius = tempCol.bounds.size.x;
Destroy(gameObject.GetComponent<BoxCollider>());
//한 변의 길이를 가지고 양측 모서리의 위치를 구한다.
mZeroPos = transform.position + -(transform.forward + transform.right) * radius * 0.5f;
mOnePos = transform.position + (transform.forward + transform.right) * radius * 0.5f;
}
//조건. Player라는 태그의 트리거가 활성화되면 대기하는 Ripple을 재생한다.
private void OnTriggerEnter(Collider other)
{
if(other.tag == "Player")
{
other.GetComponent<Rigidbody>().AddForce(Vector3.up * 30.0f, ForceMode.Impulse);
Vector3 triggerPos = other.transform.position;
//오브젝트 내의 트리거 위치 비(0~1, 0~1)
//선분의 내접을 이용한 공식을 정리하여 비율을 구한다.
Vector2 triggerRatePos = new Vector2(Mathf.Abs((-triggerPos.x + mOnePos.x) / (mZeroPos.x - mOnePos.x)), Mathf.Abs((-triggerPos.z + mOnePos.z) / (mZeroPos.z - mOnePos.z)));
for(int i = 0; i < mRippleLength; ++i)
{
//RippleCurrentTime이 0이면 > 현재 활성화 상태가 아니다.
//위치를 초기화 시키고, 코루틴으로 실시간으로 크기를 증가시켜준다.
if(mMaterial.GetFloat("_RippleCurrentTime" + i.ToString()) == 0)
{
//위치를 triggerRatePos로 변경시켜준다.
mMaterial.SetVector("_RipplePosition" + i.ToString(), triggerRatePos);
StartCoroutine(RippleSize("_RippleCurrentTime" + i.ToString()));
return;
}
}
}
}
//사이즈를 0부터 1까지 증가시키고, 0으로 되돌려놓는다(대기상태)
IEnumerator RippleSize(string target)
{
float mCurrentSize = 0f;
while(true)
{
mCurrentSize = Mathf.Lerp(mCurrentSize, 1, Time.deltaTime);
mMaterial.SetFloat(target, mCurrentSize);
if(mCurrentSize > 0.99f)
{
mMaterial.SetFloat(target, 0f);
yield break;
}
yield return null;
}
}
}
|
cs |
Tiling And Offset을 이용하여 구현하기에 입력은 0~1까지로 제한된다. 그렇기에 트리거로부터 들어온 월드 좌표를 적절히 계산하여 오브젝트내의 새로운 좌표계인 (0,0) ~ (1,1) 이내로 변환해줘야한다.
오브젝트의 양끝 모서리를 (0,0) (1,1)로 하고 초록색 점의 위치를 범위 내로 변환해야한다.
[SerializeField] private int mRippleLength;
- 대기열에 있는 Ripple효과의 개수이다. mRippleLength만큼 반복하여 탐색 후, 대기상태인 효과를 재생시킨다.
private Vector3 mZeroPos, mOnePos;
- 오브젝트 내의 새로운 좌표계로 변환하기위한 양끝 모서리 좌표이다. ZeroPos는 (0,0)에 해당하는 월드좌표이다.
private void Start()
- 머터리얼을 가져온다.
- 오브젝트의 크기가 의도에따라 변할 수 있기에, 고정 크기를 입력하는것보다 스스로 적절히 계산하도록 해야한다.
- 박스콜라이더를 추가하여 자동생성되는 콜라이더의 한 변의 길이를 구하고 이를 크기로 계산한다.
- Plane Mesh의 Pivot은 중심에 있기에, 각 forward, right , backward, left의 방향으로 radius만큼 계산하여 모서리의 위치를 저장시킨다.
private void OnTriggerEnter(Collider other)
- 내분점을 이용하여 비율을 구하여 적절한 좌표를 구한다.
- Vector2 triggerRatePos = new Vector2(....)에서 비율을 계산한 후, 쉐이더 내의 RipplePosition에 대입시키고 크기를 변화시킨다.
- for(int i = 0; i < mRippleLength; ++i) mRippleLength만큼 반복하여 _RippleCurrentTime가 0인 인덱스를 찾아 해당 인덱스의 위치를 정하고, 크기를 변화시키며 재생시킨다.
IEnumerator RippleSize(string target)
- 쉐이더 내의 float 변수인 target의 크기를 변화시키면서 1에 가까워지면 (0.99f) 다시 0으로 되돌려 놓는다.
'unity shader' 카테고리의 다른 글
[유니티] 쉐이더 그래프 - Cartoon Water (0) | 2022.08.10 |
---|---|
[유니티] 쉐이더 그래프 - 이끼, 눈 효과 (0) | 2022.08.10 |
[유니티] 쉐이더 그래프 - 불 효과 (0) | 2022.08.07 |
[유니티] 쉐이더 그래프 - 포탈 효과 (0) | 2022.08.07 |
[유니티] 쉐이더 그래프 - 회전하는 효과 만들기 (0) | 2022.08.07 |