public DoubleBufferNativeWritableHandle GetNextNativeWritableHandle( Matrix4x4 localToWorldTransform, ref JobHandleWrapper dependency) { if (IsDisposed) { throw new System.ObjectDisposedException("DoubleBufferModifierHandle", "Tried to write a modification via a disposed writing handle"); } UnityEngine.Profiling.Profiler.BeginSample("volume clearing"); if (!newDataIsAvailable) { // Only swap data if the old data hasn't been picked up yet. // just update the new data where it is mostRecentDataInA = !mostRecentDataInA; newDataIsAvailable = true; } var mostRecentVolumeData = mostRecentDataInA ? valuesA : valuesB; var volumeClearJob = new NativeArrayClearJob { newValue = 0f, writeArray = mostRecentVolumeData }; dependency = volumeClearJob.Schedule(mostRecentVolumeData.Length, 10000, dependency + writeDependency); writeDependency = dependency; UnityEngine.Profiling.Profiler.EndSample(); return(new DoubleBufferNativeWritableHandle( mostRecentVolumeData, voxelLayout, localToWorldTransform)); }
public override void RemoveEffects(VoxelWorldVolumetricLayerData layerData, ref JobHandleWrapper dependency) { var layout = layerData.VoxelLayout; var subtractCleanupJob = new NativeArrayAdditionNegativeProtection { allBaseMarkers = layerData, layerToAdd = newValues, layerMultiplier = -1, markerLayerIndex = doubleBufferedLayerIndex, totalLayersInBase = layout.dataLayerCount }; dependency = subtractCleanupJob.Schedule(layout.totalVoxels, 1000, dependency + writeDependency); }
/// <summary> /// takes in a by-voxel data array. returns another array of the same format with the diffused results. /// may modify the values in the input array. may return the input array. will handle disposing the input /// array if not returned. /// </summary> public static void ComputeDiffusion( VolumetricWorldVoxelLayout voxelLayout, DoubleBuffered <float> layerData, NativeArray <float> diffusionConstantMultipliers, float minimumDiffusionConstantMultiplier, float deltaTime, float diffusionConstant, ref JobHandleWrapper dependecy) { var combinedDiffusionFactor = deltaTime * diffusionConstant; if (combinedDiffusionFactor >= 1f / 6) { throw new System.ArgumentException("diffusion factor cannot exceed the connectivity of each node"); } var adjacencyVectors = new NativeArray <Vector3Int>(new[] { new Vector3Int(1, 0, 0), new Vector3Int(-1, 0, 0), new Vector3Int(0, 1, 0), new Vector3Int(0, -1, 0), new Vector3Int(0, 0, 1), new Vector3Int(0, 0, -1), }, Allocator.TempJob); var diffuseJob = new VoxelAdjacencyResourceConservingBoundaryComputeJob { sourceDiffusionValues = layerData.CurrentData, targetDiffusionValues = layerData.NextData, diffusionConstantAdjusters = diffusionConstantMultipliers, minimumDiffusionConstantMultiplier = minimumDiffusionConstantMultiplier, maximumDiffsuionConstant = 1 / 7f, adjacencyVectors = adjacencyVectors, voxelLayout = voxelLayout, diffusionConstant = combinedDiffusionFactor }; dependecy = diffuseJob.Schedule(layerData.CurrentData.Length, 1000, dependecy); layerData.Swap(); adjacencyVectors.Dispose(dependecy); }
public virtual bool ApplyLayerWideUpdate(VoxelWorldVolumetricLayerData data, float deltaTime, ref JobHandleWrapper dependecy) { if (effects.Length <= 0) { return(false); } var voxelLayout = data.VoxelLayout; var copyInData = new NativeArray <float>(voxelLayout.totalVoxels, Allocator.TempJob); var copyInJob = new CopyVoxelToWorkingDataJob { layerData = data, targetData = copyInData, layerId = voxelLayerId }; dependecy = copyInJob.Schedule(copyInData.Length, 1000, dependecy); var swapSpace = new NativeArray <float>(voxelLayout.totalVoxels, Allocator.TempJob); var workingData = new DoubleBuffered <float>(copyInData, swapSpace); var changed = false; foreach (var effect in effects) { if (effect.ApplyEffectToLayer(workingData, data, deltaTime, ref dependecy)) { changed = true; } } if (changed) { var copyBackJob = new CopyWorkingDataToVoxels { layerData = data, sourceData = workingData.CurrentData, layerId = this.voxelLayerId }; dependecy = copyBackJob.Schedule(workingData.CurrentData.Length, 1000, dependecy); workingData.Dispose(dependecy); } return(changed); }
public TurtleStringReadingCompletable( Mesh targetMesh, int totalSubmeshes, DependencyTracker <SymbolString <float> > symbols, DependencyTracker <NativeTurtleData> nativeData, int branchStartChar, int branchEndChar, TurtleState defaultState, CustomRuleSymbols customSymbols, TurtleVolumeWorldReferences volumetrics, Matrix4x4 localToWorldTransform) { this.targetMesh = targetMesh; this.nativeData = nativeData; UnityEngine.Profiling.Profiler.BeginSample("turtling job"); JobHandleWrapper volumetricJobHandle = currentJobHandle; var volumetricHandles = new TurtleVolumetricHandles { durabilityWriter = volumetrics.durabilityWriter.GetNextNativeWritableHandle(localToWorldTransform, ref volumetricJobHandle), universalWriter = volumetrics.universalLayerWriter.GetNextNativeWritableHandle(localToWorldTransform), volumetricData = volumetrics.world.NativeVolumeData.openReadData.AsReadOnly() }; currentJobHandle = volumetricJobHandle; UnityEngine.Profiling.Profiler.BeginSample("allocating"); var tmpHelperStack = new TmpNativeStack <TurtleState>(50, Allocator.TempJob); organInstances = new NativeList <TurtleOrganInstance>(100, Allocator.TempJob); newMeshSizeBySubmesh = new NativeArray <TurtleMeshAllocationCounter>(totalSubmeshes, Allocator.TempJob); UnityEngine.Profiling.Profiler.EndSample(); NativeArray <float> destructionCommandTimestamps; if (volumetrics.damageFlags != null) { destructionCommandTimestamps = volumetrics.damageFlags.GetDestructionCommandTimestampsReadOnly(); } else { destructionCommandTimestamps = new NativeArray <float>(0, Allocator.TempJob); } var entitySpawningSystem = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem <BeginSimulationEntityCommandBufferSystem>(); var entitySpawnBuffer = entitySpawningSystem.CreateCommandBuffer(); var turtleCompileJob = new TurtleCompilationJob { symbols = symbols.Data, operationsByKey = nativeData.Data.operationsByKey, organData = nativeData.Data.allOrganData, organInstances = organInstances, newMeshSizeBySubmesh = newMeshSizeBySubmesh, spawnEntityBuffer = entitySpawnBuffer, nativeTurtleStack = tmpHelperStack, branchStartChar = branchStartChar, branchEndChar = branchEndChar, currentState = defaultState, customRules = customSymbols, volumetricHandles = volumetricHandles, hasVolumetricDestruction = volumetrics.damageFlags != null, volumetricDestructionTimestamps = destructionCommandTimestamps, earliestValidDestructionCommand = volumetrics.damageFlags != null ? Time.time - volumetrics.damageFlags.timeCommandStaysActive : -1 }; currentJobHandle = turtleCompileJob.Schedule(currentJobHandle); volumetrics.world.NativeVolumeData.RegisterReadingDependency(currentJobHandle); entitySpawningSystem.AddJobHandleForProducer(currentJobHandle); volumetrics.damageFlags?.RegisterReaderOfDestructionFlags(currentJobHandle); volumetrics.durabilityWriter.RegisterWriteDependency(currentJobHandle); volumetrics.universalLayerWriter.RegisterWriteDependency(currentJobHandle); nativeData.RegisterDependencyOnData(currentJobHandle); symbols.RegisterDependencyOnData(currentJobHandle); currentJobHandle = tmpHelperStack.Dispose(currentJobHandle); if (volumetrics.damageFlags == null) { currentJobHandle = destructionCommandTimestamps.Dispose(currentJobHandle); } UnityEngine.Profiling.Profiler.EndSample(); }
public override bool ApplyEffectToLayer(DoubleBuffered <float> layerData, VoxelWorldVolumetricLayerData readonlyLayerData, float deltaTime, ref JobHandleWrapper dependecy) { ComputeDiffusion(layerData, readonlyLayerData.VoxelLayout, deltaTime, globalDiffusionConstant, ref dependecy); return(true); }
/// <summary> /// remove any persistent effects this handle has on the world. <br/> /// For a double buffered handle, this means subtracting the total sum which this /// handle has contributed to the volume world /// </summary> public abstract void RemoveEffects(VoxelWorldVolumetricLayerData layerData, ref JobHandleWrapper dependency);
/// <summary> /// Plays back any changes that have been cached inside this modification handle /// </summary> /// <param name="layerData">the layer data to apply changes to</param> /// <param name="dependency">job handle</param> /// <returns>true if any changes were available to be applied, false otherwise</returns> public abstract bool ConsolidateChanges(VoxelWorldVolumetricLayerData layerData, ref JobHandleWrapper dependency);
public override void RemoveEffects(VoxelWorldVolumetricLayerData layerData, ref JobHandleWrapper dependency) { // command buffer has no record of the effects it has had on the world return; }
public override bool ConsolidateChanges(VoxelWorldVolumetricLayerData layerData, ref JobHandleWrapper dependency) { // TODO: consider skipping if writeDependency is not complete yet. should the job chain keep extending, or should // consolidation be deffered? if (!newDataIsAvailable) { return(false); } var consolidationJob = new VoxelMarkerConsolidation { allBaseMarkers = layerData, oldMarkerLevels = oldValues, newMarkerLevels = newValues, markerLayerIndex = doubleBufferedLayerIndex, }; dependency = consolidationJob.Schedule(newValues.Length, 1000, dependency + writeDependency); RegisterReadDependency(dependency); newDataIsAvailable = false; return(true); }
public override bool ConsolidateChanges(VoxelWorldVolumetricLayerData layerData, ref JobHandleWrapper dependency) { if (!newDataIsAvailable) { return(false); } var commandPlaybackJob = new LayerModificationCommandPlaybackJob { commands = modificationCommands, dataArray = layerData, voxelLayout = voxelLayout }; dependency = commandPlaybackJob.Schedule(dependency + writeDependency); RegisterReadDependency(dependency); newDataIsAvailable = false; return(true); }
/// <summary> /// apply whatever effect this transform applies to the layer. /// /// </summary> /// <param name="data"></param> /// <param name="deltaTime"></param> /// <param name="dependecy"></param> /// <returns>true if any changes were applied</returns> public abstract bool ApplyEffectToLayer(DoubleBuffered <float> layerData, VoxelWorldVolumetricLayerData readonlyLayerData, float deltaTime, ref JobHandleWrapper dependecy);
private void RepairDamage(DoubleBuffered <float> layerData, VoxelWorldVolumetricLayerData readonlyLayerData, float deltaTime, ref JobHandleWrapper dependency) { damageDataUpdateDependency?.Complete(); var voxelLayers = readonlyLayerData; var damageValues = layerData.CurrentData; // this is not a parallized job, so edits are made in-place var dampenDamage = new DampenDamageJob { voxelLayerData = voxelLayers, voxelLayout = voxelLayers.VoxelLayout, volumetricDamageValues = damageValues, durabilityRegenerationFactor = Mathf.Exp(regenerationPerSecondAsPercentOfDurability * Time.deltaTime) - 1 }; dependency = JobHandle.CombineDependencies(destructionFlagReadDependencies, dependency); dependency = dampenDamage.Schedule(damageValues.Length, 1000, dependency); }
private void UpdateDestructionFlags(DoubleBuffered <float> layerData, VoxelWorldVolumetricLayerData readonlyLayerData, float deltaTime, ref JobHandleWrapper dependency) { damageDataUpdateDependency?.Complete(); var damageValues = layerData.CurrentData; // this is not a parallized job, so edits are made in-place var voxelLayers = readonlyLayerData; var updateJob = new UpdatePlantDestructionFlags { voxelLayerData = voxelLayers, flagCapLayerIndex = voxelResourceCapLayerId, voxelLayout = voxelLayers.VoxelLayout, volumetricDamageValues = damageValues, volumetricDestructionTimestamps = volumetricDestructionTimestamps, currentTime = Time.time, durabilityRegenerationFactor = Mathf.Exp(regenerationPerSecondAsPercentOfDurability * deltaTime) - 1 }; dependency = JobHandle.CombineDependencies(destructionFlagReadDependencies, dependency); damageDataUpdateDependency = dependency = updateJob.Schedule(damageValues.Length, 1000, dependency); }
public override bool ApplyEffectToLayer(DoubleBuffered <float> layerData, VoxelWorldVolumetricLayerData readonlyLayerData, float deltaTime, ref JobHandleWrapper dependecy) { UpdateDestructionFlags(layerData, readonlyLayerData, deltaTime, ref dependecy); return(true); }