Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Flickering when rendering

Discussion in 'Graphics for ECS' started by Guedez, Jun 18, 2020.

  1. Guedez

    Guedez

    Joined:
    Jun 1, 2012
    Posts:
    823
    TLDR: https://i.imgur.com/6ReCPBa.mp4
    I draw the grass tiles in 3 levels, full shadows, only receive shadows, no shadows
    What I assume it's happening is: the first frame a tile stops being rendered in one of the levels and it flips to the next something gets lost somewhere and it only renders next frame. I was at first thinking that maybe it was a precision issue where it would not be rendered in any of the levels, but they are a sequence of if else
    The whole part where you can clearly see where it reduces the total amount of blades of grass being rendered very noticeably will be soon fixed on the shader
    Code (CSharp):
    1. using GuedezGrassSystem;
    2. using System;
    3. using System.Collections.Generic;
    4. using System.Linq;
    5. using Unity.Burst;
    6. using Unity.Collections;
    7. using Unity.Collections.LowLevel.Unsafe;
    8. using Unity.Entities;
    9. using Unity.Jobs;
    10. using Unity.Mathematics;
    11. using Unity.Transforms;
    12. using UnityEngine;
    13.  
    14.  
    15. public class DrawContainer {
    16.     //   public ComputeBuffer _centers;
    17.     public ComputeBuffer _positions;
    18.     // public ComputeBuffer _centers2;
    19.     //public ComputeBuffer _positions2;
    20.     public int total;
    21.     public ComputeBuffer _argsBuffer;
    22.     public uint[] args = new uint[5];
    23.  
    24.     //   public NativeArray<float3> _centersWrite;
    25.     public NativeArray<uint> _positionsWrite;
    26.  
    27.     public MaterialPropertyBlock block;
    28.     private bool castshadow;
    29.     private bool receiveshadow;
    30.  
    31.     public NativeList<Entry> accumulator;
    32.  
    33.     public NativeList<int> sizeargs;
    34.     public DrawContainer(bool castshadow, bool receiveshadow) {
    35.         block = new MaterialPropertyBlock();
    36.         this.castshadow = castshadow;
    37.         this.receiveshadow = receiveshadow;
    38.         sizeargs = new NativeList<int>(128, Allocator.Persistent);
    39.  
    40.         accumulator = new NativeList<Entry>(1024, Allocator.Persistent);
    41.     }
    42.  
    43.     public void Dispose() {
    44.         if (accumulator.IsCreated) {
    45.             accumulator.Dispose();
    46.             sizeargs.Dispose();
    47.         }
    48.         if (_positions != null && _positions.IsValid()) {
    49.             //    _centers.EndWrite<float3>(lastCount);
    50.             if (_positionsWrite.IsCreated) {
    51.                 _positions.EndWrite<uint>(total);
    52.             }
    53.             //   _centers.Dispose();
    54.             _positions.Dispose();
    55.             //      _centers2.Dispose();
    56.             //      _positions2.Dispose();
    57.             _argsBuffer.Dispose();
    58.         }
    59.     }
    60.  
    61.     public void Prepare(uint numIndices) {
    62.         args[0] = numIndices;
    63.         //   _centers = new ComputeBuffer(1024, 12, ComputeBufferType.Structured, ComputeBufferMode.SubUpdates);
    64.         _positions = new ComputeBuffer(1024 * 1024, 4, ComputeBufferType.Structured, ComputeBufferMode.SubUpdates);
    65.         //     _centers2 = new ComputeBuffer(1024, 12, ComputeBufferType.Structured, ComputeBufferMode.SubUpdates);
    66.         //      _positions2 = new ComputeBuffer(1024 * 1024, 4, ComputeBufferType.Structured, ComputeBufferMode.SubUpdates);
    67.         _argsBuffer = new ComputeBuffer(5, 4, ComputeBufferType.IndirectArguments);
    68.     }
    69.  
    70.     public void PrepareBlock(ComputeBuffer centers) {
    71.         block.SetBuffer("centers", centers);
    72.         block.SetBuffer("position", _positions);
    73.         block.SetBuffer("rotations", GrassTile.rotations);
    74.         block.SetBuffer("types", GrassSystem.types);
    75.     }
    76.  
    77.     public void Draw(ComputeBuffer centers, Material mat, Camera cam) {
    78.         if (total != 0) {
    79.             UnityEngine.Profiling.Profiler.BeginSample("End Write");
    80.             //    _centers.EndWrite<float3>(lastCount);
    81.             _positions.EndWrite<uint>(total);
    82.             PrepareBlock(centers);
    83.             UnityEngine.Profiling.Profiler.EndSample();
    84.             UnityEngine.Profiling.Profiler.BeginSample("Prepare");
    85.             Mesh mesh = GrassSystem.baseMesh[0];
    86.             args[1] = (uint)(total);
    87.             _argsBuffer.SetData(args);
    88.             Bounds bounds1 = new Bounds(cam.transform.position, Vector3.one * 2500);
    89.             UnityEngine.Profiling.Profiler.EndSample();
    90.  
    91.             UnityEngine.Profiling.Profiler.BeginSample("DrawMeshInstancedIndirect");
    92.             Graphics.DrawMeshInstancedIndirect(mesh, 0, mat, bounds1, _argsBuffer, 0, block,
    93.                 castshadow ? UnityEngine.Rendering.ShadowCastingMode.TwoSided : UnityEngine.Rendering.ShadowCastingMode.Off, receiveshadow);
    94.             UnityEngine.Profiling.Profiler.EndSample();
    95.         }
    96.     }
    97.  
    98.     public struct Entry {
    99.         public WildGrassTilePointers tile;
    100.         public int start;
    101.         public int length;
    102.         public float dist;
    103.         public int centerIndex;
    104.     }
    105.  
    106.     internal void Resize() {
    107.         //     Utils.Swap(ref _centers, ref _centers2);
    108.         //     Utils.Swap(ref _positions, ref _positions2);
    109.         //   if (Utils.RecreateIfSmaller(ref _centers, 12, lastCount = tiles.Count, ComputeBufferType.Structured, ComputeBufferMode.SubUpdates, 1.2f)) {
    110.         //       block.SetBuffer("centers", _centers);
    111.         //   }
    112.         if (Utils.RecreateIfSmaller(ref _positions, 4, total, ComputeBufferType.Structured, ComputeBufferMode.SubUpdates, 1.2f)) {
    113.             Debug.Log("Resized");
    114.             block.SetBuffer("position", _positions);
    115.         }
    116.     }
    117.  
    118.     internal void BeginWrite() {
    119.         if (total != 0) {
    120.             //      _centersWrite = _centers.BeginWrite<float3>(0, tiles.Count);
    121.             _positionsWrite = _positions.BeginWrite<uint>(0, total);
    122.         }
    123.     }
    124.  
    125.     public unsafe JobHandle Schedule(JobHandle inputDeps) {
    126.         int count = accumulator.Length;
    127.         AccumulateJob job = new AccumulateJob();
    128.         job.accumulator = accumulator;
    129.         job.positions = _positionsWrite;
    130.         return job.ScheduleBatch(count, 32, inputDeps);
    131.     }
    132.  
    133.     //internal void Order() {
    134.     //    tiles.Sort((T1, T2) => (int)(T1.dist - T2.dist));
    135.     //}
    136. }
    137.  
    138. public class DrawContainerContainer {
    139.     public DrawContainer Close;
    140.     public DrawContainer Medium;
    141.     public DrawContainer Far;
    142.     public DrawContainerContainer() {
    143.         Close = new DrawContainer(true, true);//shadow
    144.         Medium = new DrawContainer(false, true);//no shadow cast
    145.         Far = new DrawContainer(false, false);//no shadow
    146.     }
    147.  
    148.     internal void Dispose() {
    149.         Close.Dispose();
    150.         Medium.Dispose();
    151.         Far.Dispose();
    152.     }
    153.  
    154.     internal void Prepare(uint numIndices) {
    155.         Close.Prepare(numIndices);
    156.         Medium.Prepare(numIndices);
    157.         Far.Prepare(numIndices);
    158.     }
    159. }
    160. public class ECSDrawGrassSystem : JobComponentSystem {
    161.     GrassSystemConfig[] configs;
    162.     DrawContainerContainer[] containers;
    163.  
    164.  
    165.     JobHandle combined;
    166.     protected override void OnDestroy() {
    167.         base.OnDestroy();
    168.         for (int i = 0; i < containers.Length; i++) {
    169.             containers[i].Dispose();
    170.         }
    171.     }
    172.  
    173.  
    174.  
    175.     protected override void OnCreate() {
    176.         base.OnCreate();
    177.         configs = GameObject.FindObjectsOfType<GrassSystemConfig>();
    178.         if (configs == null || configs.Length == 0 || configs.All(T => !T.enabled)) {
    179.             Enabled = false;
    180.             Debug.Log("Grass Config disabled, terminating system");
    181.             return;
    182.         }
    183.         containers = new DrawContainerContainer[configs.Count()];
    184.         for (int i = 0; i < containers.Length; i++) {
    185.             containers[i] = new DrawContainerContainer();
    186.         }
    187.         GrassTile.buildRotationBuffer();
    188.         GrassSystem.InitTypes(configs.Cast(T => T.material).ToArray());
    189.  
    190.         GrassSystem.MakeMesh();
    191.         Mesh mesh = GrassSystem.baseMesh[0];
    192.         uint numIndices = mesh.GetIndexCount(0);
    193.  
    194.         for (int i = 0; i < containers.Length; i++) {
    195.             containers[i].Prepare(numIndices);
    196.         }
    197.  
    198.         //Close.PrepareBlock();
    199.         //Medium.PrepareBlock();
    200.         //Far.PrepareBlock();
    201.     }
    202.  
    203.     protected override JobHandle OnUpdate(JobHandle inputDeps) {
    204.         if (!combined.IsCompleted) {
    205.             combined.Complete();
    206.         }
    207.         for (int i = 0; i < configs.Length; i++) {
    208.             var config = configs[i];
    209.             DrawContainerContainer cont = containers[i];
    210.  
    211.             DrawContainer Close = cont.Close;
    212.             DrawContainer Medium = cont.Medium;
    213.             DrawContainer Far = cont.Far;
    214.  
    215.             UnityEngine.Profiling.Profiler.BeginSample("Draw Last Frame");
    216.             Far.Draw(config.Centers, config.material, config.cam);
    217.             Medium.Draw(config.Centers, config.material, config.cam);
    218.             Close.Draw(config.Centers, config.material, config.cam);
    219.  
    220.             UnityEngine.Profiling.Profiler.EndSample();
    221.             UnityEngine.Profiling.Profiler.BeginSample("Prepare");
    222.             Plane[] planes = GeometryUtility.CalculateFrustumPlanes(config.cam);
    223.  
    224.             UnityEngine.Profiling.Profiler.EndSample();
    225.             UnityEngine.Profiling.Profiler.BeginSample("Iterate Tiles");
    226.             Close.total = 0;
    227.             Medium.total = 0;
    228.             Far.total = 0;
    229.             Vector3 position = config.cam.transform.position;
    230.  
    231.             int count = config.totalTiles;
    232.             if (Far.accumulator.Capacity < count) {
    233.                 Close.accumulator.ResizeUninitialized((int)(count / 10));
    234.                 Medium.accumulator.ResizeUninitialized((int)(count / 2));
    235.                 Far.accumulator.ResizeUninitialized((int)(count * 1.2f));
    236.             }
    237.             int sc = count / 32 + 2;
    238.             if (Far.sizeargs.Capacity < sc) {
    239.                 Close.sizeargs.ResizeUninitialized(sc);
    240.                 Medium.sizeargs.ResizeUninitialized(sc);
    241.                 Far.sizeargs.ResizeUninitialized(sc);
    242.             }
    243.  
    244.             Close.accumulator.Clear();
    245.             Medium.accumulator.Clear();
    246.             Far.accumulator.Clear();
    247.             Close.sizeargs.Clear();
    248.             Medium.sizeargs.Clear();
    249.             Far.sizeargs.Clear();
    250.             config.indexes.Clear();
    251.  
    252.             UnityEngine.Profiling.Profiler.BeginSample("BoundCheckerJob");
    253.             BoundCheckerJob bounder = new BoundCheckerJob();
    254.             Plane[] planes2 = GeometryUtility.CalculateFrustumPlanes(config.cam);
    255.             bounder.Frustrum = new UpdateFrustrumCulling.FrustrumPlanes() {
    256.                 Left = planes2[0],
    257.                 Right = planes2[1],
    258.                 Down = planes2[2],
    259.                 Up = planes2[3],
    260.                 Near = planes2[4],
    261.                 Far = planes2[5]
    262.             };
    263.             bounder.end = config.totalTiles;
    264.             bounder.position = position;
    265.             bounder.Close = Close.accumulator.AsParallelWriter();
    266.             bounder.Medium = Medium.accumulator.AsParallelWriter();
    267.             bounder.Far = Far.accumulator.AsParallelWriter();
    268.             bounder.CloseCount = Close.sizeargs.AsParallelWriter();
    269.             bounder.MediumCount = Medium.sizeargs.AsParallelWriter();
    270.             bounder.FarCount = Far.sizeargs.AsParallelWriter();
    271.             bounder.Source = config.ECSWildTiles;
    272.             bounder.Schedule(inputDeps).Complete();
    273.  
    274.             UnityEngine.Profiling.Profiler.BeginSample("Sum");
    275.             Close.total = Close.sizeargs.ToArray().Sum(T => T);
    276.             Medium.total = Medium.sizeargs.ToArray().Sum(T => T);
    277.             Far.total = Far.sizeargs.ToArray().Sum(T => T);
    278.             UnityEngine.Profiling.Profiler.EndSample();
    279.             UnityEngine.Profiling.Profiler.EndSample();
    280.             UnityEngine.Profiling.Profiler.EndSample();
    281.  
    282.             UnityEngine.Profiling.Profiler.BeginSample("Resizing");
    283.             Close.Resize();
    284.             Medium.Resize();
    285.             Far.Resize();
    286.             UnityEngine.Profiling.Profiler.EndSample();
    287.             //UnityEngine.Profiling.Profiler.BeginSample("OrderByDistance");
    288.             //Close.Order();
    289.             //Medium.Order();
    290.             //Far.Order();
    291.             //UnityEngine.Profiling.Profiler.EndSample();
    292.             UnityEngine.Profiling.Profiler.BeginSample("Scheduling");
    293.             UnityEngine.Profiling.Profiler.BeginSample("Begin Write");
    294.             Close.BeginWrite();
    295.             Medium.BeginWrite();
    296.             Far.BeginWrite();
    297.             UnityEngine.Profiling.Profiler.EndSample();
    298.             combined = JobHandle.CombineDependencies(Close.Schedule(inputDeps), Medium.Schedule(inputDeps), Far.Schedule(inputDeps));
    299.             UnityEngine.Profiling.Profiler.EndSample();
    300.             FPSDisplay.ExtraText = "Total blades of grass: " + (Close.total + Medium.total + Far.total);
    301.         }
    302.         return combined;
    303.     }
    304.     //[BurstCompile]
    305.     //public struct AccumulateJob : IJob {
    306.     //    public int centerIndex;
    307.     //    public int startIndex;
    308.     //    public int size;
    309.     //    [NativeDisableContainerSafetyRestriction] public NativeArray<uint> positions;
    310.     //    [ReadOnly] public NativeArray<ushort> tile_positions;
    311.     //    public void Execute() {
    312.     //        int end = startIndex + size;
    313.     //        for (int i = startIndex; i < end; i++) {
    314.     //            positions[i] = ((uint)((tile_positions[i - startIndex]) << 16)) | ((uint)(centerIndex & 0x3FFFF));
    315.     //        }
    316.     //    }
    317.     //}
    318. }
    319.  
    320. [BurstCompile]
    321. public struct AccumulateJob : IJobParallelForBatch {//ParallelForBatch {
    322.     [ReadOnly] public NativeList<DrawContainer.Entry> accumulator;
    323.     [NativeDisableContainerSafetyRestriction] public NativeArray<uint> positions;
    324.     public unsafe void Execute(int startIndex, int count) {
    325.         int end = startIndex + count;
    326.         for (int j = startIndex; j < end; j++) {
    327.             int si = accumulator[j].start;
    328.             int size = accumulator[j].length;
    329.             int centerIndex = accumulator[j].centerIndex;
    330.             int end2 = si + size;
    331.             //   centers[j] = center[j];
    332.             NativeArray<ushort> tile_positions = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray<ushort>
    333.                 (accumulator[j].tile.Positions.ToPointer(), size * 2, Allocator.None);
    334. #if ENABLE_UNITY_COLLECTIONS_CHECKS
    335.             var handle = AtomicSafetyHandle.Create();
    336.             NativeArrayUnsafeUtility.SetAtomicSafetyHandle(ref tile_positions, handle);
    337. #endif
    338.             for (int i = si; i < end2; i++) {
    339.                 positions[i] = ((uint)((tile_positions[i - si]) << 16)) | ((uint)(centerIndex & 0x3FFFF));
    340.             }
    341. #if ENABLE_UNITY_COLLECTIONS_CHECKS
    342.             AtomicSafetyHandle.Release(handle);
    343. #endif
    344.         }
    345.     }
    346. }
    347.  
    348. [BurstCompile]
    349. public struct BoundCheckerJob : IJob {
    350.     public UpdateFrustrumCulling.FrustrumPlanes Frustrum;
    351.     public float3 position;
    352.     public int end;
    353.     public NativeList<int>.ParallelWriter CloseCount;
    354.     public NativeList<int>.ParallelWriter MediumCount;
    355.     public NativeList<int>.ParallelWriter FarCount;
    356.     public NativeList<DrawContainer.Entry>.ParallelWriter Close;
    357.     public NativeList<DrawContainer.Entry>.ParallelWriter Medium;
    358.     public NativeList<DrawContainer.Entry>.ParallelWriter Far;
    359.     [NativeDisableContainerSafetyRestriction, ReadOnly] public NativeArray<WildGrassTilePointers> Source;
    360.  
    361.     public unsafe void Execute() {
    362.         int TClose = 0;
    363.         int TMedium = 0;
    364.         int TFar = 0;
    365.         for (int j = 0; j < end; j++) {
    366.             WildGrassTilePointers tile = Source[j];
    367.             Vector3 min = tile.bounds.min;
    368.             Vector3 max = tile.bounds.max;
    369.             if (CheckPlanes(min, max)) {
    370.                 float d = Vector3.Distance(tile.Center, position);
    371.                 float x = Math.Max(0, d - 15) / 4;
    372.                 int closestPower = Mathf.RoundToInt(Mathf.Pow(2, Mathf.Ceil(Mathf.Log(x, 2))));
    373.                 d = Mathf.Min(64, Mathf.Max(1, closestPower));
    374.  
    375.                 int l = tile.Count;
    376.                 if (d == 64) {
    377.                     l /= 16;
    378.                 } else if (d == 32) {
    379.                     l /= 8;
    380.                 } else if (d >= 8) {
    381.                     l /= 4;
    382.                 } else if (d >= 2) {
    383.                     l /= 2;
    384.                 }
    385.  
    386.                 if (l > 0) {
    387.                     if (d >= 1) {
    388.                         Close.AddNoResize(new DrawContainer.Entry() { tile = tile, start = TClose, length = l, dist = d, centerIndex = j });
    389.                         TClose += l;
    390.                     } else if (d < 64) {
    391.                         Medium.AddNoResize(new DrawContainer.Entry() { tile = tile, start = TMedium, length = l, dist = d, centerIndex = j });
    392.                         TMedium += l;
    393.                     } else {
    394.                         Far.AddNoResize(new DrawContainer.Entry() { tile = tile, start = TFar, length = l, dist = d, centerIndex = j });
    395.                         TFar += l;
    396.                     }
    397.                 }
    398.             }
    399.         }
    400.         CloseCount.AddNoResize(TClose);
    401.         MediumCount.AddNoResize(TMedium);
    402.         FarCount.AddNoResize(TFar);
    403.     }
    404.  
    405.  
    406.     private bool CheckPlanes(float3 boundsMin, float3 boundsMax) {
    407.         Vector3 vmin, vmax;
    408.         for (int planeIndex = 0; planeIndex < 6; planeIndex++) {
    409.             var normal = Frustrum[planeIndex].normal;
    410.             var planeDistance = Frustrum[planeIndex].distance;
    411.             // X axis
    412.             if (normal.x < 0) {
    413.                 vmin.x = boundsMin.x;
    414.                 vmax.x = boundsMax.x;
    415.             } else {
    416.                 vmin.x = boundsMax.x;
    417.                 vmax.x = boundsMin.x;
    418.             }
    419.             // Y axis
    420.             if (normal.y < 0) {
    421.                 vmin.y = boundsMin.y;
    422.                 vmax.y = boundsMax.y;
    423.             } else {
    424.                 vmin.y = boundsMax.y;
    425.                 vmax.y = boundsMin.y;
    426.             }
    427.             // Z axis
    428.             if (normal.z < 0) {
    429.                 vmin.z = boundsMin.z;
    430.                 vmax.z = boundsMax.z;
    431.             } else {
    432.                 vmin.z = boundsMax.z;
    433.                 vmax.z = boundsMin.z;
    434.             }
    435.  
    436.             var dot1 = normal.x * vmin.x + normal.y * vmin.y + normal.z * vmin.z;
    437.             if (dot1 + planeDistance < 0)
    438.                 return false;
    439.  
    440.             var dot2 = normal.x * vmax.x + normal.y * vmax.y + normal.z * vmax.z;
    441.             if (dot2 + planeDistance <= 0)
    442.                 return true;
    443.         }
    444.  
    445.         return true;
    446.     }
    447. }
     
  2. officialfonee

    officialfonee

    Joined:
    May 22, 2018
    Posts:
    42
    Did you ever figure this out? Ive been using ECS with DrawMeshInstancedIndirect and im getting the same flickering.

    EDIT: I figured out why mine was flickering. If you use a parallel job to fill your matrices for DrawMeshInstancedIndirect, matrices were taking a different index as they were getting culled every frame. This cause their indices to constantly be different and for some reason made DrawMeshInstancedIndirect to flicker. I solved this easily by just calling my job on a single thread. I am not really sure why it matters to DrawMeshInstancedIndirect, but it fixed it for me.
     
    Last edited: Jan 2, 2021
    deus0 likes this.