/// <summary> /// Sets the material of the voxel at the given world position. /// </summary> /// <param name="worldPos"></param> /// <param name="val"></param> public void setMaterialFromWorldPos(Vector3 worldPos, byte val) { worldPos = worldPos - position; Vector3I arrayPos = new Vector3I((int)Math.Round(worldPos.x) / NodeManager.LODSize[LOD], (int)Math.Round(worldPos.y) / NodeManager.LODSize[LOD], (int)Math.Round(worldPos.z) / NodeManager.LODSize[LOD]); if (arrayPos.x < -1 || arrayPos.x > 17 || arrayPos.y < -1 || arrayPos.y > 17 || arrayPos.z < -1 || arrayPos.z > 17) { Debug.Log("Wrong node. " + arrayPos); return; } bool change = (densityChangeData.getMaterial(arrayPos.x, arrayPos.y, arrayPos.z) != val); densityChangeData.setMaterial(arrayPos.x, arrayPos.y, arrayPos.z, val); if (change) { setPermanence(true); hasDensityChangeData = true; MeshFactory.requestSave(this); } }
/// <summary> /// Initializes the Quixel Engine /// </summary> /// <param name="mats">Array of materials.</param> /// <param name="terrainObj">Parent terrain object. (empty)</param> /// <param name="worldName">Name of the world. Used for paging. (empty)</param> public static void init(Material[] mats, GameObject terrainObj, string worldName) { MeshFactory.terrainObj = terrainObj; materials = mats; Debug.Log("Materials: " + mats.Length); DensityPool.init(); MeshFactory.start(); NodeManager.init(worldName); }
/// <summary> /// Regenerates the chunk without threading. /// </summary> public void regenerateChunk() { if (regenReq) { regenFlag = true; } else { MeshFactory.requestMesh(this); regenReq = true; } }
/// <summary> /// Updates the Quixel system. Should be called every step. /// </summary> public static void update() { DensityPool.update(); MeshFactory.update(); if (cameraObj != null) { NodeManager.setViewPosition(cameraObj.transform.position); } if (!Application.isPlaying) { active = false; } }
/// <summary> /// Sets the density of a point, given a world pos. /// </summary> /// <param name="worldPos"></param> public void setDensityFromWorldPos(Vector3 worldPos, float val) { worldPos = worldPos - position; Vector3I arrayPos = new Vector3I((int)(worldPos.x), (int)(worldPos.y), (int)(worldPos.z)); if (arrayPos.x < -1 || arrayPos.x > 17 || arrayPos.y < -1 || arrayPos.y > 17 || arrayPos.z < -1 || arrayPos.z > 17) { Debug.Log("Wrong node. " + arrayPos); return; } densityChangeData.set(arrayPos.x, arrayPos.y, arrayPos.z, val); setPermanence(true); hasDensityChangeData = true; MeshFactory.requestSave(this); }
/// <summary> /// Continuously check if we have chunks to generate. /// </summary> private void generateLoop() { bool sleep = true; while (QuixelEngine.isActive()) { sleep = false; MeshFactory.MeshRequest req = MeshFactory.getNextRequest(); if (req == null) { sleep = true; } else { if (req.densities == null) { if (!req.hasDensities) { req.densities = DensityPool.getDensityData(); } else { req.densities = req.node.densityData; } } MeshFactory.GenerateMeshData(req); lock (finishedQueue) finishedQueue.Enqueue(req); } if (sleep) { Thread.Sleep(30); } else { Thread.Sleep(4); } } }
public Node(Node parent, Vector3 position, int subNodeID, int LOD, RenderType renderType) { densityChangeData = new DensityData(); this.parent = parent; this.position = position; this.subNodeID = subNodeID; this.LOD = LOD; float chunkWidth = (NodeManager.LODSize[LOD] * NodeManager.nodeSize) / 2f; center = new Vector3(position.x + chunkWidth, position.y + chunkWidth, position.z + chunkWidth); setRenderType(renderType); if (parent != null && parent.permanent) { permanent = true; } NodeManager.nodeCount[LOD]++; float nWidth = NodeManager.LODSize[LOD] * NodeManager.nodeSize; chunkPos.x = (int)(center.x / nWidth); chunkPos.y = (int)(center.y / nWidth); chunkPos.z = (int)(center.z / nWidth); if (LOD == 0) { string dir = getDirectory(); if (Directory.Exists(dir) && File.Exists(dir + "\\densities.txt")) { MeshFactory.requestLoad(this); } } regenReq = true; MeshFactory.requestMesh(this); }
/// <summary> /// Sets the density of a point, given a world pos. /// </summary> /// <param name="worldPos"></param> public void setDensityFromWorldPos(Vector3 worldPos, float val) { worldPos = worldPos - position; Vector3I arrayPos = new Vector3I((int)Math.Round(worldPos.x) / NodeManager.LODSize[LOD], (int)Math.Round(worldPos.y) / NodeManager.LODSize[LOD], (int)Math.Round(worldPos.z) / NodeManager.LODSize[LOD]); if (arrayPos.x < -1 || arrayPos.x > 17 || arrayPos.y < -1 || arrayPos.y > 17 || arrayPos.z < -1 || arrayPos.z > 17) { Debug.Log("Wrong node. " + arrayPos + ":" + worldPos + ":" + containsDensityPoint(worldPos).ToString()); return; } densityChangeData.set(arrayPos.x, arrayPos.y, arrayPos.z, val); setPermanence(true); hasDensityChangeData = true; MeshFactory.requestSave(this); }
/// <summary> /// Called when a mesh has been generated /// </summary> /// <param name="mesh">Mesh data</param> public void setMesh(MeshData meshData) { densityData.setChangeData(densityChangeData); regenReq = false; if (regenFlag) { regenFlag = false; regenReq = true; MeshFactory.requestMesh(this); } hasMesh = true; if (meshData.indexArray.Length == 0) { return; } if (chunk == null) { chunk = ChunkPool.getChunk(); if (LOD > 2) { chunk.transform.position = position - new Vector3(0f, (NodeManager.LODSize[LOD] / 2f), 0f); } else { chunk.transform.position = position; } //chunk.GetComponent<MeshFilter>().mesh.subMeshCount = QuixelEngine.materials.Length; chunk.GetComponent <MeshRenderer>().materials = QuixelEngine.materials; } empty = false; Mesh mesh = new Mesh(); mesh.subMeshCount = QuixelEngine.materials.Length; mesh.vertices = meshData.triangleArray; for (int i = 0; i < QuixelEngine.materials.Length; i++) { if (meshData.indexArray[i].Length > 0) { mesh.SetTriangles(meshData.indexArray[i], i); } } //mesh.triangles = meshData.indexArray; mesh.uv = meshData.uvArray; mesh.normals = meshData.normalArray; //mesh.RecalculateBounds(); mesh.Optimize(); chunk.GetComponent <MeshFilter>().mesh = mesh; if (LOD == 0 && collides) { chunk.GetComponent <MeshCollider>().sharedMesh = mesh; } meshData.dispose(); renderCheck(); switch (renderType) { case RenderType.BACK: if (chunk != null) { chunk.layer = 9; } break; case RenderType.FRONT: if (chunk != null) { chunk.layer = 8; } break; } if (parent != null) { parent.renderCheck(); } }
/// <summary> /// Queue a mesh for generation. /// </summary> /// <param name="req"></param> public void queueGenerateMesh(MeshFactory.MeshRequest req) { lock (genQueue) genQueue.Enqueue(req); }