1. 다음과 같은 매터리얼을 준비한다.
2. 빈 오브젝트를 생성하고 파티클 컴포넌트를 생성한 뒤, 다음과 같이 파티클 설정을 하여 프리팹으로 만든다. 차후 스크립트에서 'Start Rotation'과 'Start Color'항목을 변경할 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
using UnityEngine;
using System.Collections;
public class scrVisualizer : MonoBehaviour{
public int iSegmentPoweOfTwo = 64;
public GameObject objParticle;
private float[] ins_fLeftTable;
private float[] ins_fRightTable;
private float[] ins_fMixedTable;
private GameObject[] ins_objParticleTable;
private static Vector3 ins_HSV2RGB(Vector3 _HSV){
_HSV.x = (100 + _HSV.x) % 1;
float HueSlice = 6 * _HSV.x;
float HueSliceInteger = Mathf.Floor(HueSlice);
float HueSliceInterpolant = HueSlice - HueSliceInteger;
Vector3 TempRGB = new Vector3(
_HSV.z * (1 - _HSV.y),
_HSV.z * (1 - _HSV.y * HueSliceInterpolant),
_HSV.z * (1 - _HSV.y * (1 - HueSliceInterpolant))
);
float IsOddSlice = HueSliceInteger % 2;
float ThreeSliceSelector = 0.5f * (HueSliceInteger - IsOddSlice);
Vector3 ScrollingRGBForEvenSlices = new Vector3(_HSV.z, TempRGB.z, TempRGB.x);
Vector3 ScrollingRGBForOddSlices = new Vector3(TempRGB.y, _HSV.z, TempRGB.x);
Vector3 ScrollingRGB = Vector3.Lerp(ScrollingRGBForEvenSlices, ScrollingRGBForOddSlices, IsOddSlice);
float IsNotFirstSlice = Mathf.Clamp01(ThreeSliceSelector);
float IsNotSecondSlice = Mathf.Clamp01(ThreeSliceSelector - 1);
return Vector3.Lerp(
ScrollingRGB,
Vector3.Lerp(
new Vector3(ScrollingRGB.z, ScrollingRGB.x, ScrollingRGB.y),
new Vector3(ScrollingRGB.y, ScrollingRGB.z, ScrollingRGB.x),
IsNotSecondSlice
),
IsNotFirstSlice
);
}
private void ins_getSpectrum(){
AudioListener.GetSpectrumData(ins_fLeftTable, 0, FFTWindow.Triangle);
AudioListener.GetSpectrumData(ins_fRightTable, 1, FFTWindow.Triangle);
for (int i = 0; i < iSegmentPoweOfTwo; ++i)ins_fMixedTable[i] = ins_fLeftTable[i] + ins_fRightTable[i];
}
private void ins_drawParticle(){
for (int i = 0; i < iSegmentPoweOfTwo; ++i){
float f = Mathf.Lerp(0, Mathf.PI * 2, (float)i / (float)iSegmentPoweOfTwo);
ins_objParticleTable[i].transform.localPosition = new Vector3(
(1 + Mathf.Log(1 + ins_fMixedTable[i]) * 5) * Mathf.Cos(f),
(1 + Mathf.Log(1 + ins_fMixedTable[i]) * 5) * Mathf.Sin(f),
0
);
}
}
void Awake(){
ins_fLeftTable = new float[iSegmentPoweOfTwo];
ins_fRightTable = new float[iSegmentPoweOfTwo];
ins_fMixedTable = new float[iSegmentPoweOfTwo];
ins_objParticleTable = new GameObject[iSegmentPoweOfTwo];
for (int i = 0; i < iSegmentPoweOfTwo; ++i){
float f = (float)i / (float)iSegmentPoweOfTwo;
Vector3 hue = ins_HSV2RGB(new Vector3(f, 1, 1));
ins_objParticleTable[i] = Instantiate(
objParticle,
new Vector3(0, 0, 0),
Quaternion.AngleAxis(f * 360, Vector3.forward),
transform
) as GameObject;
ins_objParticleTable[i].GetComponent<ParticleSystem>().startColor = new Color(hue.x, hue.y, hue.z);
ins_objParticleTable[i].GetComponent<ParticleSystem>().startRotation = f * 2 * Mathf.PI;
}
transform.Rotate(Vector3.up, 180);
}
void Update(){
ins_getSpectrum();
ins_drawParticle();
}
}
3. 그리고 파티클 생성기를 위해 다음과 같이 코드를 작성한다. 코드에 관해 간단히 설명을 하자면 이렇다.
public int iSegmentPoweOfTwo; // 파티클의 개수이다. 또한 스펙트럼의 정밀도이기도 하며, 개수는 항상 2의 승수가 되어야 하고 64-8192사이의 숫자여야 한다.
public GameObject objParticle; // 파티클에 해당하는 오브젝트이다. 앞서 작성한 프리팹을 여기에 바인드 시키도록 한다.
private static Vector3 ins_HSV2RGB(Vector3 _HSV); // HSV색상을 RGB색상으로 변환한다. xyz순서로 hsv, rgb이며 0-1범위의 값을 갖는다. 빛의 파장에 따른 색상 값을 얻어오기 위해 hsv색상을 사용할 것이다.
private void ins_getSpectrum(); // 이 객체의 리스너로부터 현재 가청 중인 사운드의 스펙트럼을 얻는다. 0(left)과 1(right)채널의 스펙트럼을 각각 얻어서 더하며 이 더한 값을 사용하게 된다.
private void ins_drawParticle(); // 생성한 인스턴스들을 추출한 스펙트럼에 근거하여 움직인다. 원 형태로 퍼지며 스팩트럼 값 고/저의 차를 어느정도 균등하게 하기 위해 log를 적용하였다.
* Awake()에선 파티클 오브젝트를 생성하며, 생성된 인스턴스들에 대해 무지개 색상 형태를 띄도록 startColor에 순차적으로 빛의 파장 값을 대입하였다.
본래 위에서 조절한 파티클 옵션은 2D에서 사용되는 형태의 파티클인데, 이 파티클의 생성된 입자는 시간이 지날 수록 점점 어두워지며 사라지는 형태를 띈다.
그런데 이 과정에서 z값이 점차적으로 작아지는데 이 점을 이용하여 카메라를 원근 투영으로 전환하고 z값이 줄어드는 과정을 직접 관찰할 수 있도록 하였다.
그리고 이러한 모양은 전체적으로 직선형태로 관찰되었으며, 카메라를 중심으로 전체 파티클을 원의 자취대로 배치하니 마치 원통형 터널의 안에서 바라보는 형태를 띄게 되었다.