An open source Danmaku development kit for Unity3D.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Switch to using procedural instancing

james713 58acf888 b97a4f45

+403 -199
+5 -1
Assets/DanmakU/Runtime/Core/DanmakuManager.cs
··· 54 54 foreach (var group in RendererGroups.Values) { 55 55 group.Dispose(); 56 56 } 57 + ComputeBufferPool.DisposeShared(); 57 58 } 58 59 59 60 /// <summary> ··· 189 190 return update; 190 191 } 191 192 192 - public void Render(int layer) => Renderer.Render(Sets, layer); 193 + public void Render(int layer) { 194 + Renderer.FlushBuffers(); 195 + Renderer.Render(Sets, layer); 196 + } 193 197 194 198 public void Dispose() { 195 199 Renderer.Dispose();
+2 -12
Assets/DanmakU/Runtime/Core/DanmakuPool.cs
··· 83 83 /// The recommended batch size for processing Danmaku in parallelizable jobs. 84 84 /// </summary> 85 85 /// <seealso cref="Unity.Jobs.IJobParallelFor"/> 86 - public const int kBatchSize = 32; 86 + public const int kBatchSize = 1; 87 87 const int kGrowthFactor = 2; 88 88 89 89 /// <summary> ··· 138 138 public NativeArray<Vector4> Colors; 139 139 140 140 internal NativeArray<int> activeCountArray; 141 - internal NativeArray<Matrix4x4> Transforms; 142 - internal NativeArray<Vector2> Directions; 143 141 internal NativeArray<Vector2> OldPositions; 144 142 internal NativeArray<int> CollisionMasks; 145 143 ··· 153 151 Speeds = new NativeArray<float>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 154 152 AngularSpeeds = new NativeArray<float>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 155 153 Colors = new NativeArray<Vector4>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 156 - Transforms = new NativeArray<Matrix4x4>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 157 154 OldPositions = new NativeArray<Vector2>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 158 - Directions = new NativeArray<Vector2>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 159 155 CollisionMasks = new NativeArray<int>(poolSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); 160 156 } 161 157 ··· 164 160 if (count <= 0) return dependency; 165 161 new NativeSlice<Vector2>(OldPositions, 0, count).CopyFrom(new NativeSlice<Vector2>(Positions, 0, count)); 166 162 var move = new MoveDanmaku(this).Schedule(count, kBatchSize, dependency); 167 - var boundsCheck = new BoundsCheckDanmaku(this).Schedule(count, kBatchSize, move); 168 - var transforms = new ComputeDanmakuTranforms(this).Schedule(count, kBatchSize, move); 169 - dependency = JobHandle.CombineDependencies(boundsCheck, transforms); 163 + dependency = new BoundsCheckDanmaku(this).Schedule(count, kBatchSize, move); 170 164 if (DanmakuCollider.ColliderCount > 0) { 171 165 var collide = new CollideDanamku(this).Schedule(count, kBatchSize, move); 172 166 dependency = JobHandle.CombineDependencies(dependency, collide); ··· 223 217 Resize(ref Speeds); 224 218 Resize(ref AngularSpeeds); 225 219 Resize(ref Colors); 226 - Resize(ref Transforms); 227 - Resize(ref Directions); 228 220 Resize(ref OldPositions); 229 221 Resize(ref CollisionMasks); 230 222 } ··· 251 243 Speeds.Dispose(); 252 244 AngularSpeeds.Dispose(); 253 245 Colors.Dispose(); 254 - Transforms.Dispose(); 255 - Directions.Dispose(); 256 246 OldPositions.Dispose(); 257 247 CollisionMasks.Dispose(); 258 248 }
-93
Assets/DanmakU/Runtime/Core/DanmakuRenderer.cs
··· 1 - using System; 2 - using System.Collections.Generic; 3 - using UnityEngine; 4 - using UnityEngine.Rendering; 5 - using Unity.Collections; 6 - using Unity.Collections.LowLevel.Unsafe; 7 - using Object = UnityEngine.Object; 8 - 9 - namespace DanmakU { 10 - 11 - internal class DanmakuRenderer : IDisposable { 12 - 13 - const int kBatchSize = 1023; 14 - 15 - static Vector4[] colorCache = new Vector4[kBatchSize]; 16 - static Matrix4x4[] transformCache = new Matrix4x4[kBatchSize]; 17 - static int ColorPropertyId = Shader.PropertyToID("_Color"); 18 - 19 - public Color Color { get; set; } = Color.white; 20 - 21 - public readonly Mesh Mesh; 22 - 23 - Material sharedMaterial; 24 - protected Material renderMaterial; 25 - public Material Material { 26 - get { return sharedMaterial; } 27 - set { 28 - if (renderMaterial != null) Object.DestroyImmediate(renderMaterial); 29 - sharedMaterial = value; 30 - if (sharedMaterial != null) { 31 - renderMaterial = Object.Instantiate(sharedMaterial); 32 - renderMaterial.enableInstancing = true; 33 - PrepareMaterial(renderMaterial); 34 - } 35 - } 36 - } 37 - 38 - readonly MaterialPropertyBlock propertyBlock; 39 - 40 - public DanmakuRenderer(Material material, Mesh mesh) { 41 - propertyBlock = new MaterialPropertyBlock(); 42 - Material = material; 43 - Mesh = mesh; 44 - } 45 - 46 - protected virtual void PrepareMaterial(Material material) {} 47 - 48 - public virtual void Dispose() { 49 - if (renderMaterial == null) return; 50 - Object.DestroyImmediate(renderMaterial); 51 - } 52 - 53 - internal unsafe void Render(List<DanmakuSet> sets, int layer) { 54 - var mesh = Mesh; 55 - int batchIndex = 0; 56 - foreach (var set in sets) { 57 - var pool = set.Pool; 58 - if (pool == null || pool.ActiveCount <= 0) return; 59 - 60 - var srcColors = (Vector4*)pool.Colors.GetUnsafeReadOnlyPtr(); 61 - var srcTransforms = (Matrix4x4*)pool.Transforms.GetUnsafeReadOnlyPtr(); 62 - 63 - int poolIndex = 0; 64 - while (poolIndex < pool.ActiveCount) { 65 - var count = Math.Min(kBatchSize - batchIndex, pool.ActiveCount - poolIndex); 66 - fixed (Vector4* colors = colorCache) { 67 - UnsafeUtility.MemCpy(colors + batchIndex, srcColors + poolIndex, sizeof(Vector4) * count); 68 - } 69 - fixed (Matrix4x4* transforms = transformCache) { 70 - UnsafeUtility.MemCpy(transforms + batchIndex, srcTransforms + poolIndex, sizeof(Matrix4x4) * count); 71 - } 72 - batchIndex += count; 73 - poolIndex += count; 74 - batchIndex %= kBatchSize; 75 - if (batchIndex == 0) RenderBatch(mesh, kBatchSize, layer); 76 - } 77 - } 78 - if (batchIndex != 0) RenderBatch(mesh, batchIndex, layer); 79 - } 80 - 81 - void RenderBatch(Mesh mesh, int batchSize, int layer) { 82 - propertyBlock.SetVectorArray(ColorPropertyId, colorCache); 83 - Graphics.DrawMeshInstanced(mesh, 0, renderMaterial, transformCache, 84 - count: batchSize, 85 - properties: propertyBlock, 86 - castShadows: ShadowCastingMode.Off, 87 - receiveShadows: false, 88 - layer: layer); 89 - } 90 - 91 - } 92 - 93 - }
Assets/DanmakU/Runtime/Core/DanmakuRenderer.cs.meta Assets/DanmakU/Runtime/Core/Rendering/DanmakuRenderer.cs.meta
-46
Assets/DanmakU/Runtime/Core/Jobs/ComputeDanmakuTransforms.cs
··· 1 - using UnityEngine; 2 - using Unity.Jobs; 3 - using Unity.Collections; 4 - using Unity.Collections.LowLevel.Unsafe; 5 - 6 - namespace DanmakU { 7 - 8 - internal struct ComputeDanmakuTranforms : IJobParallelFor { 9 - 10 - [ReadOnly] public NativeArray<Vector2> Positions; 11 - [ReadOnly] public NativeArray<Vector2> Directions; 12 - [WriteOnly] public NativeArray<Matrix4x4> Transforms; 13 - 14 - public ComputeDanmakuTranforms(DanmakuPool pool) { 15 - Positions = pool.Positions; 16 - Directions = pool.Directions; 17 - Transforms = pool.Transforms; 18 - } 19 - 20 - public unsafe void Execute(int index) { 21 - var position = Positions[index]; 22 - var direction = Directions[index]; 23 - 24 - var floatPtr = (float*)((Matrix4x4*)Transforms.GetUnsafePtr() + index); 25 - 26 - *floatPtr++ = direction.x; // 0, 0 27 - *floatPtr++ = direction.y; // 0, 1 28 - *floatPtr++ = 0f; // 0, 2 29 - *floatPtr++ = 0f; // 0, 3 30 - *floatPtr++ = -direction.y; // 1, 0 31 - *floatPtr++ = direction.x; // 1, 1 32 - *floatPtr++ = 0f; // 1, 2 33 - *floatPtr++ = 0f; // 1, 3 34 - *floatPtr++ = 0f; // 2, 0 35 - *floatPtr++ = 0f; // 2, 1 36 - *floatPtr++ = 1f; // 2, 2 37 - *floatPtr++ = 0f; // 2, 3 38 - *floatPtr++ = position.x; // 3, 0 39 - *floatPtr++ = position.y; // 3, 1 40 - *floatPtr++ = 0f; // 3, 2 41 - *floatPtr = 1f; // 3, 3 42 - } 43 - 44 - } 45 - 46 - }
+1 -1
Assets/DanmakU/Runtime/Core/Jobs/ComputeDanmakuTransforms.cs.meta Assets/DanmakU/Runtime/Core/Rendering/ComputeBufferPool.cs.meta
··· 1 1 fileFormatVersion: 2 2 - guid: 208fdc86bebf5be4489809d21096c65b 2 + guid: 09294d4c63fd5f94596f9396e2fc0bee 3 3 MonoImporter: 4 4 externalObjects: {} 5 5 serializedVersion: 2
+2 -9
Assets/DanmakU/Runtime/Core/Jobs/MoveDanmaku.cs
··· 11 11 12 12 public NativeArray<Vector2> Positions; 13 13 public NativeArray<float> Rotations; 14 - [WriteOnly] public NativeArray<Vector2> Directions; 15 14 [ReadOnly] public NativeArray<float> Speeds; 16 15 [ReadOnly] public NativeArray<float> AngularSpeeds; 17 16 ··· 19 18 DeltaTime = Time.deltaTime; 20 19 Positions = pool.Positions; 21 20 Rotations = pool.Rotations; 22 - Directions = pool.Directions; 23 21 Speeds = pool.Speeds; 24 22 AngularSpeeds = pool.AngularSpeeds; 25 23 } 26 24 27 25 public unsafe void Execute(int index) { 28 26 var positionPtr = (float*)Positions.GetUnsafePtr() + (index * 2); 29 - var directionPtr = (float*)Directions.GetUnsafePtr() + (index * 2); 30 27 var rotationPtr = (float*)Rotations.GetUnsafePtr() + index; 31 28 var speed = Speeds[index]; 32 29 var rotation = *rotationPtr + AngularSpeeds[index] * DeltaTime; 33 - var dirX = Mathf.Cos(rotation); 34 - var dirY = Mathf.Sin(rotation); 35 30 *rotationPtr = rotation; 36 - *positionPtr++ += speed * dirX * DeltaTime; 37 - *positionPtr += speed * dirY * DeltaTime; 38 - *directionPtr++ = dirX; 39 - *directionPtr = dirY; 31 + *positionPtr++ += speed * Mathf.Cos(rotation)* DeltaTime; 32 + *positionPtr += speed * Mathf.Sin(rotation) * DeltaTime; 40 33 } 41 34 42 35 }
+8
Assets/DanmakU/Runtime/Core/Rendering.meta
··· 1 + fileFormatVersion: 2 2 + guid: 793af90c78230f14a9bc461f291a8252 3 + folderAsset: yes 4 + DefaultImporter: 5 + externalObjects: {} 6 + userData: 7 + assetBundleName: 8 + assetBundleVariant:
+132
Assets/DanmakU/Runtime/Core/Rendering/ComputeBufferPool.cs
··· 1 + using System; 2 + using System.Collections.Generic; 3 + using UnityEngine; 4 + 5 + namespace DanmakU { 6 + 7 + internal sealed class ComputeBufferPool : IDisposable { 8 + 9 + public struct Context { 10 + 11 + public readonly ComputeBufferPool Pool; 12 + readonly Queue<ComputeBuffer> usedBuffers; 13 + 14 + public Context(ComputeBufferPool pool) { 15 + Pool = pool; 16 + usedBuffers = new Queue<ComputeBuffer>(); 17 + } 18 + 19 + public ComputeBuffer Rent(int count, int stride) { 20 + var buffer = Pool.Rent(count, stride); 21 + usedBuffers.Enqueue(buffer); 22 + return buffer; 23 + } 24 + 25 + public void Flush() { 26 + while (usedBuffers.Count > 0) { 27 + Pool.Return(usedBuffers.Dequeue()); 28 + } 29 + } 30 + 31 + } 32 + 33 + struct ComputeBufferParams : IEquatable<ComputeBufferParams> { 34 + public readonly int Count; 35 + public readonly int Stride; 36 + 37 + public ComputeBufferParams(ComputeBuffer buffer) { 38 + Count = buffer.count; 39 + Stride = buffer.stride; 40 + } 41 + 42 + public ComputeBufferParams(int count, int stride) { 43 + Count = count; 44 + Stride = stride; 45 + } 46 + 47 + public ComputeBuffer CreateBuffer(ComputeBufferType type) { 48 + return new ComputeBuffer(Count, Stride, type); 49 + } 50 + 51 + public bool Equals(ComputeBufferParams bufferParams) { 52 + return Count == bufferParams.Count && Stride == bufferParams.Count; 53 + } 54 + } 55 + 56 + // To avoid GC on fetch. 57 + class ParamsEquality : IEqualityComparer<ComputeBufferParams> { 58 + public bool Equals(ComputeBufferParams a, ComputeBufferParams b) { 59 + return a.Count == b.Count && a.Stride == b.Stride; 60 + } 61 + public int GetHashCode(ComputeBufferParams bufferParams) { 62 + return bufferParams.Count * 7 + bufferParams.Stride; 63 + } 64 + } 65 + 66 + static Dictionary<ComputeBufferType, ComputeBufferPool> Pools; 67 + 68 + readonly Dictionary<ComputeBufferParams, Queue<ComputeBuffer>> queues; 69 + public ComputeBufferType Type { get; } 70 + 71 + public ComputeBufferPool(ComputeBufferType type = ComputeBufferType.Default) { 72 + queues = new Dictionary<ComputeBufferParams, Queue<ComputeBuffer>>(new ParamsEquality()); 73 + Type = type; 74 + } 75 + 76 + public ComputeBuffer Rent(int count, int stride) { 77 + var bufferParams = new ComputeBufferParams(count, stride); 78 + Queue<ComputeBuffer> queue; 79 + if (!queues.TryGetValue(bufferParams, out queue)) { 80 + queue = new Queue<ComputeBuffer>(); 81 + queues.Add(bufferParams, queue); 82 + } 83 + if (queue.Count <= 0) { 84 + return bufferParams.CreateBuffer(Type); 85 + } else { 86 + return queue.Dequeue(); 87 + } 88 + } 89 + 90 + public void Return(ComputeBuffer buffer) { 91 + if (buffer == null) return; 92 + var bufferParams = new ComputeBufferParams(buffer); 93 + Queue<ComputeBuffer> queue; 94 + if (!queues.TryGetValue(bufferParams, out queue)) { 95 + queue = new Queue<ComputeBuffer>(); 96 + queues.Add(bufferParams, queue); 97 + } 98 + queue.Enqueue(buffer); 99 + } 100 + 101 + public Context CreateContext() => new Context(this); 102 + 103 + public static void DisposeShared() { 104 + if (Pools == null) return; 105 + foreach (var pool in Pools.Values) { 106 + pool.Dispose(); 107 + } 108 + Pools.Clear(); 109 + } 110 + 111 + public static ComputeBufferPool GetShared(ComputeBufferType type = ComputeBufferType.Default) { 112 + Pools = Pools ?? new Dictionary<ComputeBufferType, ComputeBufferPool>(); 113 + ComputeBufferPool pool; 114 + if (!Pools.TryGetValue(type, out pool)) { 115 + pool = new ComputeBufferPool(type); 116 + Pools.Add(type, pool); 117 + } 118 + return pool; 119 + } 120 + 121 + public void Dispose() { 122 + foreach (var queue in queues.Values) { 123 + while (queue.Count > 0) { 124 + queue.Dequeue().Dispose(); 125 + } 126 + } 127 + queues.Clear(); 128 + } 129 + 130 + } 131 + 132 + }
+134
Assets/DanmakU/Runtime/Core/Rendering/DanmakuRenderer.cs
··· 1 + using System; 2 + using System.Collections.Generic; 3 + using UnityEngine; 4 + using UnityEngine.Rendering; 5 + using Unity.Collections; 6 + using Unity.Collections.LowLevel.Unsafe; 7 + using Object = UnityEngine.Object; 8 + 9 + namespace DanmakU { 10 + 11 + 12 + internal class DanmakuRenderer : IDisposable { 13 + 14 + const int kBatchSize = 4096; 15 + 16 + static Vector4[] colorCache = new Vector4[kBatchSize]; 17 + static Vector2[] positionCache = new Vector2[kBatchSize]; 18 + static float[] rotationCache = new float[kBatchSize]; 19 + static uint[] args = new uint[] {0, 0, 0, 0, 0}; 20 + 21 + static int positionPropertyId = Shader.PropertyToID("positionBuffer"); 22 + static int rotationPropertyId = Shader.PropertyToID("rotationBuffer"); 23 + static int colorPropertyId = Shader.PropertyToID("colorBuffer"); 24 + 25 + public Color Color { get; set; } = Color.white; 26 + 27 + public readonly Mesh Mesh; 28 + 29 + Material sharedMaterial; 30 + protected Material renderMaterial; 31 + public Material Material { 32 + get { return sharedMaterial; } 33 + set { 34 + if (renderMaterial != null) Object.DestroyImmediate(renderMaterial); 35 + sharedMaterial = value; 36 + if (sharedMaterial != null) { 37 + renderMaterial = Object.Instantiate(sharedMaterial); 38 + renderMaterial.enableInstancing = true; 39 + PrepareMaterial(renderMaterial); 40 + } 41 + } 42 + } 43 + 44 + readonly MaterialPropertyBlock propertyBlock; 45 + readonly ComputeBufferPool.Context StructuredBuffers; 46 + readonly ComputeBufferPool.Context ArgBuffers; 47 + 48 + public unsafe DanmakuRenderer(Material material, Mesh mesh) { 49 + propertyBlock = new MaterialPropertyBlock(); 50 + StructuredBuffers = ComputeBufferPool.GetShared().CreateContext(); 51 + ArgBuffers = ComputeBufferPool.GetShared(ComputeBufferType.IndirectArguments).CreateContext(); 52 + Material = material; 53 + Mesh = mesh; 54 + } 55 + 56 + protected virtual void PrepareMaterial(Material material) {} 57 + 58 + public virtual void Dispose() { 59 + if (renderMaterial != null) { 60 + Object.DestroyImmediate(renderMaterial); 61 + } 62 + FlushBuffers(); 63 + } 64 + 65 + public void FlushBuffers() { 66 + StructuredBuffers.Flush(); 67 + ArgBuffers.Flush(); 68 + } 69 + 70 + public unsafe void Render(List<DanmakuSet> sets, int layer) { 71 + var mesh = Mesh; 72 + int batchIndex = 0; 73 + 74 + foreach (var set in sets) { 75 + var pool = set.Pool; 76 + if (pool == null || pool.ActiveCount <= 0) return; 77 + 78 + var srcPositions = (Vector2*)pool.Positions.GetUnsafeReadOnlyPtr(); 79 + var srcRotations = (float*)pool.Rotations.GetUnsafeReadOnlyPtr(); 80 + var srcColors = (Color*)pool.Colors.GetUnsafeReadOnlyPtr(); 81 + 82 + int poolIndex = 0; 83 + while (poolIndex < pool.ActiveCount) { 84 + var count = Math.Min(kBatchSize - batchIndex, pool.ActiveCount - poolIndex); 85 + fixed (Vector2* colors = positionCache) { 86 + UnsafeUtility.MemCpy(colors + batchIndex, srcPositions+ poolIndex, sizeof(Vector2) * count); 87 + } 88 + fixed (float* rotations = rotationCache) { 89 + UnsafeUtility.MemCpy(rotations + batchIndex, srcRotations + poolIndex, sizeof(float) * count); 90 + } 91 + fixed (Vector4* colors = colorCache) { 92 + UnsafeUtility.MemCpy(colors + batchIndex, srcColors + poolIndex, sizeof(Vector4) * count); 93 + } 94 + batchIndex += count; 95 + poolIndex += count; 96 + batchIndex %= kBatchSize; 97 + if (batchIndex == 0) RenderBatch(mesh, kBatchSize, layer); 98 + } 99 + } 100 + if (batchIndex != 0) RenderBatch(mesh, batchIndex, layer); 101 + } 102 + 103 + unsafe void RenderBatch(Mesh mesh, int batchSize, int layer) { 104 + ComputeBuffer argsBuffer = ArgBuffers.Rent(1, args.Length * sizeof(uint)); 105 + ComputeBuffer positionBuffer = StructuredBuffers.Rent(kBatchSize, sizeof(Vector2)); 106 + ComputeBuffer colorBuffer = StructuredBuffers.Rent(kBatchSize, sizeof(Color)); 107 + ComputeBuffer rotationBuffer = StructuredBuffers.Rent(kBatchSize, sizeof(float)); 108 + 109 + colorBuffer.SetData(colorCache, 0, 0, batchSize); 110 + positionBuffer.SetData(positionCache, 0, 0, batchSize); 111 + rotationBuffer.SetData(rotationCache, 0, 0, batchSize); 112 + 113 + propertyBlock.SetBuffer(positionPropertyId, positionBuffer); 114 + propertyBlock.SetBuffer(rotationPropertyId, rotationBuffer); 115 + propertyBlock.SetBuffer(colorPropertyId, colorBuffer); 116 + 117 + args[0] = mesh.GetIndexCount(0); 118 + args[1] = (uint)batchSize; 119 + argsBuffer.SetData(args); 120 + 121 + Graphics.DrawMeshInstancedIndirect(mesh, 0, renderMaterial, 122 + bounds: new Bounds(Vector3.zero, Vector3.one * 1000f), 123 + bufferWithArgs: argsBuffer, 124 + argsOffset: 0, 125 + properties: propertyBlock, 126 + castShadows: ShadowCastingMode.Off, 127 + receiveShadows: false, 128 + layer: layer, 129 + camera: null); 130 + } 131 + 132 + } 133 + 134 + }
Assets/DanmakU/Runtime/Core/SpriteDanmakuRenderer.cs Assets/DanmakU/Runtime/Core/Rendering/SpriteDanmakuRenderer.cs
Assets/DanmakU/Runtime/Core/SpriteDanmakuRenderer.cs.meta Assets/DanmakU/Runtime/Core/Rendering/SpriteDanmakuRenderer.cs.meta
+13 -2
Assets/DanmakU/Runtime/Modifiers/DanmakuAcceleration.cs
··· 1 1 using Unity.Jobs; 2 2 using Unity.Collections; 3 + using Unity.Collections.LowLevel.Unsafe; 3 4 using UnityEngine; 4 5 5 6 namespace DanmakU.Modifiers { ··· 21 22 if (acceleration.Approximately(0f)) return dependency; 22 23 if (Mathf.Approximately(acceleration.Size, 0f)) { 23 24 return new ApplyFixedAcceleration { 25 + Count = pool.ActiveCount, 24 26 Acceleration = acceleration.Center, 25 27 Speeds = pool.Speeds 26 - }.Schedule(pool.ActiveCount, DanmakuPool.kBatchSize, dependency); 28 + }.Schedule(); 27 29 } else { 28 30 return new ApplyRandomAcceleration { 29 31 Acceleration = acceleration.Center, ··· 32 34 } 33 35 } 34 36 35 - struct ApplyFixedAcceleration : IJobParallelFor { 37 + struct ApplyFixedAcceleration : IJob, IJobParallelFor { 36 38 39 + public int Count; 37 40 public float Acceleration; 38 41 public NativeArray<float> Speeds; 39 42 43 + public unsafe void Execute() { 44 + var ptr = (float*)(Speeds.GetUnsafePtr()); 45 + var end = ptr + Count; 46 + while (ptr < end) { 47 + *ptr++ += Acceleration; 48 + } 49 + } 50 + 40 51 public void Execute(int index) { 41 52 Speeds[index] += Acceleration; 42 53 }
+34 -13
Assets/DanmakU/Runtime/Shaders/Danmaku_Ranged_Sprite_Shader.shader
··· 2 2 Shader "Sprites/Danmaku Ranged" { 3 3 Properties { 4 4 _MainTex ("Sprite Texture", 2D) = "white" {} 5 - _Color ("Tint", Color) = (1,1,1,1) 6 5 _ColorDark ("Tint Dark", Color) = (0,0,0,0) 7 6 _ColorBright ("Tint Bright", Color) = (1,1,1,1) 8 7 [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0 ··· 33 32 #pragma multi_compile_instancing 34 33 #pragma multi_compile _ PIXELSNAP_ON 35 34 #pragma multi_compile _ ETC1_EXTERNAL_ALPHA 35 + #pragma instancing_options procedural:setup 36 36 37 37 #include "UnityCG.cginc" 38 - 39 - UNITY_INSTANCING_BUFFER_START(Props) 40 - UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) 41 - UNITY_DEFINE_INSTANCED_PROP(fixed2, _Flip) 42 - UNITY_INSTANCING_BUFFER_END(Props) 43 38 44 39 CBUFFER_START(UnityPerDrawSprite) 45 40 float _EnableExternalAlpha; 46 41 CBUFFER_END 47 42 43 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 44 + StructuredBuffer<float2> positionBuffer; 45 + StructuredBuffer<float> rotationBuffer; 46 + StructuredBuffer<float4> colorBuffer; 47 + #endif 48 + 48 49 float4 _ColorDark; 49 50 float4 _ColorBright; 50 51 ··· 64 65 UNITY_VERTEX_OUTPUT_STEREO 65 66 }; 66 67 68 + void setup() { 69 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 70 + float2 position = positionBuffer[unity_InstanceID]; 71 + float rotation = rotationBuffer[unity_InstanceID]; 72 + float cosR = cos(rotation); 73 + float sinR = sin(rotation); 74 + 75 + unity_ObjectToWorld = float4x4( 76 + cosR, -sinR, 0, position.x, 77 + sinR, cosR, 0, position.y, 78 + 0, 0, 1, 0, 79 + 0, 0, 0, 1 80 + ); 81 + 82 + unity_WorldToObject = unity_ObjectToWorld; 83 + unity_WorldToObject._14_24_34 *= -1; 84 + unity_WorldToObject._11_22_33 = 1.0f / unity_WorldToObject._11_22_33; 85 + #endif 86 + } 87 + 67 88 v2f SpriteVert(appdata_t IN) 68 89 { 69 90 v2f OUT; ··· 71 92 UNITY_SETUP_INSTANCE_ID (IN); 72 93 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 73 94 74 - #ifdef UNITY_INSTANCING_ENABLED 75 - IN.vertex.xy *= UNITY_ACCESS_INSTANCED_PROP(Props, _Flip); 76 - #endif 77 - 78 95 OUT.vertex = UnityObjectToClipPos(IN.vertex); 79 96 OUT.texcoord = IN.texcoord; 80 - OUT.color = IN.color * UNITY_ACCESS_INSTANCED_PROP(Props, _Color); 97 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 98 + OUT.color = IN.color * colorBuffer[unity_InstanceID]; 99 + #else 100 + OUT.color = IN.color; 101 + #endif 81 102 82 - #ifdef PIXELSNAP_ON 103 + #ifdef PIXELSNAP_ON 83 104 OUT.vertex = UnityPixelSnap (OUT.vertex); 84 - #endif 105 + #endif 85 106 86 107 return OUT; 87 108 }
+32 -10
Assets/DanmakU/Runtime/Shaders/Danmaku_Sprite_Shader.shader
··· 31 31 #pragma multi_compile_instancing 32 32 #pragma multi_compile _ PIXELSNAP_ON 33 33 #pragma multi_compile _ ETC1_EXTERNAL_ALPHA 34 + #pragma instancing_options procedural:setup 34 35 35 36 #include "UnityCG.cginc" 36 - 37 - UNITY_INSTANCING_BUFFER_START(Props) 38 - UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) 39 - UNITY_DEFINE_INSTANCED_PROP(fixed2, _Flip) 40 - UNITY_INSTANCING_BUFFER_END(Props) 41 37 42 38 CBUFFER_START(UnityPerDrawSprite) 43 39 float _EnableExternalAlpha; 44 40 CBUFFER_END 45 41 42 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 43 + StructuredBuffer<float2> positionBuffer; 44 + StructuredBuffer<float> rotationBuffer; 45 + StructuredBuffer<float4> colorBuffer; 46 + #endif 47 + 46 48 struct appdata_t 47 49 { 48 50 float4 vertex : POSITION; ··· 59 61 UNITY_VERTEX_OUTPUT_STEREO 60 62 }; 61 63 64 + void setup() { 65 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 66 + float2 position = positionBuffer[unity_InstanceID]; 67 + float rotation = rotationBuffer[unity_InstanceID]; 68 + float cosR = cos(rotation); 69 + float sinR = sin(rotation); 70 + 71 + unity_ObjectToWorld = float4x4( 72 + cosR, -sinR, 0, position.x, 73 + sinR, cosR, 0, position.y, 74 + 0, 0, 1, 0, 75 + 0, 0, 0, 1 76 + ); 77 + 78 + unity_WorldToObject = unity_ObjectToWorld; 79 + unity_WorldToObject._14_24_34 *= -1; 80 + unity_WorldToObject._11_22_33 = 1.0f / unity_WorldToObject._11_22_33; 81 + #endif 82 + } 83 + 62 84 v2f SpriteVert(appdata_t IN) 63 85 { 64 86 v2f OUT; ··· 66 88 UNITY_SETUP_INSTANCE_ID (IN); 67 89 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT); 68 90 69 - #ifdef UNITY_INSTANCING_ENABLED 70 - IN.vertex.xy *= UNITY_ACCESS_INSTANCED_PROP(Props, _Flip); 71 - #endif 72 - 73 91 OUT.vertex = UnityObjectToClipPos(IN.vertex); 74 92 OUT.texcoord = IN.texcoord; 75 - OUT.color = IN.color * UNITY_ACCESS_INSTANCED_PROP(Props, _Color); 93 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 94 + OUT.color = IN.color * colorBuffer[unity_InstanceID]; 95 + #else 96 + OUT.color = IN.color; 97 + #endif 76 98 77 99 #ifdef PIXELSNAP_ON 78 100 OUT.vertex = UnityPixelSnap (OUT.vertex);
+32 -6
Assets/DanmakU/Runtime/Shaders/Danmaku_Standard_Shader.shader
··· 13 13 // Physically based Standard lighting model, and enable shadows on all light types 14 14 #pragma surface surf Standard fullforwardshadows 15 15 #pragma instancing_options assumeuniformscaling 16 + #pragma instancing_options procedural:setup 16 17 17 18 // Use shader model 3.0 target, to get nicer looking lighting 18 19 #pragma target 3.0 ··· 23 24 float2 uv_MainTex; 24 25 }; 25 26 27 + half4 _Color; 26 28 half _Glossiness; 27 29 half _Metallic; 28 30 29 - // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. 30 - // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. 31 - UNITY_INSTANCING_BUFFER_START(Props) 32 - UNITY_DEFINE_INSTANCED_PROP(fixed4, _Color) 33 - UNITY_INSTANCING_BUFFER_END(Props) 31 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 32 + StructuredBuffer<float2> positionBuffer; 33 + StructuredBuffer<float> rotationBuffer; 34 + StructuredBuffer<float4> colorBuffer; 35 + #endif 36 + 37 + void setup() { 38 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 39 + float2 position = positionBuffer[unity_InstanceID]; 40 + float rotation = rotationBuffer[unity_InstanceID]; 41 + float cosR = cos(rotation); 42 + float sinR = sin(rotation); 43 + 44 + unity_ObjectToWorld = float4x4( 45 + cosR, -sinR, 0, position.x, 46 + sinR, cosR, 0, position.y, 47 + 0, 0, 1, 0, 48 + 0, 0, 0, 1 49 + ); 50 + 51 + unity_WorldToObject = unity_ObjectToWorld; 52 + unity_WorldToObject._14_24_34 *= -1; 53 + unity_WorldToObject._11_22_33 = 1.0f / unity_WorldToObject._11_22_33; 54 + #endif 55 + } 34 56 35 57 void surf (Input IN, inout SurfaceOutputStandard o) { 36 58 // Albedo comes from a texture tinted by color 37 - fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * UNITY_ACCESS_INSTANCED_PROP(Props, _Color); 59 + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED 60 + fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * colorBuffer[unity_InstanceID]; 61 + #else 62 + fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; 63 + #endif 38 64 o.Albedo = c.rgb; 39 65 // Metallic and smoothness come from slider variables 40 66 o.Metallic = _Metallic;
+3 -3
Assets/Test Scene.unity
··· 294 294 FrameRate: 0 295 295 Arc: 296 296 Count: 297 - _min: 20 298 - _max: 20 297 + _min: 500 298 + _max: 500 299 299 ArcLength: 300 300 _min: 6.2831855 301 301 _max: 6.2831855 ··· 491 491 Sprite: {fileID: 21300000, guid: 4cddd60e11667c848a99d851ee8b4e89, type: 3} 492 492 ColliderRadius: 2 493 493 ColliderOffset: {x: 0, y: 0} 494 - DefaultPoolSize: 1000 494 + DefaultPoolSize: 128000 495 495 --- !u!4 &2040105327 496 496 Transform: 497 497 m_ObjectHideFlags: 0
+4 -2
ProjectSettings/ProjectSettings.asset
··· 537 537 webGLLinkerTarget: 0 538 538 scriptingDefineSymbols: {} 539 539 platformArchitecture: {} 540 - scriptingBackend: {} 540 + scriptingBackend: 541 + Standalone: 0 541 542 il2cppCompilerConfiguration: {} 542 543 incrementalIl2cppBuild: {} 543 544 allowUnsafeCode: 0 544 545 additionalIl2CppArgs: 545 546 scriptingRuntimeVersion: 1 546 - apiCompatibilityLevelPerPlatform: {} 547 + apiCompatibilityLevelPerPlatform: 548 + Standalone: 3 547 549 m_RenderingPath: 1 548 550 m_MobileRenderingPath: 1 549 551 metroPackageName: DanmakU
+1 -1
README.md
··· 16 16 ### Requirements and Caveats 17 17 18 18 * Unity 2018.1 or newer. 19 - * Support for [GPU Instancing](https://docs.unity3d.com/Manual/GPUInstancing.html). All shaders used to render bullets must have GPU Instancing enabled. 19 + * Support for [Procedural GPU Instancing](https://docs.unity3d.com/Manual/GPUInstancing.html). All shaders used to render bullets must have GPU Instancing enabled. Requires Shader Model 4.5 or newer.