Created
February 22, 2020 21:40
-
-
Save HurricanKai/26169d4ebcbf2584766b4ae30efd4399 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Threading; | |
using Unity.Burst; | |
using Unity.Collections; | |
using Unity.Collections.Experimental; | |
using Unity.Entities; | |
using Unity.Jobs; | |
using Unity.Jobs.LowLevel.Unsafe; | |
using Unity.Mathematics; | |
using Unity.Transforms; | |
using UnityEngine; | |
using UnityEngine.PlayerLoop; | |
using UnityEngine.Profiling; | |
using UnityEngine.Rendering; | |
using UnityEngine.UI; | |
using static Unity.Mathematics.math; | |
[UpdateInGroup(typeof(PresentationSystemGroup))] | |
public class VoxelRenderSystem : JobComponentSystem | |
{ | |
private EntityQuery _query; | |
private int _colorProp; | |
private Mesh _voxMesh; | |
private Material _voxMat; | |
const int batchSize = 1023; | |
// private NativeArray<Matrix4x4> _matrixCache; | |
private NativeArray<Vector4> _colorCache; | |
private NativeQueue<BatchPart> _batchQueue; | |
private int _positionBufferProp; | |
private int _scaleBufferProp; | |
private ComputeBufferPool _colorBufferPool; | |
private ComputeBufferPool _positionBufferPool; | |
private ComputeBufferPool _scaleBufferPool; | |
private NativeArray<float3> _defaultScales; | |
private MaterialPropertyBlock _matPropBlock; | |
public SemaphoreSlim CMDSemaphore { get; private set; } | |
public CommandBuffer CommandBuffer { get; private set; } | |
public ComputeBuffer LastColorBuffer; | |
public ComputeBuffer LastPositionBuffer; | |
public ComputeBuffer LastScaleBuffer; | |
public int LastSize; | |
protected override void OnCreate() | |
{ | |
base.OnCreate(); | |
_query = GetEntityQuery(new EntityQueryDesc | |
{ | |
All = new[] { ComponentType.ReadOnly<VoxelColor>() }, | |
Any = new []{ ComponentType.ReadOnly<Translation>(), ComponentType.ReadOnly<Scale>(), } | |
}); | |
CMDSemaphore = new SemaphoreSlim(1, 1); | |
CommandBuffer = new CommandBuffer(); | |
CommandBuffer.name = "Voxel Rendering System @" + World.Name; | |
_colorProp = Shader.PropertyToID("colorBuffer"); | |
_positionBufferProp = Shader.PropertyToID("positionBuffer"); | |
_scaleBufferProp = Shader.PropertyToID("scaleBuffer"); | |
_voxMesh = CreateMesh(); | |
_voxMat = GraphicsSettings.renderPipelineAsset?.defaultMaterial; | |
_matPropBlock = new MaterialPropertyBlock(); | |
// _matrixCache = new NativeArray<Matrix4x4>(batchSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); | |
_colorCache = new NativeArray<Vector4>(batchSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); | |
_batchQueue = new NativeQueue<BatchPart>(Allocator.Persistent); | |
_positionBufferPool = new ComputeBufferPool(batchSize, sizeof(float) * 3, ComputeBufferType.IndirectArguments, "Position Buffer"); | |
_scaleBufferPool = new ComputeBufferPool(batchSize, sizeof(float) * 3, ComputeBufferType.IndirectArguments, "Scale Buffer"); | |
_colorBufferPool = new ComputeBufferPool(batchSize, sizeof(float) * 4, ComputeBufferType.IndirectArguments, "Color Buffer"); | |
_defaultScales = new NativeArray<float3>(batchSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); | |
for (int i = 0; i < batchSize; i++) | |
_defaultScales[i] = float3(1, 1, 1); | |
/*new MemsetNativeArray<float3> | |
{ | |
Source = _defaultScales, | |
Value = float3(1, 1, 1) | |
}.Schedule(batchSize, 128);*/ | |
} | |
protected override void OnDestroy() | |
{ | |
base.OnDestroy(); | |
CommandBuffer.Dispose(); | |
CMDSemaphore.Dispose(); | |
// _matrixCache.Dispose(); | |
_colorCache.Dispose(); | |
_batchQueue.Dispose(); | |
_positionBufferPool.Dispose(); | |
_scaleBufferPool.Dispose(); | |
_colorBufferPool.Dispose(); | |
_defaultScales.Dispose(); | |
} | |
private Mesh CreateMesh() | |
{ | |
Vector3[] vertices = | |
{ | |
new Vector3(0, 0, 0), | |
new Vector3(1, 0, 0), | |
new Vector3(1, 1, 0), | |
new Vector3(0, 1, 0), | |
new Vector3(0, 1, 1), | |
new Vector3(1, 1, 1), | |
new Vector3(1, 0, 1), | |
new Vector3(0, 0, 1), | |
}; | |
int[] triangles = | |
{ | |
0, 2, 1, //face front | |
0, 3, 2, | |
2, 3, 4, //face top | |
2, 4, 5, | |
1, 2, 5, //face right | |
1, 5, 6, | |
0, 7, 4, //face left | |
0, 4, 3, | |
5, 4, 7, //face back | |
5, 7, 6, | |
0, 6, 7, //face bottom | |
0, 1, 6 | |
}; | |
Mesh mesh = new Mesh(); | |
mesh.Clear(); | |
mesh.vertices = vertices; | |
mesh.triangles = triangles; | |
mesh.Optimize(); | |
return mesh; | |
} | |
private struct BatchPart | |
{ | |
public ArchetypeChunk Chunk; | |
public int Start; | |
public int Length; | |
} | |
private struct BatchingJob : IJob | |
{ | |
public NativeQueue<BatchPart> Batches; | |
[ReadOnly] public NativeArray<ArchetypeChunk> Chunks; | |
public void Execute() | |
{ | |
int i = 0; | |
foreach (var chunk in Chunks) | |
{ | |
for (int k = 0; k < chunk.Count;) | |
{ | |
var entriesLeft = batchSize - i; | |
var count = min(entriesLeft, chunk.Count - k); | |
var start = k; | |
k += count; | |
i += count; | |
Batches.Enqueue(new BatchPart | |
{ | |
Chunk = chunk, | |
Start = start, | |
Length = count, | |
}); | |
if (i == batchSize) i = 0; | |
} | |
} | |
} | |
} | |
protected override JobHandle OnUpdate(JobHandle inputDependencies) | |
{ | |
if (_voxMat == null) | |
{ | |
_voxMat = GraphicsSettings.renderPipelineAsset?.defaultMaterial; | |
return inputDependencies; | |
} | |
if (_voxMesh == null) | |
{ | |
_voxMesh = CreateMesh(); | |
return inputDependencies; | |
} | |
var voxelColorType = GetArchetypeChunkComponentType<VoxelColor>(true); | |
var positionType = GetArchetypeChunkComponentType<Translation>(true); | |
var scaleType = GetArchetypeChunkComponentType<Scale>(true); | |
Profiler.BeginSample("Dependencies"); | |
inputDependencies.Complete(); | |
CMDSemaphore.Wait(); | |
CommandBuffer.Clear(); | |
Profiler.EndSample(); | |
_positionBufferPool.Swap(); | |
_scaleBufferPool.Swap(); | |
_colorBufferPool.Swap(); | |
Profiler.BeginSample("Batch Processing"); | |
int i = 0; | |
var positionBuffer = _positionBufferPool.Rent(); | |
var scaleBuffer = _scaleBufferPool.Rent(); | |
var colorBuffer = _colorBufferPool.Rent(); | |
while (_batchQueue.TryDequeue(out var batch)) | |
{ | |
Profiler.BeginSample("Batch"); | |
var chunk = batch.Chunk; | |
Profiler.BeginSample("Copy"); | |
{ | |
colorBuffer.SetData(chunk.GetNativeArray(voxelColorType), batch.Start, i, batch.Length); | |
if (chunk.Has(positionType)) | |
positionBuffer.SetData(chunk.GetNativeArray(positionType), batch.Start, i, batch.Length); | |
if (chunk.Has(scaleType)) | |
scaleBuffer.SetData(chunk.GetNativeArray(scaleType), batch.Start, i, batch.Length); | |
else | |
{ | |
scaleBuffer.SetData(_defaultScales, 0, i, batch.Length); | |
} | |
} | |
Profiler.EndSample(); | |
i += batch.Length; | |
if (i == batchSize) | |
{ | |
Profiler.BeginSample("Submitting"); | |
_matPropBlock.Clear(); | |
_matPropBlock.SetBuffer(_colorProp, colorBuffer); | |
_matPropBlock.SetBuffer(_positionBufferProp, positionBuffer); | |
_matPropBlock.SetBuffer(_scaleBufferProp, scaleBuffer); | |
CommandBuffer.DrawMeshInstancedProcedural(_voxMesh, 0, _voxMat, -1, batchSize, _matPropBlock); | |
LastSize = i; | |
LastColorBuffer = colorBuffer; | |
LastPositionBuffer = positionBuffer; | |
LastScaleBuffer = scaleBuffer; | |
i = 0; | |
positionBuffer = _positionBufferPool.Rent(); | |
scaleBuffer = _scaleBufferPool.Rent(); | |
colorBuffer = _colorBufferPool.Rent(); | |
Profiler.EndSample(); | |
} | |
Profiler.EndSample(); | |
} | |
Profiler.BeginSample("Rest"); | |
if (i > 0) | |
{ | |
NativeArray<int> a; | |
_matPropBlock.Clear(); | |
_matPropBlock.SetBuffer(_colorProp, colorBuffer); | |
_matPropBlock.SetBuffer(_positionBufferProp, positionBuffer); | |
_matPropBlock.SetBuffer(_scaleBufferProp, scaleBuffer); | |
CommandBuffer.DrawMeshInstancedProcedural(_voxMesh, 0, _voxMat, -1, i, _matPropBlock); | |
LastSize = i; | |
LastColorBuffer = colorBuffer; | |
LastPositionBuffer = positionBuffer; | |
LastScaleBuffer = scaleBuffer; | |
} | |
Profiler.EndSample(); | |
Profiler.EndSample(); | |
CMDSemaphore.Release(); | |
var chunks = _query.CreateArchetypeChunkArrayAsync(Allocator.TempJob, out var acjh); | |
var handle = new BatchingJob | |
{ | |
Batches = _batchQueue, | |
Chunks = chunks | |
}.Schedule(acjh); | |
chunks.Dispose(handle); | |
return handle; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Shader "Custom/VoxelShader" { | |
Properties | |
{ } | |
SubShader | |
{ | |
Tags { "RenderType"="Opaque" } | |
LOD 100 | |
Pass | |
{ | |
CGPROGRAM | |
#pragma vertex vert | |
#pragma fragment frag | |
#pragma multi_compile_instancing | |
#pragma instancing_options procedural:setup | |
#include "UnityCG.cginc" | |
#include "Matrix.hlsl" | |
#pragma enable_d3d11_debug_symbols | |
#pragma target 4.5 | |
struct appdata | |
{ | |
float4 vertex : POSITION; | |
UNITY_VERTEX_INPUT_INSTANCE_ID | |
}; | |
struct v2f | |
{ | |
float4 vertex : SV_POSITION; | |
UNITY_VERTEX_INPUT_INSTANCE_ID | |
}; | |
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED | |
StructuredBuffer<float3> positionBuffer; | |
StructuredBuffer<float3> scaleBuffer; | |
StructuredBuffer<float4> colorBuffer; | |
#endif | |
void setup() | |
{ | |
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED | |
float3 pos = positionBuffer[unity_InstanceID]; | |
float3 scale = scaleBuffer[unity_InstanceID]; | |
unity_ObjectToWorld = compose(pos, float4(0, 0, 0, 1), scale); | |
#endif | |
} | |
v2f vert(appdata v) | |
{ | |
v2f o; | |
UNITY_SETUP_INSTANCE_ID(v); | |
UNITY_TRANSFER_INSTANCE_ID(v, o); | |
o.vertex = mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, v.vertex)); | |
return o; | |
} | |
float4 frag(v2f i) : SV_Target | |
{ | |
UNITY_SETUP_INSTANCE_ID(i); | |
#ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED | |
return colorBuffer[unity_InstanceID]; | |
#endif | |
return float4(1.0, 1.0, 1.0, 1.0); | |
} | |
ENDCG | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using Unity.Collections; | |
using Unity.Entities; | |
using Unity.Mathematics; | |
using static Unity.Mathematics.math; | |
using UnityEngine; | |
using UnityEngine.Rendering; | |
public class VoxSRP : RenderPipeline | |
{ | |
private readonly CommandBuffer _staticCB; | |
private ComputeBuffer _posBuff; | |
private ComputeBuffer _scaleBuff; | |
private ComputeBuffer _colorBuff; | |
private Mesh _mesh; | |
private Material _mat; | |
private Mesh CreateMesh() | |
{ | |
Vector3[] vertices = | |
{ | |
new Vector3(0, 0, 0), | |
new Vector3(1, 0, 0), | |
new Vector3(1, 1, 0), | |
new Vector3(0, 1, 0), | |
new Vector3(0, 1, 1), | |
new Vector3(1, 1, 1), | |
new Vector3(1, 0, 1), | |
new Vector3(0, 0, 1), | |
}; | |
int[] triangles = | |
{ | |
0, 2, 1, //face front | |
0, 3, 2, | |
2, 3, 4, //face top | |
2, 4, 5, | |
1, 2, 5, //face right | |
1, 5, 6, | |
0, 7, 4, //face left | |
0, 4, 3, | |
5, 4, 7, //face back | |
5, 7, 6, | |
0, 6, 7, //face bottom | |
0, 1, 6 | |
}; | |
Mesh mesh = new Mesh(); | |
mesh.Clear(); | |
mesh.vertices = vertices; | |
mesh.triangles = triangles; | |
mesh.Optimize(); | |
return mesh; | |
} | |
public VoxSRP() | |
{ | |
_mesh = CreateMesh(); | |
_mat = GraphicsSettings.renderPipelineAsset?.defaultMaterial; | |
_staticCB = new CommandBuffer(); | |
_posBuff = new ComputeBuffer(9, sizeof(float) * 3); | |
_scaleBuff = new ComputeBuffer(9, sizeof(float) * 3); | |
_colorBuff = new ComputeBuffer(9, sizeof(float) * 4); | |
WriteStaticCommands(); | |
} | |
protected override void Dispose(bool disposing) | |
{ | |
base.Dispose(disposing); | |
_staticCB?.Dispose(); | |
_posBuff.Dispose(); | |
_scaleBuff.Dispose(); | |
_colorBuff.Dispose(); | |
} | |
private void WriteStaticCommands() | |
{ | |
_staticCB.Clear(); | |
_staticCB.ClearRenderTarget(true, true, Color.grey, 1.0f); | |
/* | |
_scaleBuff.SetData(new[] | |
{ | |
float3(1, 1, 1), float3(1, 1, 1), float3(1, 1, 1), float3(1, 1, 1), float3(1, 1, 1), | |
float3(1, 1, 1), float3(1, 1, 1), float3(1, 1, 1) | |
}); | |
_colorBuff.SetData(new []{ Color.red, Color.blue, Color.green, Color.yellow, Color.magenta, Color.white, Color.blue, Color.green }); | |
_posBuff.SetData(new[] | |
{ | |
float3(0, 0, 0), float3(0, 0, 1), float3(0, 1, 0), float3(0, 1, 1), float3(1, 0, 0), | |
float3(1, 0, 1), float3(1, 1, 0), float3(1, 1, 1) | |
}); | |
var matProp = new MaterialPropertyBlock(); | |
matProp.SetBuffer("positionBuffer", _posBuff); | |
matProp.SetBuffer("scaleBuffer", _scaleBuff); | |
matProp.SetBuffer("colorBuffer", _colorBuff); | |
_staticCB.DrawMeshInstancedProcedural(_mesh, 0, _mat, -1, 8, matProp);*/ | |
} | |
private VoxelRenderSystem _last; | |
protected override void Render(ScriptableRenderContext context, Camera[] cameras) | |
{ | |
context.InvokeOnRenderObjectCallback(); | |
foreach (var camera in cameras) | |
{ | |
context.SetupCameraProperties(camera); | |
Render(context, camera); | |
context.DrawGizmos(camera, GizmoSubset.PreImageEffects); | |
context.DrawGizmos(camera, GizmoSubset.PostImageEffects); | |
} | |
context.Submit(); | |
if (_last != null) | |
{ | |
var vrs = _last; | |
var i = vrs.LastSize; | |
var positions = new float3[i]; | |
var scales = new float3[i]; | |
var colors = new float4[i]; | |
vrs.LastColorBuffer.GetData(colors, 0, 0, i); | |
vrs.LastPositionBuffer.GetData(positions, 0, 0, i); | |
vrs.LastScaleBuffer.GetData(scales, 0, 0, i); | |
Debug.Log($"positions: [" + String.Join("", | |
positions.ToList() | |
.ConvertAll(x => x.ToString()) | |
.ToArray()) + "]"); | |
Debug.Log($"scales: [" + String.Join("", | |
scales.ToList() | |
.ConvertAll(x => x.ToString()) | |
.ToArray()) + "]"); | |
Debug.Log($"colors: [" + String.Join("", | |
colors.ToList() | |
.ConvertAll(x => x.ToString()) | |
.ToArray()) + "]"); | |
} | |
} | |
private void Render(ScriptableRenderContext ctx, Camera camera) | |
{ | |
ctx.ExecuteCommandBuffer(_staticCB); | |
foreach (var world in World.AllWorlds) | |
{ | |
var vrs = world.GetExistingSystem<VoxelRenderSystem>(); | |
if (vrs != null) | |
{ | |
if (!vrs.CMDSemaphore.Wait(10)) | |
{ | |
Debug.LogWarning($"{vrs} was busy!"); | |
continue; | |
} | |
ctx.ExecuteCommandBuffer(vrs.CommandBuffer); | |
if (true) | |
{ | |
_last = vrs; | |
/*var i = vrs.LastSize; | |
var positions = new float3[i]; | |
var scales = new float3[i]; | |
var colors = new float4[i]; | |
vrs.LastColorBuffer.GetData(colors, 0, 0, i); | |
vrs.LastPositionBuffer.GetData(positions, 0, 0, i); | |
vrs.LastScaleBuffer.GetData(scales, 0, 0, i); | |
Debug.Log($"positions: [" + String.Join("", | |
positions.ToList() | |
.ConvertAll(x => x.ToString()) | |
.ToArray()) + "]"); | |
Debug.Log($"scales: [" + String.Join("", | |
scales.ToList() | |
.ConvertAll(x => x.ToString()) | |
.ToArray()) + "]"); | |
Debug.Log($"colors: [" + String.Join("", | |
colors.ToList() | |
.ConvertAll(x => x.ToString()) | |
.ToArray()) + "]");-*/ | |
} | |
vrs.CMDSemaphore.Release(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment