public void Length() { var array = new NativeArray3D <int>(length, width, height, Unity.Collections.Allocator.Temp); Assert.AreEqual(length * width * height, array.Length); array.Dispose(); }
public static JobHandle Schedule(NativeArray3D <GridNode> grid, ulong flags, int3 min, int3 max) { return(new SetFlagsInNodeRange { Flags = flags, Grid = grid, LocalGridMin = min, LocalGridMax = max, }.Schedule()); }
public void Dispose() { var array = new NativeArray3D <int>(length, width, height, Unity.Collections.Allocator.Temp); Assert.IsTrue(array.IsCreated); array.Dispose(); Assert.Throws <System.ObjectDisposedException>(() => { array[0, 0, 0] = 10; }); Assert.False(array.IsCreated); Assert.Throws <System.ObjectDisposedException>(() => { array.Dispose(); }); Assert.Throws <System.ObjectDisposedException>(() => { array.Dispose(default).Complete();
public int3 GetNearestNodeIndices(NativeArray3D <GridNode> array, Vector3 position, GridViewData viewData) { var gridX = ToGridDistance(position.x, viewData.BoxSize); var gridY = ToGridDistance(position.y, viewData.BoxSize); var gridZ = ToGridDistance(position.z, viewData.BoxSize); if (gridX < 0) { gridX = 0; } if (gridY < 0) { gridY = 0; } if (gridZ < 0) { gridZ = 0; } var xLen = array.GetLength(0); var yLen = array.GetLength(1); var zLen = array.GetLength(2); if (gridX > xLen) { gridX = xLen; } if (gridY > yLen) { gridY = yLen; } if (gridZ > zLen) { gridZ = zLen; } return(new int3(gridX, gridY, gridZ)); }
public static unsafe (PathStatus PathStatus, List <GridNode> NodePath, List <Vector3> VectorPath) Complete(BurstAStarPathFinder pathFinder, ref NativeArray3D <GridNode> grid, INativeArrayProducer <NativeAreaDefinition> areas, int queryId, GridPoint start, GridPoint end, ulong allowedFlags, float4x4 localToWorld) { using (var nativeAreas = areas.ToNativeArray(Allocator.TempJob)) using (var nativePath = new NativeList <GridNode>(grid.Length, Allocator.TempJob)) using (var nativeVectorPath = new NativeList <Vector3>(grid.Length, Allocator.TempJob)) using (var nativePriorityQueue = new NativePriorityQueue(grid.Length / 8, Allocator.TempJob)) { var result = new PathFindingJobResult(); var job = new PathFindingJob { QueryId = queryId, AllowedFlags = allowedFlags, StartPoint = start, EndPoint = end, OpenQueue = nativePriorityQueue, Grid = grid, Areas = nativeAreas, Path = nativePath, MaxPoints = 5000, WorldPath = nativeVectorPath, TransformMatrix = localToWorld, ResultPtr = &result }; pathFinder.Stopwatch.Restart(); job.Run(); pathFinder.Stopwatch.Stop(); var path = job.Path.ToArray().ToList(); var worldPath = nativeVectorPath.ToArray().ToList(); return(result.PathStatus, path, worldPath); } }
/// <summary> /// Voxelizes the mesh into the specified grid. The mesh is scaled to fit the grid (minus padding). /// Returns the voxelization job containing its job handle. The voxelization job must be disposed once the job has completed. /// </summary> /// <param name="vertices"></param> /// <param name="normals"></param> /// <param name="grid"></param> /// <param name="material"></param> /// <param name="properties"></param> /// <returns>The voxelization job containing its job handle. The voxelization job must be disposed once the job has completed.</returns> public static VoxelizationJob Voxelize <TIndexer>(NativeArray <float3> vertices, NativeArray <float3> normals, NativeArray3D <Voxel, TIndexer> grid, int material, VoxelizationProperties properties) where TIndexer : struct, IIndexer { var triangles = vertices.Length / 3; var width = grid.Length(0); var height = grid.Length(1); var depth = grid.Length(2); var scaledVertices = new NativeArray <float3>(vertices.Length, Allocator.TempJob); var scaleJobHandle = new VoxelizerMeshScaleJob { inVertices = vertices, outVertices = scaledVertices, width = grid.Length(0), height = grid.Length(1), depth = grid.Length(2), padding = properties.padding }.Schedule(); var binsStream = new NativeStream(triangles, Allocator.TempJob); //Bin triangles var binJobHandle = new VoxelizerBinJob { vertices = scaledVertices, width = width, height = height, depth = depth, stream = binsStream.AsWriter() }.Schedule(triangles, properties.parallelForBatchCount, scaleJobHandle); var binColsX = new NativeList <VoxelizerCollectBinsJob.Column>(Allocator.TempJob); var binColsY = new NativeList <VoxelizerCollectBinsJob.Column>(Allocator.TempJob); var binColsZ = new NativeList <VoxelizerCollectBinsJob.Column>(Allocator.TempJob); var binsX = new NativeList <int>(Allocator.TempJob); var binsY = new NativeList <int>(Allocator.TempJob); var binsZ = new NativeList <int>(Allocator.TempJob); //Collect bins and reorder var collectBinsJobHandle = new VoxelizerCollectBinsJob { stream = binsStream.AsReader(), streams = triangles, width = width, height = height, depth = depth, binColumnsX = binColsX, binsX = binsX, binColumnsY = binColsY, binsY = binsY, binColumnsZ = binColsZ, binsZ = binsZ }.Schedule(binJobHandle); var intersectionsStreamX = new NativeStream(height * depth, Allocator.TempJob); var intersectionsStreamY = new NativeStream(width * depth, Allocator.TempJob); var intersectionsStreamZ = new NativeStream(width * height, Allocator.TempJob); //Intersect X axis var intersectXJobHandle = new VoxelizerMeshIntersectionJob { vertices = scaledVertices, normals = normals, columns = binColsX.AsDeferredJobArray(), bins = binsX, width = width, height = height, depth = depth, axis = 0, stream = intersectionsStreamX.AsWriter(), smoothNormals = properties.smoothNormals }.Schedule(binColsX, properties.parallelForBatchCount, collectBinsJobHandle); //Intersect Y axis var intersectYJobHandle = new VoxelizerMeshIntersectionJob { vertices = scaledVertices, normals = normals, columns = binColsY.AsDeferredJobArray(), bins = binsY, width = width, height = height, depth = depth, axis = 1, stream = intersectionsStreamY.AsWriter(), smoothNormals = properties.smoothNormals }.Schedule(binColsY, properties.parallelForBatchCount, collectBinsJobHandle); //Intersect Z axis var intersectZJobHandle = new VoxelizerMeshIntersectionJob { vertices = scaledVertices, normals = normals, columns = binColsZ.AsDeferredJobArray(), bins = binsZ, width = width, height = height, depth = depth, axis = 2, stream = intersectionsStreamZ.AsWriter(), smoothNormals = properties.smoothNormals }.Schedule(binColsZ, properties.parallelForBatchCount, collectBinsJobHandle); var intersectionColsX = new NativeList <VoxelizerCollectBinsJob.Column>(height * depth, Allocator.TempJob); var intersectionColsY = new NativeList <VoxelizerCollectBinsJob.Column>(width * depth, Allocator.TempJob); var intersectionColsZ = new NativeList <VoxelizerCollectBinsJob.Column>(width * height, Allocator.TempJob); var intersectionsX = new NativeList <float4>(Allocator.TempJob); var intersectionsY = new NativeList <float4>(Allocator.TempJob); var intersectionsZ = new NativeList <float4>(Allocator.TempJob); //Collect X axis var collectXJobHandle = new VoxelizerCollectIntersectionsJob { stream = intersectionsStreamX.AsReader(), binColumns = binColsX, columns = intersectionColsX, intersections = intersectionsX }.Schedule(intersectXJobHandle); //Collect Y axis var collectYJobHandle = new VoxelizerCollectIntersectionsJob { stream = intersectionsStreamY.AsReader(), binColumns = binColsY, columns = intersectionColsY, intersections = intersectionsY }.Schedule(intersectYJobHandle); //Collect Z axis var collectZJobHandle = new VoxelizerCollectIntersectionsJob { stream = intersectionsStreamZ.AsReader(), binColumns = binColsZ, columns = intersectionColsZ, intersections = intersectionsZ }.Schedule(intersectZJobHandle); //Voxelizing using only the axis intersections can result in holes. //The voxelizer job will detect those holes and put them in this list //so they can be fixed later var holes = new NativeList <VoxelizerFillJob <TIndexer> .Hole>(Allocator.TempJob); //Fill in materials and normals where possible var voxelizerFillJobHandle = new VoxelizerFillJob <TIndexer> { colsX = intersectionColsX, colsY = intersectionColsY, colsZ = intersectionColsZ, intersectionsX = intersectionsX, intersectionsY = intersectionsY, intersectionsZ = intersectionsZ, material = material, grid = grid, holes = holes, angleThreshold = properties.angleThreshold, snapThreshold = properties.snapThreshold }.Schedule(JobHandle.CombineDependencies(collectXJobHandle, collectYJobHandle, collectZJobHandle)); //If there are holes in the voxel data, i.e. missing intersections and normals, //then they are patched up in a second pass var patchesQueue = new NativeQueue <VoxelizerFindPatchesJob <TIndexer> .PatchedHole>(Allocator.TempJob); //Find all hole patches in parallel var findPatchesJobHandle = new VoxelizerFindPatchesJob <TIndexer> { vertices = scaledVertices, normals = normals, holes = holes.AsDeferredJobArray(), angleThreshold = properties.angleThreshold, smoothNormals = properties.smoothNormals, queue = patchesQueue.AsParallelWriter() }.Schedule(holes, properties.parallelForBatchCount, voxelizerFillJobHandle); //Apply the hole patches to the grid var applyPatchesJobHandle = new VoxelizerApplyPatchesJob <TIndexer> { queue = patchesQueue, grid = grid }.Schedule(findPatchesJobHandle); return(new VoxelizationJob(applyPatchesJobHandle, scaledVertices, binsStream, binColsX, binColsY, binColsZ, binsX, binsY, binsZ, intersectionsStreamX, intersectionsStreamY, intersectionsStreamZ, intersectionColsX, intersectionColsY, intersectionColsZ, intersectionsX, intersectionsY, intersectionsZ, holes, patchesQueue)); }
protected override JobHandle OnUpdate(JobHandle inputDeps) { if (!_voxelWorldSystem.IsInitialized) { return(inputDeps); } if (_isInitialized) { return(inputDeps); } var xzSize = _voxelWorldSystem.VoxelWorld.ChunkSize * _voxelWorldSystem.VoxelWorld.MaxChunks; VoxelsMap = new NativeArray3D <Entity>(xzSize.x, _voxelWorldSystem.VoxelWorld.ChunkSize.y, xzSize.z, Allocator.Persistent); _isInitialized = true; var worldPosition = GetComponentDataFromEntity <Translation>(true)[_voxelWorldSystem.VoxelWorld.Entity].Value; var World = _voxelWorldSystem.VoxelWorld; var et = _chunkGroup.ToEntityArray(Allocator.Persistent); var tmp = _chunkGroup.ToComponentDataArray <VoxelChunk>(Allocator.Persistent); var pos = _chunkGroup.ToComponentDataArray <Translation>(Allocator.Persistent); for (int i = 0; i < tmp.Length; i++) { var chunkEntity = et[i]; var voxelChunk = tmp[i]; var translation = pos[i]; if (voxelChunk.NeedsUpdate == 1) { int3 offset = World.MaxChunks * World.ChunkSize / 2; float x = worldPosition.x + voxelChunk.X * World.ChunkSize.x - offset.x; float z = worldPosition.z + voxelChunk.Z * World.ChunkSize.z - offset.z; float y = worldPosition.y; translation.Value = new Vector3(x, y, z); EntityManager.SetComponentData(chunkEntity, translation); voxelChunk.NeedsUpdate = 0; voxelChunk.IsInitialized = 1; EntityManager.SetComponentData(chunkEntity, voxelChunk); } if (voxelChunk.IsInitialized == 1 && voxelChunk.IsPopulated == 0) { var terrainHeight = GenerateTerrainHeight(voxelChunk, translation, _voxelWorldSystem.VoxelWorld.ChunkSize); for (int x = 0; x < World.ChunkSize.x; x++) { for (int y = 0; y < World.ChunkSize.y; y++) { for (int z = 0; z < World.ChunkSize.z; z++) { Vector3 position = new float3(translation.Value.x + x, translation.Value.y + y, translation.Value.z + z); Entity voxelEntity; switch (terrainHeight[x, y, z]) { case 1: voxelEntity = EntityManager.Instantiate(voxelChunk.VoxelPrefab1); break; case 2: voxelEntity = EntityManager.Instantiate(voxelChunk.VoxelPrefab2); break; default: continue; } EntityManager.SetComponentData(voxelEntity, new Voxel { Entity = voxelEntity, VoxelChunkEntity = chunkEntity, X = x, Y = y, Z = z, Initialized = 1 }); EntityManager.SetComponentData(voxelEntity, new Translation { Value = position }); VoxelsMap[x, y, z] = voxelEntity; } } } voxelChunk.IsPopulated = 1; } } et.Dispose(); tmp.Dispose(); pos.Dispose(); return(inputDeps); }
private void Update() { if (undo) { undo = false; var editManager = GetComponent <VoxelEditManagerContainer>().Instance; if (editManager != null) { editManager.Undo(); } } if (redo) { redo = false; var editManager = GetComponent <VoxelEditManagerContainer>().Instance; if (editManager != null) { editManager.Redo(); } } if (!lockSelection) { Camera camera = Camera.current; if (camera != null) { Vector3 relPos = camera.transform.position - transform.position; Vector3 relDir = Quaternion.Inverse(transform.rotation) * camera.transform.forward.normalized; //if (field.RayCast(relPos, relDir, 16, out TestVoxelField.RayCastResult result)) if (gameObject.GetComponent <VoxelWorldContainer>().Instance.RayCast(relPos, relDir, 64, out VoxelWorld <MortonIndexer> .RayCastResult result)) { selectedCell = new Vector3Int(Mathf.FloorToInt(result.pos.x), Mathf.FloorToInt(result.pos.y), Mathf.FloorToInt(result.pos.z)); } else { selectedCell = null; } if (selectedCell != null) { lockedSelection = selectedCell.Value; } else { lockedSelection = Vector3Int.zero; } } else { selectedCell = null; } } else { selectedCell = lockedSelection; } if (selectedCell != null && prevSelectedCell != selectedCell) { //field.FillCell(selectedCell.Value.x, selectedCell.Value.y, selectedCell.Value.z, 0, gizmoCellMaterials, gizmoCellIntersections, gizmoCellNormals); var sculpture = gameObject.GetComponent <VoxelWorldContainer>().Instance; VoxelChunk <MortonIndexer> chunk = sculpture.GetChunk(ChunkPos.FromVoxel(selectedCell.Value, sculpture.ChunkSize)); if (chunk != null) { chunk.FillCell( ((selectedCell.Value.x % sculpture.ChunkSize) + sculpture.ChunkSize) % sculpture.ChunkSize, ((selectedCell.Value.y % sculpture.ChunkSize) + sculpture.ChunkSize) % sculpture.ChunkSize, ((selectedCell.Value.z % sculpture.ChunkSize) + sculpture.ChunkSize) % sculpture.ChunkSize, 0, gizmoCellMaterials, gizmoCellIntersections, gizmoCellNormals); gizmoCell = new RawArrayVoxelCell(0, (Vector3)selectedCell.Value, gizmoCellMaterials, gizmoCellIntersections, gizmoCellNormals); NativeMemoryCache memoryCache = new NativeMemoryCache(Allocator.Persistent); var polygonizer = new CMSVoxelPolygonizer <RawArrayVoxelCell, CMSStandardProperties, SvdQefSolver <RawArrayVoxelCell>, IntersectionSharpFeatureSolver <RawArrayVoxelCell> >(new CMSStandardProperties(), new SvdQefSolver <RawArrayVoxelCell>(), new IntersectionSharpFeatureSolver <RawArrayVoxelCell>(), memoryCache); var components = new NativeList <VoxelMeshComponent>(Allocator.Persistent); var componentIndices = new NativeList <PackedIndex>(Allocator.Persistent); var componentVertices = new NativeList <VoxelMeshComponentVertex>(Allocator.Persistent); polygonizer.Polygonize(gizmoCell, components, componentIndices, componentVertices); gizmoComponents = new List <VoxelMeshComponent>(components.Length); for (int i = 0; i < components.Length; i++) { gizmoComponents.Add(components[i]); } gizmoComponentIndices = new List <PackedIndex>(componentIndices.Length); for (int i = 0; i < componentIndices.Length; i++) { gizmoComponentIndices.Add(componentIndices[i]); } gizmoComponentVertices = new List <VoxelMeshComponentVertex>(componentVertices.Length); for (int i = 0; i < componentVertices.Length; i++) { gizmoComponentVertices.Add(componentVertices[i]); } memoryCache.Dispose(); components.Dispose(); componentIndices.Dispose(); componentVertices.Dispose(); gizmoPosition = selectedCell.Value; gizmoTransform = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale); } } prevSelectedCell = selectedCell; float brushSize = 2.1f + 8; if (placeSdf) { placeSdf = false; regenerate = true; var editManager = GetComponent <VoxelEditManagerContainer>().Instance; switch (brushType) { case BrushType.Sphere: gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new SphereSDF(brushSize), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer()); break; case BrushType.Box: gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new BoxSDF(brushSize), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer()); break; case BrushType.Cylinder: gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new CylinderSDF(brushSize, brushSize), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer()); break; case BrushType.Pyramid: gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y - brushSize / 2, gizmoPosition.z), Quaternion.Euler(sdfRotation), new PyramidSDF(brushSize * 2, brushSize * 2), MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer()); break; case BrushType.Mesh: var mesh = voxelizeMesh.mesh; var triangles = mesh.triangles; var vertices = mesh.vertices; var normals = mesh.normals; var inVertices = new NativeArray <float3>(triangles.Length, Allocator.TempJob); var inNormals = new NativeArray <float3>(triangles.Length, Allocator.TempJob); for (int l = triangles.Length, i = 0; i < l; i += 3) { inVertices[i] = vertices[triangles[i]]; inVertices[i + 1] = vertices[triangles[i + 1]]; inVertices[i + 2] = vertices[triangles[i + 2]]; inNormals[i] = normals[triangles[i]]; inNormals[i + 1] = normals[triangles[i + 1]]; inNormals[i + 2] = normals[triangles[i + 2]]; } int voxelizerSize = 64; var outVoxels = new NativeArray3D <Voxel.Voxel, MortonIndexer>(new MortonIndexer(voxelizerSize, voxelizerSize, voxelizerSize), voxelizerSize, voxelizerSize, voxelizerSize, Allocator.TempJob); var voxelizationProperties = smoothVoxelizerNormals ? Voxelizer.VoxelizationProperties.SMOOTH : Voxelizer.VoxelizationProperties.FLAT; var watch = new System.Diagnostics.Stopwatch(); watch.Start(); using (var job = Voxelizer.Voxelize(inVertices, inNormals, outVoxels, MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), voxelizationProperties)) { job.Handle.Complete(); } watch.Stop(); Debug.Log("Voxelized mesh: " + watch.ElapsedMilliseconds + "ms"); watch.Reset(); watch.Start(); //TODO Make voxelizer also undoable? gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplyGrid((int)gizmoPosition.x, (int)gizmoPosition.y, (int)gizmoPosition.z, outVoxels, true, false, null); watch.Stop(); Debug.Log("Applied to grid: " + watch.ElapsedMilliseconds + "ms"); inVertices.Dispose(); inNormals.Dispose(); outVoxels.Dispose(); break; case BrushType.Custom: using (var sdf = customBrush.Instance.CreateSdf(Allocator.TempJob)) { gameObject.GetComponent <VoxelWorldContainer>().Instance.ApplySdf(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), sdf, MaterialColors.ToInteger(materialRed, materialGreen, materialBlue, materialTexture), replaceSdfMaterial, editManager.Consumer()); } break; } } if (gizmoPosition != null) { switch (brushType) { case BrushType.Sphere: gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new SphereSDF(brushSize)); break; case BrushType.Box: gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new BoxSDF(brushSize)); break; case BrushType.Cylinder: gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new CylinderSDF(brushSize, brushSize)); break; case BrushType.Pyramid: gameObject.GetComponent <SdfShapeRenderHandler>().Render(new Vector3(gizmoPosition.x, gizmoPosition.y - brushSize / 2, gizmoPosition.z), Quaternion.Euler(sdfRotation), new PyramidSDF(brushSize * 2, brushSize * 2)); break; case BrushType.Custom: Matrix4x4 brushTransform = Matrix4x4.TRS(new Vector3(gizmoPosition.x, gizmoPosition.y, gizmoPosition.z), Quaternion.Euler(sdfRotation), new Vector3(1, 1, 1)); using (var sdf = customBrush.Instance.CreateSdf(Allocator.TempJob)) { gameObject.GetComponent <SdfShapeRenderHandler>().Render(brushTransform, sdf); } Camera camera = Camera.current; if (camera != null) { selectedPrimitive = -1; var ray = camera.transform.forward.normalized; float maxDst = 60.0f; int steps = Mathf.CeilToInt(maxDst * 2); for (int i = 0; i < steps && selectedPrimitive < 0; i++) { var pos = camera.transform.position + ray * maxDst / steps * i; int j = 0; foreach (var primitive in customBrush.Instance.Primitives) { var renderSdf = customBrush.Instance.Evaluator.GetRenderSdf(primitive); if (renderSdf != null && renderSdf.Eval(math.mul(math.mul(brushTransform, primitive.invTransform), new float4(pos, 1.0f)).xyz) < 0) { selectedPrimitive = j; break; } j++; } } } if (selectedPrimitive >= 0 && selectedPrimitive < customBrush.Instance.Primitives.Count) { var primitive = customBrush.Instance.Primitives[selectedPrimitive]; var renderSdf = customBrush.Instance.Evaluator.GetRenderSdf(primitive); if (renderSdf != null) { gameObject.GetComponent <SdfShapeRenderHandler>().Render(brushTransform * (Matrix4x4)primitive.transform, renderSdf); } } break; } } if (generateEachFrame || regenerate) { regenerate = false; //GenerateMesh(); } }
public NativeArray3DDebugView(NativeArray3D <T> array) { m_Array = array; }