/// <summary> /// Initialize function. Called from VoxelTerrain when a new VTPart gameobject is instantiated /// </summary> /// <param name="v">VoxelTerrain parent</param> /// <param name="i"> Index of this part in x direction </param> /// <param name="j"> Index of this part in y direction </param> /// <param name="k"> Index of this part in z direction </param> public void Init(VoxelTerrain v, int i, int j, int k) { this.v = v; px = i; py = j; pz = k; // Init chunks array _chunks = new VTChunk[nchunk * nchunk * nchunk]; }
private void PaintAtPoint(VoxelTerrain terrain, int x, int y, int z) { if (paintOnlyBlank) { var voxel = terrain.GetVoxel(x, y, z); if (voxel.MeshShape != Voxel.MeshShapeType.None) { return; } } if (!paintBlockType && paintShape) { var currentVoxel = terrain.GetVoxel(x, y, z); if (currentVoxel.MeshShape != Voxel.MeshShapeType.None) { terrain.SetVoxel(x, y, z, currentVoxel.ChangeShape(selectedMeshShape, selectedRotation, selectedUpsideDown)); } } else if (paintBlockType && !paintShape) { var currentVoxel = terrain.GetVoxel(x, y, z); if (currentVoxel.MeshShape != Voxel.MeshShapeType.None) { terrain.SetVoxel(x, y, z, currentVoxel.ChangeBlockType(selectedBlockType)); } } else { terrain.SetVoxel(x, y, z, new Voxel(selectedMeshShape, selectedRotation, selectedUpsideDown, selectedBlockType)); } }
public override void OnInspectorGUI() { v = target as VoxelTerrain; DrawDefaultInspector(); v.blockSize = Mathf.NextPowerOfTwo((int)v.blockSize); v.size = Mathf.RoundToInt(v.size / v.npart / v.blockSize) * v.blockSize * v.npart; EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Init")) { v.Init(); List <Material> mat = new List <Material>(); foreach (string f in System.IO.Directory.GetFiles(Application.dataPath + "/Materials/VT", "*.mat")) { mat.Add(AssetDatabase.LoadAssetAtPath(f.Substring(f.IndexOf("Assets")), typeof(Material)) as Material); } v.mat = mat[Random.Range(0, mat.Count)]; } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("Make Part")) { Undo.RegisterSceneUndo("Make VT"); long t0 = System.DateTime.Now.Ticks / System.TimeSpan.TicksPerMillisecond; MakePart(v.edx, v.edy, v.edz); last = (System.DateTime.Now.Ticks / System.TimeSpan.TicksPerMillisecond - t0) / 1000; } EditorGUILayout.LabelField("Time taken in last Make operation:" + last); EditorStyles.label.wordWrap = true; EditorGUILayout.LabelField("Use the arrow keys, keypad 8 and keypad 2 to select a part of the Voxel Terrain. Once selected, it will" + "be highlighted. Then click on 'Make Part' to generate terrain in that region."); }
/// <summary> /// Load a chunk into the terrain object. /// </summary> /// <param name="terrain">The terrain.</param> /// <param name="chunkIndex">The chunk index.</param> /// <returns>The chunk.</returns> public Chunk LoadChunk(VoxelTerrain terrain, Position chunkIndex) { // Deserialize or generate the chunk Chunk chunk; if (!this.serializer.TryDeserialiseChunk(chunkIndex, out chunk)) { // Get the surface heights of the chunk float[] surfaceHeights; if (!terrain.SurfaceHeights.TryGetValue(chunkIndex.X, out surfaceHeights)) { surfaceHeights = this.voxelGenerator.GenerateSurfaceHeights(chunkIndex.X); terrain.SurfaceHeights.Add(chunkIndex.X, surfaceHeights); } // The chunk doesn't yet exist, so generate a new one chunk = new Chunk(); this.voxelGenerator.Generate(chunk.Voxels, surfaceHeights, chunkIndex); // Serialize the generated chunk this.serializer.SerialiseChunk(chunk, chunkIndex); } // Add the chunk to the terrain object terrain.Chunks.Add(chunkIndex, chunk); return chunk; }
private void InitForTerrain(VoxelTerrain terrain) { if (terrain == null) { m_initTerrain = null; return; } if (terrain.readable == null) { return; } if (terrain.writeable == null) { return; } m_initTerrain = terrain; if (terrain == null) { return; } m_rectBrush = new RectBrush(terrain.voxelSize, terrain.readable.min, terrain.readable.max, terrain.readable.Sample, terrain.SetValue); m_rectBrush.width = 1.0f; m_rectBrush.height = 1.0f; m_circleBrush = new CircleBrush(terrain.voxelSize, terrain.readable.min, terrain.readable.max, terrain.readable.Sample, terrain.SetValue); m_circleBrush.radius = 0.5f; }
private void OnValidate() { if (terrain == null) { terrain = GetComponent <VoxelTerrain>(); } terrain.UpdateMesh(); }
void OnSceneGUI() { v = target as VoxelTerrain; if (!v.initialized) { return; } VTPart part = v.getPart(v.edx, v.edy, v.edz); Event e = Event.current; if (e.type == EventType.keyDown) { if (e.control) { if (e.keyCode == KeyCode.RightArrow) { v.edx++; } if (e.keyCode == KeyCode.LeftArrow) { v.edx--; } if (e.keyCode == KeyCode.UpArrow) { v.edz++; } if (e.keyCode == KeyCode.DownArrow) { v.edz--; } if (e.keyCode == KeyCode.Keypad8) { v.edy++; } if (e.keyCode == KeyCode.Keypad2) { v.edy--; } v.edx = Mathf.Clamp(v.edx, 0, v.npart - 1); v.edy = Mathf.Clamp(v.edy, 0, v.npart - 1); v.edz = Mathf.Clamp(v.edz, 0, v.npart - 1); Vector3 cp = Camera.current.transform.position; v.LoadMeshes(cp); } } Vector3 p = new Vector3(v.edx + 0.5f, v.edy + 0.5f, v.edz + 0.5f) * v.partSize; partCube.transform.position = p; partCube.transform.localScale = v.partSize * Vector3.one; /* * int l=v.getPart (v.edx,v.edy,v.edz).getLOD (Camera.current.transform.position); * Handles.BeginGUI (); * GUI.Label(new Rect(10,10,100,100),"LOD: "+l); * Handles.EndGUI (); */ }
void Start() { _previousLocation = null; _parentTerrain = GetComponent <VoxelTerrain>(); if (_parentTerrain == null) { throw new System.Exception("VoxelTerrain component not found!"); } }
void CreatePlanes(VoxelTerrain terrain) { if (createPlane) { var normal = planeNormals[alignment]; plane = new Plane(normal, tileCursorPosition); createPlane = false; } }
void Start() { player = GameObject.FindGameObjectWithTag("Player").transform; v = GameObject.FindObjectOfType(typeof(VoxelTerrain)) as VoxelTerrain; Vector3 cp = Camera.main.transform.position; v.LoadMeshes(cp); }
public static void Save(VoxelTerrain terrain, string path) { using (var output = new System.IO.StreamWriter(LevelPath(path), false, System.Text.Encoding.UTF8)) { output.WriteLine("# Level terrain data for {0}", path); output.WriteLine("# X, Y, Z, MeshShape, Rotation, IsUpsideDown, BlockType"); foreach (var chunk in terrain.Chunks.Values) { SaveChunk(chunk, output); } } }
void OnEnable() { v = target as VoxelTerrain; if (v.transform.FindChild("partCube") == null) { partCube = GameObject.CreatePrimitive(PrimitiveType.Cube); partCube.transform.parent = v.transform; partCube.name = "partCube"; partCube.renderer.sharedMaterial = AssetDatabase.LoadAssetAtPath("Assets/Materials/Highlight.mat", typeof(Material)) as Material; } partCube = v.transform.FindChild("partCube").gameObject; partCube.SetActive(true); }
public VoxelTerrain GetParentTerrain() { if (_parentTerrain != null) { return(_parentTerrain); } if (transform.parent != null) { _parentTerrain = transform.parent.GetComponent <VoxelTerrain>(); } return(_parentTerrain); }
public static void Load(VoxelTerrain terrain) { foreach (var file in Directory.GetFiles(LevelPath(terrain.LevelName), "*.chunk")) { Debug.Log("Related files: " + file); Vector3 chunkPosition; if (!ChunkSerializer.GetChunkPosition(file, out chunkPosition)) { return; } var chunk = terrain.GetChunk((int)chunkPosition.x, (int)chunkPosition.y, (int)chunkPosition.z); ChunkSerializer.Deserialize(chunk, file); } }
public static void Save(VoxelTerrain terrain, bool onlyDirty) { var baseFolder = LevelPath(terrain.LevelName); Directory.CreateDirectory(baseFolder); foreach (var chunk in terrain.Chunks.Values) { if (onlyDirty && !chunk.IsDataDirty) { continue; } var pos = chunk.ChunkPosition; var filename = Path.Combine(baseFolder, string.Format("{0}.{1}.{2}.chunk", pos.x, pos.y, pos.z)); Debug.Log("Saving chunk: " + filename); ChunkSerializer.Serialize(chunk, filename); chunk.IsDataDirty = false; } }
public static void Load(VoxelTerrain terrain, string path) { foreach (var line in System.IO.File.ReadAllLines(LevelPath(path))) { if (line.Length == 0 || line[0] == '#') { continue; } var split = line.Split(','); var x = int.Parse(split[0]); var y = int.Parse(split[1]); var z = int.Parse(split[2]); var meshShape = ParseMeshShape(split[3]); var rotation = ParseRotation(split[4]); var isUpsideDown = split[5] == "true"; var blockType = ushort.Parse(split[6]); terrain.SetVoxel(x, y, z, new Voxel(meshShape, rotation, isUpsideDown, blockType)); } }
/// <summary> /// Creates voxel terrain object /// </summary> public static VoxelTerrain New(int Y) { GameObject obj = new GameObject("Layer " + Y); obj.isStatic = true; obj.transform.position = new Vector3(0, VoxelChunk.ChunkHeight * Y, 0) * WorldManager.VoxelToUnitScale; VoxelTerrain terrain = obj.AddComponent <VoxelTerrain>(); terrain.Y = Y; terrain.mTerrainGenerator = new TerrainGen_Overworld(123); // Create chunk pool for (int i = 0; i < 30; ++i) { terrain.mChunkPool.Enqueue(VoxelChunk.NewPoolObj(terrain)); } return(terrain); }
void Start() { if (Main == null) { Main = this; Debug.Log("World Manager created."); // Make sure library is initialized ResourceLoader.AttemptImport(); mWorker = GetComponent <WorldWorker>(); mCurrentTerrain = VoxelTerrain.New(-1); Entity_Player player = Resources.Load <Entity_Player>("Entities/Human/Player/Player Prefab"); Instantiate(player.gameObject); } else { Debug.LogError("Cannot have multiple world managers active at once."); Destroy(gameObject); } }
public override void OnInspectorGUI() { DrawDefaultInspector(); m_Terrain = (VoxelTerrain)target; EditorGUILayout.BeginHorizontal(); if (GUILayout.Button("Generate")) { m_Terrain.Generate(); m_Terrain.Reset(); } if (GUILayout.Button("Delete")) { m_Terrain.Eliminate(); m_Terrain.Reset(); } EditorGUILayout.EndHorizontal(); }
public FirstPersonCameraSimulator() { info = TW.Data.GetSingleton <CameraInfo>(); cam = new SpectaterCamera(); terrain = TW.Data.GetSingleton <VoxelTerrain>(); camData = TW.Data.GetSingleton <FirstPersonCamera>(); cam.CameraPosition = camData.Position; camData.LookDir -= Vector3.UnitX * camData.LookDir.X * 2; cam.CameraDirection = camData.LookDir; cam.UpdateCameraInfo(); cam.AngleHorizontal = cam.AngleHorizontal; points = new List <Vector3>(); points.Add(Vector3.UnitX * 0.5f); points.Add(Vector3.UnitY * 0.5f); points.Add(Vector3.UnitZ * 0.5f); points.Add(-Vector3.UnitX * 0.5f); points.Add(-Vector3.UnitY * 0.5f); points.Add(-Vector3.UnitY * 1.5f); points.Add(-Vector3.UnitZ * 0.5f); }
public TerrainAStar() { terrain = TW.Data.GetSingleton <VoxelTerrain>(); }
void Awake() { m_terrain = GetComponent <VoxelTerrain>(); }
public static void ReduceMesh(Chunk chunk, MeshData meshData) { if (chunk.IsEmpty()) { return; } List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); int size = Chunk.CHUNK_SIZE; // Sweep over 3-axes for (int d = 0; d < 3; d++) { int i, j, k, l, w, h, u = (d + 1) % 3, v = (d + 2) % 3; int[] x = new int[3]; int[] q = new int[3]; int[] mask = new int[(size + 1) * (size + 1)]; q[d] = 1; for (x[d] = -1; x[d] < size;) { // Compute the mask int n = 0; for (x[v] = 0; x[v] < size; ++x[v]) { for (x[u] = 0; x[u] < size; ++x[u], ++n) { int a = 0; if (0 <= x[d]) { a = (int)VoxelTerrain.GetBlock(chunk, x[0], x[1], x[2]).type; } int b = 0; if (x[d] < size - 1) { b = (int)VoxelTerrain.GetBlock(chunk, x[0] + q[0], x[1] + q[1], x[2] + q[2]).type; } if (a != -1 && b != -1 && a == b) { mask[n] = 0; } else if (a > 0) { a = 1; mask[n] = a; } else { b = 1; mask[n] = -b; } } } // Increment x[d] ++x[d]; // Generate mesh for mask using lexicographic ordering n = 0; for (j = 0; j < size; ++j) { for (i = 0; i < size;) { var c = mask[n]; if (c > -3) { // Compute width for (w = 1; c == mask[n + w] && i + w < size; ++w) { } // Compute height bool done = false; for (h = 1; j + h < size; ++h) { for (k = 0; k < w; ++k) { if (c != mask[n + k + h * size]) { done = true; break; } } if (done) { break; } } // Add quad bool flip = false; x[u] = i; x[v] = j; int[] du = new int[3]; int[] dv = new int[3]; if (c > -1) { du[u] = w; dv[v] = h; } else { flip = true; c = -c; du[u] = w; dv[v] = h; } Vector3 v1 = new Vector3(x[0], x[1], x[2]); Vector3 v2 = new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]); Vector3 v3 = new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]); Vector3 v4 = new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]); if (c > 0 && !flip) { AddFace(v1, v2, v3, v4, vertices, triangles, 0); } if (flip) { AddFace(v4, v3, v2, v1, vertices, triangles, 0); } // Zero-out mask for (l = 0; l < h; ++l) { for (k = 0; k < w; ++k) { mask[n + k + l * size] = 0; } } // Increment counters and continue i += w; n += w; } else { ++i; ++n; } } } } } meshData.ColliderVertices = vertices; meshData.ColliderTriangles = triangles; }
/// <summary> /// Create a new object to be using in object pool for a terrain /// </summary> public static VoxelChunk NewPoolObj(VoxelTerrain Terrain) { // Create inactive game object GameObject obj = new GameObject(); obj.isStatic = true; obj.transform.parent = Terrain.transform; obj.layer = LayerMask.NameToLayer("Terrain"); // Add (Initialize) component VoxelChunk chunk = obj.AddComponent <VoxelChunk>(); chunk.mTerrain = Terrain; // Init data chunk.mVoxelData = new VoxelInstance[ChunkWidth, ChunkHeight, ChunkWidth]; // Fill with air ushort air = VoxelLibrary.GetID("air"); for (int x = 0; x < ChunkWidth; ++x) { for (int y = 0; y < ChunkHeight; ++y) { for (int z = 0; z < ChunkWidth; ++z) { chunk.mVoxelData[x, y, z] = new VoxelInstance(air); } } } // Setup rendering { GameObject subObj = new GameObject("Terrain"); subObj.isStatic = true; subObj.transform.parent = obj.transform; chunk.mMeshTerrainFilter = subObj.AddComponent <MeshFilter>(); MeshRenderer renderer = subObj.AddComponent <MeshRenderer>(); renderer.sharedMaterial = VoxelLibrary.mTerrainMaterial; renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; { Mesh mesh = new Mesh(); mesh.name = "Terrain Mesh"; mesh.MarkDynamic(); chunk.mMeshTerrainFilter.sharedMesh = mesh; } } { GameObject subObj = new GameObject("Liquid"); subObj.isStatic = true; subObj.transform.parent = obj.transform; chunk.mMeshLiquidFilter = subObj.AddComponent <MeshFilter>(); MeshRenderer renderer = subObj.AddComponent <MeshRenderer>(); renderer.sharedMaterial = VoxelLibrary.mLiquidMaterial; renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; { Mesh mesh = new Mesh(); mesh.name = "Liquid Mesh"; mesh.MarkDynamic(); chunk.mMeshLiquidFilter.sharedMesh = mesh; } } // Setup collision chunk.mMeshCollider = obj.AddComponent <MeshCollider>(); chunk.mMeshCollider.sharedMaterial = Resources.Load <PhysicMaterial>("World/Phys_Terrain"); { Mesh mesh = new Mesh(); mesh.name = "Physics Mesh"; mesh.MarkDynamic(); chunk.mMeshCollider.sharedMesh = mesh; } // Flag as inactive obj.name = "Chunk (Inactive)"; obj.transform.position = Vector3.zero; obj.SetActive(false); return(chunk); }
private void SaveAllDataDirty(VoxelTerrain terrain) { VoxelLoader.Save(terrain, true); }
void OnEnable() { _target = (VoxelTerrain)target; }
/// <summary> /// Initialises a new instance of the MarchingCubesGenerator class. /// </summary> /// <param name="terrain">The terrain.</param> /// <param name="isoLevel">The isolevel, which is the density at which the mesh surface lies.</param> public MarchingCubesGenerator(VoxelTerrain terrain, byte isoLevel) : base(terrain) { this.IsoLevel = isoLevel; }
/// <summary> /// Unload a chunk from the terrain object. /// </summary> /// <param name="terrain">The terrain.</param> /// <param name="chunkIndex">The chunk index.</param> /// <returns>The chunk that was unloaded; Null if the chunk was never loaded.</returns> public Chunk UnloadChunk(VoxelTerrain terrain, Position chunkIndex) { // Get the chunk Chunk chunk; if (!terrain.Chunks.TryGetValue(chunkIndex, out chunk)) { // The chunk isn't loaded so do nothing return null; } // Serialize the chunk this.serializer.SerialiseChunk(chunk, chunkIndex); // Remove the chunk from the Terrain object terrain.Chunks.Remove(chunkIndex); return chunk; }
public IEnumerator GenerateMesh(VoxelTerrain voxelTerrain) { MeshFilter meshFilter = GetComponent <MeshFilter>(); PolygonCollider2D polygonCollider = GetComponent <PolygonCollider2D>(); // Mesh info List <Vector3> points = new List <Vector3>(); List <int> indices = new List <int>(); Vector3 offsetPoint = Vector3.zero; int indexOffset = 0; // Track which voxel configurations have edges //Dictionary<Vector2Int, int> edgePoints = new Dictionary<Vector2Int, int>(); // Remember the configuration(lookup) for each voxel square int[,] lookupGrid = new int[Size, Size]; float[,] expandedTerrain = new float[Size, Size]; int[,] chunkEdgeLookup = new int[Size, Size]; for (int y = 0; y < Size; y++) { for (int x = 0; x < Size; x++) { int lookup = 0; if (x < Size - 1 && y < Size - 1) { for (int offset = 0; offset < 4; offset++) { var o = offsets[offset]; var v = Terrain[x + o.x, y + o.y]; expandedTerrain[x, y] = v; lookup += v > 0f ? (1 << offset) : 0; } } else { for (int offset = 0; offset < 4; offset++) { var o = offsets[offset]; var v = voxelTerrain.GetVoxel( ChunkCoord.x * Size + x + o.x, ChunkCoord.y * Size + y + o.y ); expandedTerrain[x, y] = v; lookup += v > 0f ? (1 << offset) : 0; } } lookupGrid[x, y] = lookup; int chunkEdge = ChunkEdgeIndex(x, y); chunkEdgeLookup[x, y] = chunkEdge; if (lookup > 0 && lookup < 15 || chunkEdge != 0) { edgePoints.Add(new Vector2Int(x, y), chunkEdge == 0 && (lookup == 5 || lookup == 10) ? 2 : 1); } } } for (int y = 0; y < Size; y++) { for (int x = 0; x < Size; x++) { offsetPoint.x = x; offsetPoint.y = y; int lookup = lookupGrid[x, y]; int chunkEdge = chunkEdgeLookup[x, y]; // Add points int tempIndexOffset = 0; for (int i = 0; i < 6; i++) { int p = pointLookup[lookup, i]; if (p < 0) { break; } points.Add(basePoints[p] + offsetPoint); tempIndexOffset++; } // Add indices for (int i = 0; i < 12; i++) { int index = indexLookup[lookup, i]; if (index < 0) { break; } indices.Add(index + indexOffset); } indexOffset += tempIndexOffset; } } var mesh = meshFilter.mesh; mesh.Clear(); mesh.vertices = points.ToArray(); mesh.triangles = indices.ToArray(); mesh.RecalculateNormals(); mesh.RecalculateBounds(); // Calculate polygon collider polygonCollider.pathCount = 0; while (edgePoints.Any()) { // List<Vector2> pathPoints = new List<Vector2>(); // Starting at the first point in the queue var point = edgePoints.Keys.First(); var startingPoint = point; int lookup = lookupGrid[point.x, point.y]; int nextConnection = -1; edgePoints[point] = edgePoints[point] - 1; if (edgePoints[point] <= 0) { edgePoints.Remove(point); } // Find the first valid edge for the point for (int i = 0; i < 4; i++) { int chunkEdge = ChunkEdgeIndex(point.x, point.y); int connection = edgeConnections[chunkEdge, lookup, i]; // Valid connection that leads to another edge if (connection >= 0 && edgePoints.ContainsKey(point + edgeOffset[connection])) { pathPoints.Add(basePoints[i + 4] + (Vector3Int)point); var extraPoints = extraEdgePoint[chunkEdge][lookup]; for (int e = 0; e < extraPoints.Length; e++) { pathPoints.Add(basePoints[extraPoints[e]] + (Vector3Int)point); } nextConnection = connection; break; } } // If no valid connection, ignore this point if (nextConnection == -1) { continue; } point += edgeOffset[nextConnection]; // Keep following the edges that are connected to our starting point // until we reach our starting again while (point != startingPoint) { int chunkEdge = ChunkEdgeIndex(point.x, point.y); edgePoints[point] = edgePoints[point] - 1; if (edgePoints[point] <= 0) { edgePoints.Remove(point); } // The 'up' edge from the voxel below us is our 'down' edge. Same with left/right, etc. // This is a nice trick to do this conversion int incomingEdge = 3 - nextConnection; // Add 4 to get the cardinal points instead of diagonals pathPoints.Add(basePoints[incomingEdge + 4] + (Vector3Int)point); var extraPoints = extraEdgePoint[chunkEdge][lookup]; for (int e = 0; e < extraPoints.Length; e++) { pathPoints.Add(basePoints[extraPoints[e]] + (Vector3Int)point); } yield return(new WaitForSeconds(0.1f)); lookup = lookupGrid[point.x, point.y]; nextConnection = edgeConnections[chunkEdge, lookup, incomingEdge]; var nextPoint = point + edgeOffset[nextConnection]; point = nextPoint; } polygonCollider.SetPath(polygonCollider.pathCount++, pathPoints); pathPoints.Clear(); } }