More Related Content
Similar to ARグラスで 魅力的な絵作り (10)
More from Kazuya Hiruma (20)
ARグラスで 魅力的な絵作り
- 27. 27
ポストプロセスで上下左右の際をフェードアウトさせる
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
float2 uv = abs(i.uv * 2.0 - 1.0);
float2 u = _Width / _ScreenParams.xy * 0.5;
u = smoothstep(0, u, 1.0 - uv);
col = col * u.x * u.y;
return col;
}
UV値を利⽤して画⾯端に近づくにつれてフェードさせる
(ARグラスは黒=発光しない=透明になっていく)
- 39. 39
パーティクルのターゲット変更
[numthreads(THREAD_NUM,1,1)]
void Update(uint id : SV_DispatchThreadID)
{
Particle p = _Particles[id];
float4x4 mat = _MatrixData[_InitDataList[id].targetId];
p.isActive = _InitDataList[id].isActive;
p.targetPosition = mul(mat, float4(_InitDataList[id].targetPosition,
1.0)).xyz;
p.uv = _InitDataList[id].uv;
p.targetId = _InitDataList[id].targetId;
_Particles[id] = p;
}
パーティクルのターゲット先を変更(更新)する
- 40. 40
パーティクルのターゲット変更
[numthreads(THREAD_NUM,1,1)]
void Explosion(uint id : SV_DispatchThreadID)
{
Particle p = _Particles[id];
if (_OnCircle == 1)
{
float h = rand(p.id);
float s = sin(p.id + _Time) * 1.5;
float c = cos(p.id + _Time) * 1.5;
float3 pp = float3(s, h * 1.5, c) + noise(p.position);
float3 pos = (pp - p.position) * _DeltaTime * p.speed;
p.position += pos;
p.color = float4(1, 1, 1, 1);
p.useTexture = 0;
}
else
{
float h = rand(p.id);
float3 pos = (p.targetPosition + float3(0, cos(h + _Time) * 0.01, 0) -
p.position) * _DeltaTime * p.speed;
p.position += pos;
}
p.color = float4(1, 1, 1, 1);
p.useTexture = 0;
_Particles[id] = p;
}
別形状のためのカーネル
- 42. 42
メッシュの情報を集める
public class ParticleTarget : MonoBehaviour
{
private Mesh _mesh = null;
public Mesh Mesh => _mesh ?? (_mesh = GetComponent<MeshFilter>().mesh);
private Renderer _renderer = null;
private Renderer Renderer => _renderer ?? (_renderer =
GetComponent<Renderer>());
public int VertexCount => Mesh.vertexCount;
public Vector3[] Vertices => Mesh.vertices;
public Vector2[] UV => Mesh.uv;
public Matrix4x4 WorldMatrix => transform.localToWorldMatrix;
public Texture2D Texture => Renderer.material.mainTexture as Texture2D;
}
シンタックスシュガー的にデータを渡すだけのコード
- 43. 43
頂点、UV情報をひとつの配列にまとめる
private void CollectAllData()
{
int count = GetCount();
_allVertices = new Vector3[count];
_allUV = new Vector2[count];
int idx = 0;
foreach (var t in _targets)
{
System.Array.Copy(t.Vertices, 0, _allVertices, idx,
t.Vertices.Length);
System.Array.Copy(t.UV, 0, _allUV, idx, t.UV.Length);
idx += t.Vertices.Length;
}
}
グループの頂点などをメモリアクセスしやすいように配列にまとめる
- 44. 44
ターゲットモデルのマトリクスをまとめる
private void UpdateMatrices(ParticleTargetGroup group)
{
for (int i = 0; i < group.ParticleTargets.Length; i++)
{
_matrixData[i] = group.ParticleTargets[i].WorldMatrix;
}
_matrixBuffer.SetData(_matrixData);
_computeShader.SetBuffer(_kernelSetup, _propertyDef.MatrixDataID,
_matrixBuffer);
}
各頂点の⾏列計算はシェーダで⾏うためMatrixデータをまとめてGPUに送る
- 45. 45
テクスチャをTextureArrayにまとめる
private void CreateTextureArray()
{
int count = _targets.Length;
int width = _targets[0].Texture.width;
int height = _targets[0].Texture.height;
_textureArray = new Texture2DArray(width, height, count,
TextureFormat.RGBA32, false, true);
_textureArray.filterMode = FilterMode.Bilinear;
_textureArray.wrapMode = TextureWrapMode.Repeat;
for (int i = 0; i < _targets.Length; i++)
{
_textureArray.SetPixels(_targets[i].Texture.GetPixels(0), i, 0);
}
_textureArray.Apply();
}
Matrix同様、テクスチャもシェーダ側でアクセスするためTextureArrayにまとめる
- 47. 47
GPUインスタンシングで描画
v2f vert (appdata v, uint id : SV_InstanceID)
{
Particle p = _Particles[id];
v2f o;
v.vertex.xyz = (v.vertex.xyz * _BaseScale) +
p.position;
o.vertex = mul(UNITY_MATRIX_VP,
float4(v.vertex.xyz, 1.0));
o.uv.xy = p.uv.xy;
o.uv.z = p.targetId;
o.color = p.color;
o.texid = p.targetId;
o.useTex = p.useTexture;
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col;
if (i.useTex == 1)
{
col = UNITY_SAMPLE_TEX2DARRAY(_Textures,
i.uv);
col = pow(col, 1.5);
}
else
{
col = i.color;
}
return col;
}
Compute Shaderの計算に基づいてパーティクルをレンダリングする
頂点シェーダ フラグメントシェーダ
- 48. 48
GPUインスタンシングで描画
DrawMeshInstancedIndirectメソッドで⼀度に描画
private void DrawParticles()
{
Graphics.DrawMeshInstancedIndirect(
_particleMesh,
0, // submesh index
_particleMat,
new Bounds(Vector3.zero, Vector3.one * 32f),
_argsBuffer,
0,
null,
UnityEngine.Rendering.ShadowCastingMode.Off,
false,
gameObject.layer
);
}