public VoxelUpdateInfo(VoxelUpdateInfo super, byte xi, byte yi, byte zi) : this() { size = super.size / VoxelBlock.CHILD_DIMENSION; detailLevel = (byte)(super.detailLevel + 1); control = super.control; x = super.x * VoxelBlock.CHILD_DIMENSION + xi; y = super.y * VoxelBlock.CHILD_DIMENSION + yi; z = super.z * VoxelBlock.CHILD_DIMENSION + zi; for (byte xii = 0; xii < DIMENSION; ++xii) { for (byte yii = 0; yii < DIMENSION; ++yii) { for (byte zii = 0; zii < DIMENSION; ++zii) { blocks[xii, yii, zii] = super.getSub(VoxelBlock.CHILD_COUNT_POWER, (byte)(xii + xi + VoxelBlock.CHILD_DIMENSION - 1), (byte)(yii + yi + VoxelBlock.CHILD_DIMENSION - 1), (byte)(zii + zi + VoxelBlock.CHILD_DIMENSION - 1)); renderers[xii, yii, zii] = super.renderers[(int)((xii + xi + 1) * 0.5), (int)((yii + yi + 1) * 0.5), (int)((zii + zi + 1) * 0.5)]; if (renderers[xii, yii, zii] == null || renderers[xii, yii, zii].old) { renderers[xii, yii, zii] = super.blocks[(int)((xii + xi + 1) * 0.5), (int)((yii + yi + 1) * 0.5), (int)((zii + zi + 1) * 0.5)].getRenderer(0, 0, 0, 0); if (renderers[xii, yii, zii] == null || renderers[xii, yii, zii].old) renderers[xii, yii, zii] = blocks[xii, yii, zii].getRenderer(0, 0, 0, 0); if (renderers[xii, yii, zii] != null && renderers[xii, yii, zii].old) renderers[xii, yii, zii] = null; } } } } }
public VoxelRenderer(VoxelIndex index, VoxelTree control) : this(index, control, new Vector3( index.x * control.sizes[index.depth], index.y * control.sizes[index.depth], index.z * control.sizes[index.depth])) { }
public void Test() { var voxelTree = new VoxelTree(Vector3.zero, Vector3.one * size); voxelTree.GetRoot().AddChild(OctreeNode.ChildIndex.LeftAboveBack).SetItem(4); voxelTree.GetRoot().AddChild(OctreeNode.ChildIndex.RightAboveForward).SetItem(5); }
public CubeModifier(VoxelTree control, Vector3 worldPosition, Vector3 worldDimensions, VoxelHolder value, bool updateMesh) : base(control, updateMesh) { this.value = value; Vector3 dimensions = worldDimensions / control.voxelSize(); min = control.transform.InverseTransformPoint(worldPosition) / control.voxelSize() - dimensions /2 - Vector3.one * (control.voxelSize() / 2); max = min + dimensions; apply(); }
public SphereModifier(VoxelTree control, Vector3 worldPosition, float worldRadius, VoxelHolder value, bool updateMesh) : base(control, updateMesh) { this.value = value; Vector3 radiusCube = new Vector3(worldRadius, worldRadius, worldRadius) / control.voxelSize(); min = control.transform.InverseTransformPoint(worldPosition) / control.voxelSize() - radiusCube - Vector3.one * (control.voxelSize() / 2); max = min + radiusCube * 2; apply(); }
public SphereModifier(VoxelTree control, Vector3 worldPosition, float worldRadius, VoxelHolder value, bool updateMesh) : base(control, updateMesh) { this.value = value; Vector3 radiusCube = new Vector3(worldRadius, worldRadius, worldRadius) / control.voxelSize(); Vector3 min = control.transform.InverseTransformPoint(worldPosition) / control.voxelSize() - radiusCube -Vector3.one *0.5f; Vector3 max = min + radiusCube * 2; center = (min + max) / 2; radius = center.x - min.x; minDis = (radius - 1); maxDis = (radius + 1); setMinMax(min, max); // apply(); }
public VoxelRenderer(VoxelIndex index, VoxelTree control, Vector3 localPosition) { this.index = index; this.position = localPosition; this.control = control; size = 0; ++rendCount; VERTS = new Vector3[0]; NORMS = new Vector3[0]; TRIS = new int[0]; lock(control.renderers) { control.renderers[index] = this; } }
public VoxelUpdateInfo(float size, VoxelHolder main, VoxelTree control) : this() { this.size = size; this.detailLevel = 0; this.control = control; x = y = z = 0; for (byte xi = 0; xi < DIMENSION; ++xi) { for (byte yi = 0; yi < DIMENSION; ++yi) { for (byte zi = 0; zi < DIMENSION; ++zi) { blocks[xi, yi, zi] = Voxel.empty; } } } blocks[1, 1, 1] = main; }
public GenMeshJob(VoxelBlock block, VoxelTree control, byte detailLevel) { this.block = block; this.control = control; this.detailLevel = detailLevel; }
public UpdateCheckJob(VoxelBlock block, VoxelTree control, byte detailLevel) { this.block = block; this.control = control; this.detailLevel = detailLevel; control.addUpdateCheckJob(); }
public LinkRenderersJob(VoxelTree control) { this.control = control; }
public void setFromSister(VoxelUpdateInfo sister, byte xi, byte yi, byte zi) { size = sister.size; detailLevel = sister.detailLevel; control = sister.control; x = sister.x + xi - 1; y = sister.y + yi - 1; z = sister.z + zi - 1; for (byte xii = (byte)(1 - (xi + 1) / 2); xii < DIMENSION - (xi / 2); ++xii) { for (byte yii = (byte)(1 - (yi + 1) / 2); yii < DIMENSION - (yi / 2); ++yii) { for (byte zii = (byte)(1 - (zi + 1) / 2); zii < DIMENSION - (zi / 2); ++zii) { blocks[xii, yii, zii] = sister.blocks[xii + xi - 1, yii + yi - 1, zii + zi - 1]; renderers[xii, yii, zii] = sister.renderers[xii + xi - 1, yii + yi - 1, zii + zi - 1]; } } } }
public void clearSuperRenderers(byte detailLevel, int x, int y, int z, VoxelTree control) { if (detailLevel > 0) { short factor = (short)(1 << (detailLevel - CHILD_COUNT_POWER)); byte xi = (byte)(x / factor); byte yi = (byte)(y / factor); byte zi = (byte)(z / factor); if (renderer != null && filledWithSubRenderers(false)) { control.enqueueJob(new DropRendererJob(renderer)); renderer = null; } ((VoxelBlock)children[xi, yi, zi]).clearSuperRenderers((byte)(detailLevel - CHILD_COUNT_POWER), x - xi * factor, y - yi * factor, z - zi * factor, control); } }
public void setToHeightmap(byte detailLevel, int x, int y, int z, ref float[,] map, byte material, VoxelTree control) { if (detailLevel <= CHILD_COUNT_POWER) { for (int xi = 0; xi < CHILD_DIMENSION; ++xi) { for (int zi = 0; zi < CHILD_DIMENSION; ++zi) { for (int yi = 0; yi < CHILD_DIMENSION; ++yi) { if (yi + y >= map[x + xi, z + zi]) break; else if (material == byte.MaxValue) { children[xi, yi, zi] = Voxel.empty; } else { if (yi + y >= map[x + xi, z + zi] - 1) { byte opacity = (byte)((map[x + xi, z + zi] - yi - y) * byte.MaxValue); if (opacity > control.isoLevel || children[xi, yi, zi].averageOpacity() <= opacity) children[xi, yi, zi] = new Voxel(material, opacity); } else { children[xi, yi, zi] = new Voxel(material, byte.MaxValue); } } } } } } else { int multiplier = (1 << (detailLevel - CHILD_COUNT_POWER)); for (int xi = 0; xi < CHILD_DIMENSION; ++xi) { for (int zi = 0; zi < CHILD_DIMENSION; ++zi) { int xMax = x + (xi + 1) * multiplier; int zMax = z + (zi + 1) * multiplier; float yMin = float.MaxValue; float yMax = 0; for (int xPos = x + xi * multiplier; xPos < xMax; ++xPos) { for (int zPos = z + zi * multiplier; zPos < zMax; ++zPos) { if (map[xPos, zPos] < yMin) yMin = map[xPos, zPos]; if (map[xPos, zPos] > yMax) yMax = map[xPos, zPos]; } } int firstUnsolidBlock = Mathf.Min(((int)(yMin - y)) / multiplier, CHILD_DIMENSION); int lastUnsolidBlock = Mathf.Min(((int)(yMax - y)) / multiplier, CHILD_DIMENSION - 1); int yi = 0; for (; yi < firstUnsolidBlock; ++yi) { if (material == byte.MaxValue) children[xi, yi, zi] = Voxel.empty; else children[xi, yi, zi] = new Voxel(material, byte.MaxValue); } if (lastUnsolidBlock < 0) continue; for (; yi <= lastUnsolidBlock; ++yi) { if (children[xi, yi, zi].GetType() == typeof(Voxel)) children[xi, yi, zi] = new VoxelBlock((Voxel)children[xi, yi, zi]); ((VoxelBlock)children[xi, yi, zi]).setToHeightmap((byte)(detailLevel - CHILD_COUNT_POWER), x + xi * multiplier, y + yi * multiplier, z + zi * multiplier, ref map, material, control); } } } } control.dirty = true; }
public void clearSubRenderers(bool clearSelf, VoxelTree control) { if (clearSelf && renderer != null) { //control.enqueueJob(new DropRendererJob(renderer)); renderer.clear(); renderer = null; return; } for (byte xi = 0; xi < CHILD_DIMENSION; ++xi) { for (byte yi = 0; yi < CHILD_DIMENSION; ++yi) { for (byte zi = 0; zi < CHILD_DIMENSION; ++zi) { if (children[xi, yi, zi].GetType() != typeof(Voxel)) ((VoxelBlock)children[xi, yi, zi]).clearSubRenderers(true, control); } } } }
public void clearSubRenderers(VoxelTree control) { clearSubRenderers(true, control); }
public void NeighboursTest() { var grandChildCoords = new Coords(new[] { new OctreeChildCoords(1, 1, 1), new OctreeChildCoords(0, 1, 0) }); Assert.AreEqual(2, grandChildCoords.Length); Assert.AreEqual(new OctreeChildCoords(1, 1, 1), grandChildCoords.GetCoord(0)); Assert.AreEqual(new OctreeChildCoords(0, 1, 0), grandChildCoords.GetCoord(1)); var neighbourCoords = VoxelTree.GetNeighbourCoords(grandChildCoords, NeighbourSide.Right); if (neighbourCoords != null) { var rightOfGrandChildCoords = neighbourCoords.Value; Assert.AreEqual(2, rightOfGrandChildCoords.Length); Assert.AreEqual(new OctreeChildCoords(1, 1, 1), rightOfGrandChildCoords.GetCoord(0)); Assert.AreEqual(new OctreeChildCoords(1, 1, 0), rightOfGrandChildCoords.GetCoord(1)); Assert.NotNull(VoxelTree.GetNeighbourCoords(rightOfGrandChildCoords, NeighbourSide.Left)); Assert.AreNotEqual(VoxelTree.GetNeighbourCoords(rightOfGrandChildCoords, NeighbourSide.Left), rightOfGrandChildCoords); var furtherRightCoords = VoxelTree.GetNeighbourCoords(rightOfGrandChildCoords, NeighbourSide.Right); // uh oh, we just went out of bounds // Assert.AreEqual(2, furtherRightCoords.Length); Assert.IsNull(furtherRightCoords); } // Assert.AreEqual(new OctreeChildCoords(0, 1, 1), furtherRightCoords.GetCoord(0)); // Assert.AreEqual(new OctreeChildCoords(0, 1, 0), furtherRightCoords.GetCoord(1)); // furtherRightCoords = VoxelNode.GetNeighbourCoords(furtherRightCoords, NeighbourSide.Right); // Assert.IsNotNull(furtherRightCoords, "furtherLeftCoords"); // not null because it will just look at another voxelTree instead var coords = VoxelTree.GetNeighbourCoords(grandChildCoords, NeighbourSide.Left); if (coords != null) { var leftOfGrandChildCoords = coords.Value; Assert.AreEqual(VoxelTree.GetNeighbourCoords(leftOfGrandChildCoords, NeighbourSide.Right), grandChildCoords); Assert.AreEqual(2, leftOfGrandChildCoords.Length); // and back again Assert.AreEqual(new OctreeChildCoords(0, 1, 1), leftOfGrandChildCoords.GetCoord(0)); Assert.AreEqual(new OctreeChildCoords(1, 1, 0), leftOfGrandChildCoords.GetCoord(1)); } var aboveGrandChildCoords = VoxelTree.GetNeighbourCoords(grandChildCoords, NeighbourSide.Above); // Assert.IsNotNull(aboveGrandChildCoords); // not null, just another voxelTree! Assert.IsNull(aboveGrandChildCoords); // null, oob coords = VoxelTree.GetNeighbourCoords(grandChildCoords, NeighbourSide.Below); if (coords != null) { var belowGrandChildCoords = coords.Value; Assert.AreEqual(VoxelTree.GetNeighbourCoords(belowGrandChildCoords, NeighbourSide.Above), grandChildCoords); Assert.AreEqual(2, belowGrandChildCoords.Length); Assert.AreEqual(new OctreeChildCoords(1, 1, 1), belowGrandChildCoords.GetCoord(0)); Assert.AreEqual(new OctreeChildCoords(0, 0, 0), belowGrandChildCoords.GetCoord(1)); coords = VoxelTree.GetNeighbourCoords(belowGrandChildCoords, NeighbourSide.Below); if (coords != null) { var furterBelowGrandChildCoords = coords.Value; Assert.AreEqual(VoxelTree.GetNeighbourCoords(furterBelowGrandChildCoords, NeighbourSide.Above), belowGrandChildCoords); Assert.AreEqual(2, furterBelowGrandChildCoords.Length); Assert.AreEqual(new OctreeChildCoords(1, 0, 1), furterBelowGrandChildCoords.GetCoord(0)); Assert.AreEqual(new OctreeChildCoords(0, 1, 0), furterBelowGrandChildCoords.GetCoord(1)); } // 111, 010, behind, z-1 // 110, 011 coords = VoxelTree.GetNeighbourCoords(grandChildCoords, NeighbourSide.Back); if (coords != null) { var behindGrandChildCoords = coords.Value; Assert.AreEqual(VoxelTree.GetNeighbourCoords(behindGrandChildCoords, NeighbourSide.Forward), grandChildCoords); Assert.AreEqual(2, belowGrandChildCoords.Length); Assert.AreEqual(new OctreeChildCoords(1, 1, 0), behindGrandChildCoords.GetCoord(0)); Assert.AreEqual(new OctreeChildCoords(0, 1, 1), behindGrandChildCoords.GetCoord(1)); } coords = VoxelTree.GetNeighbourCoords(grandChildCoords, NeighbourSide.Forward); if (coords != null) { var inFrontOfGrandChildCoords = coords.Value; Assert.AreEqual(VoxelTree.GetNeighbourCoords(inFrontOfGrandChildCoords, NeighbourSide.Back), grandChildCoords); Assert.AreEqual(2, belowGrandChildCoords.Length); Assert.AreEqual(new OctreeChildCoords(1, 1, 1), inFrontOfGrandChildCoords.GetCoord(0)); Assert.AreEqual(new OctreeChildCoords(0, 1, 1), inFrontOfGrandChildCoords.GetCoord(1)); } } const int incorrectSide = 6; Assert.Throws <ArgumentOutOfRangeException>( () => VoxelTree.GetNeighbourCoords(grandChildCoords, (NeighbourSide)incorrectSide)); Assert.Throws <ArgumentOutOfRangeException>( () => VoxelTree.GetNeighbourCoords(grandChildCoords, (NeighbourSide)incorrectSide + 1)); var rootCoords = new Coords(); Assert.IsNull(VoxelTree.GetNeighbourCoords(rootCoords, NeighbourSide.Above)); Assert.IsNull(VoxelTree.GetNeighbourCoords(rootCoords, NeighbourSide.Below)); Assert.IsNull(VoxelTree.GetNeighbourCoords(rootCoords, NeighbourSide.Forward)); Assert.IsNull(VoxelTree.GetNeighbourCoords(rootCoords, NeighbourSide.Back)); Assert.IsNull(VoxelTree.GetNeighbourCoords(rootCoords, NeighbourSide.Right)); Assert.IsNull(VoxelTree.GetNeighbourCoords(rootCoords, NeighbourSide.Left)); }
public static bool isRenderLod(float x, float y, float z, float size, VoxelTree control) { if (!control.useLod) return size == control.sizes[control.maxDetail]; return getDistSquare(control.getLocalCamPosition(), new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), size) >= size * size * control.getLodDetail(); }
public void updateAll(int x, int y, int z, byte detailLevel, VoxelTree control, bool force = false) { // check if this is a high enough detail level. If not, call the childrens' update methods if (!isRenderSize(control.sizes[detailLevel], control) && (!isRenderLod(x, y, z, control.sizes[detailLevel], control))) { for (byte xi = 0; xi < CHILD_DIMENSION; ++xi) { for (byte yi = 0; yi < CHILD_DIMENSION; ++yi) { for (byte zi = 0; zi < CHILD_DIMENSION; ++zi) { //VoxelUpdateInfo childInfo = new VoxelUpdateInfo(info, xi, yi, zi); if (children[xi, yi, zi].GetType() == typeof(Voxel)) { //if (!childInfo.isSolid()) children[xi, yi, zi] = new VoxelBlock((Voxel)children[xi, yi, zi]); //else //continue; } UpdateCheckJob job = new UpdateCheckJob((VoxelBlock)children[xi, yi, zi], control, (byte)(detailLevel + 1)); job.setOffset((byte)(x * CHILD_DIMENSION + xi), (byte)(y * CHILD_DIMENSION + yi), (byte)(z * CHILD_DIMENSION + zi)); control.enqueueCheck(job); } } } if (renderer != null) { //GameObject.Destroy(renderer.ob); //lock (myControl) { // myControl.enqueueJob(new DropRendererJob(renderer)); // renderer = null; //} renderer.old = true; } return; } // check if we already have a mesh if (renderer == null) { //clearSubRenderers(); renderer = new VoxelRenderer(new VoxelIndex(x, y, z, detailLevel), control); //info.renderers[1, 1, 1] = renderer; } else { renderer.old = false; if (!force) return; } // We should generate a mesh GenMeshJob updateJob = new GenMeshJob(this, control, detailLevel); updateJob.setOffset(x, y, z); control.enqueueUpdate(updateJob); }
public void setToHeightmap(byte detailLevel, int x, int y, int z, ref float[,] map, byte[,] mats, VoxelTree control) { if (detailLevel <= CHILD_COUNT_POWER) { for (int xi = 0; xi < CHILD_DIMENSION; ++xi) { for (int zi = 0; zi < CHILD_DIMENSION; ++zi) { for (int yi = 0; yi < CHILD_DIMENSION; ++yi) { if (yi + y >= map[x + xi, z + zi]) break; else if (yi + y >= map[x + xi, z + zi] - 1) { if (mats[x + xi, z + zi] == byte.MaxValue) children[xi, yi, zi] = Voxel.empty; else children[xi, yi, zi] = new Voxel(mats[x + xi, z + zi], (byte)((map[x + xi, z + zi] - yi - y) * byte.MaxValue)); } else { if (mats[x + xi, z + zi] == byte.MaxValue) children[xi, yi, zi] = Voxel.empty; else children[xi, yi, zi] = new Voxel(mats[x + xi, z + zi], byte.MaxValue); } } } } } else { int multiplier = (1 << (detailLevel - CHILD_COUNT_POWER)); for (int xi = 0; xi < CHILD_DIMENSION; ++xi) { for (int zi = 0; zi < CHILD_DIMENSION; ++zi) { int xMax = x + (xi + 1) * multiplier; int zMax = z + (zi + 1) * multiplier; float yMin = float.MaxValue; float yMax = 0; bool multipleMaterials = false; byte material = mats[x, z]; for (int xPos = x + xi * multiplier; xPos < xMax; ++xPos) { for (int zPos = z + zi * multiplier; zPos < zMax; ++zPos) { if (map[xPos, zPos] < yMin) yMin = map[xPos, zPos]; if (map[xPos, zPos] > yMax) yMax = map[xPos, zPos]; if (mats[xPos, zPos] != material) multipleMaterials = true; } } if (multipleMaterials) yMin = 0; int firstUnsolidBlock = Mathf.Min(((int)(yMin - y)) / multiplier, CHILD_DIMENSION); int lastUnsolidBlock = Mathf.Min(((int)(yMax - y)) / multiplier, CHILD_DIMENSION - 1); int yi = 0; for (; yi < firstUnsolidBlock; ++yi) { if (mats[x + xi * multiplier, z + zi * multiplier] == byte.MaxValue) children[xi, yi, zi] = Voxel.empty; else children[xi, yi, zi] = new Voxel(mats[x + xi * multiplier, z + zi * multiplier], byte.MaxValue); } if (lastUnsolidBlock < 0) continue; for (; yi <= lastUnsolidBlock; ++yi) { VoxelBlock newChild = new VoxelBlock(); newChild.setToHeightmap((byte)(detailLevel - CHILD_COUNT_POWER), x + xi * multiplier, y + yi * multiplier, z + zi * multiplier, ref map, mats, control); children[xi, yi, zi] = newChild; } } } } control.dirty = true; }
protected Modifier(VoxelTree control, bool updateMesh) { this.control = control; this.updateMesh = updateMesh; }
public static bool isRenderSize(float size, VoxelTree control) { return control.sizes[control.maxDetail - VoxelRenderer.VOXEL_COUNT_POWER] == size; }
public void set(byte detailLevel, int x, int y, int z, Voxel value, VoxelTree control) { if (detailLevel > 0) { short factor = (short)(1 << (detailLevel - CHILD_COUNT_POWER)); byte xi = (byte)(x / factor); byte yi = (byte)(y / factor); byte zi = (byte)(z / factor); if (detailLevel == CHILD_COUNT_POWER) { children[xi, yi, zi] = value; } else { if (children[xi, yi, zi].GetType() == typeof(Voxel)) { if (children[xi, yi, zi].Equals(value)) { ++skippedSubdivisions; return; } children[xi, yi, zi] = new VoxelBlock((Voxel)children[xi, yi, zi]); } ((VoxelBlock)children[xi, yi, zi]).set((byte)(detailLevel - CHILD_COUNT_POWER), x - xi * factor, y - yi * factor, z - zi * factor, value, control); } } else set(value); }