static void BuildRock(ref FastNoise_t noise, int x, int y, int z, PinnedChunkData_t chunk) { int xMinus = x - y % 3; int xPlus = x + (x + y + z) % 3; int yMinus = y - x % 3; int yPlus = y + (y + z) % 3; int zMinus = z - (z + x) % 3; int zPlus = z + (x + y) % 3; for (int i = xMinus; i < xPlus; i++) { for (int j = yMinus; j < yPlus; j++) { for (int k = zMinus; k < zPlus; k++) { if (i >= 0 && i < VOXEL_CHUNK_SIZE_XZ && j >= 0 && j < VOXEL_CHUNK_SIZE_Y && k >= 0 && k < VOXEL_CHUNK_SIZE_XZ) { var ofs = i + (k * VOXEL_CHUNK_SIZE_XZ) + (j * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Rock.WithFlags(EVoxelBlockFlags.FullVoxel); } } } } }
public JobHandle ScheduleChunkGenerationJob(WorldChunkPos_t cpos, PinnedChunkData_t chunk) { return(new ProcWorldStreaming_V1_Job_t() { cpos = cpos, chunk = chunk }.Schedule()); }
public void Execute() { chunk = GenerateVoxels(cpos, chunk); unsafe { chunk.pinnedDecorationCount[0] = chunk.decorationCount; chunk.pinnedFlags[0] = chunk.flags; } }
static PinnedChunkData_t GenerateVoxelsSinWave(WorldChunkPos_t cpos, PinnedChunkData_t chunk) { var Y_OFS = (VOXEL_CHUNK_SIZE_Y * MaxVoxelChunkLine(VOXEL_CHUNK_VIS_MAX_Y)) / 8; bool solid = false; bool air = false; chunk.flags = EChunkFlags.LAYER_DEFAULT; WorldVoxelPos_t pos = ChunkToWorld(cpos); Vector3 v3 = WorldToVec3(pos); for (int x = 0; x < VOXEL_CHUNK_SIZE_XZ; ++x) { for (int z = 0; z < VOXEL_CHUNK_SIZE_XZ; ++z) { var cs = Mathf.Cos((v3.x + x) / 64); var ss = Mathf.Sin((v3.z + z) / 64); for (int y = 0; y < VOXEL_CHUNK_SIZE_Y; ++y) { var ofs = x + (z * VOXEL_CHUNK_SIZE_XZ) + (y * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); var ypos = v3.y + y; if (ypos < ((cs + ss) * (Y_OFS / 2))) { chunk.voxeldata[ofs] = EVoxelBlockType.Dirt; solid = true; } else { air = true; chunk.voxeldata[ofs] = EVoxelBlockType.Air; } } } } if (solid) { chunk.flags |= EChunkFlags.SOLID; } if (air) { chunk.flags |= EChunkFlags.AIR; } chunk.flags |= EChunkFlags.LAYER_DEFAULT; return(chunk); }
static unsafe bool IsSolidXZPlane(PinnedChunkData_t chunk) { byte *solidFlags = stackalloc byte[VOXELS_PER_CHUNK_XZ]; for (int i = 0; i < VOXELS_PER_CHUNK_XZ; ++i) { solidFlags[i] = 0; } int numSolid = 0; int ofs = 0; for (int y = 0; y < VOXEL_CHUNK_SIZE_Y; ++y) { for (int z = 0; z < VOXEL_CHUNK_SIZE_XZ; ++z) { int ofsxz = z * VOXEL_CHUNK_SIZE_XZ; for (int x = 0; x < VOXEL_CHUNK_SIZE_XZ; ++x) { if (solidFlags[ofsxz] == 0) { var block = chunk.voxeldata[ofs].type; if (block != EVoxelBlockType.Air) { solidFlags[ofsxz] = 1; ++numSolid; if (numSolid == VOXELS_PER_CHUNK_XZ) { return(true); } } } ++ofsxz; ++ofs; } } } return(false); }
protected override JobHandle CreateGenVoxelsJob(WorldChunkPos_t pos, PinnedChunkData_t chunk) { return(_gameMode.worldStreaming.ScheduleChunkGenerationJob(pos, chunk)); }
static PinnedChunkData_t GenerateVoxels(WorldChunkPos_t cpos, PinnedChunkData_t chunk) { FastNoise_t noise = FastNoise_t.New(); chunk.flags = EChunkFlags.ALL_LAYERS_FLAGS; bool solid = false; bool air = true; bool fullVoxel = false; var wpos = ChunkToWorld(cpos); var v3 = WorldToVec3(wpos); for (int x = 0; x < VOXEL_CHUNK_SIZE_XZ; ++x) { for (int z = 0; z < VOXEL_CHUNK_SIZE_XZ; ++z) { var xpos = (int)v3.x + x; var zpos = (int)v3.z + z; bool isEmptyAtBottom = false; var lowerGroundHeight = GetLowerGroundHeight(ref noise, xpos, zpos); var upperGroundHeight = GetUpperGroundHeight(ref noise, xpos, zpos, lowerGroundHeight); float waterDepth = CalculateRiver(ref noise, xpos, zpos, lowerGroundHeight, 0, 0, ref upperGroundHeight); bool isRoad = CalculateRoad(ref noise, xpos, zpos, lowerGroundHeight, 0, 0, ref upperGroundHeight); for (int y = 0; y < VOXEL_CHUNK_SIZE_Y; ++y) { var ofs = x + (z * VOXEL_CHUNK_SIZE_XZ) + (y * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); var ypos = v3.y + y; EVoxelBlockType bt; bool isCave = false; if (ypos > lowerGroundHeight && ypos <= upperGroundHeight) { // Let's see about some caves er valleys! float caveNoise = GetPerlinValue(ref noise, xpos, ypos, zpos, 0.001f) * (0.015f * ypos) + 0.1f; caveNoise += GetPerlinValue(ref noise, xpos, ypos, zpos, 0.01f) * 0.06f + 0.1f; caveNoise += GetPerlinValue(ref noise, xpos, ypos, zpos, 0.02f) * 0.02f + 0.01f; isCave = caveNoise > GetPerlinNormal(ref noise, xpos, ypos, zpos, 0.01f) * 0.3f + 0.4f; } if (ypos <= upperGroundHeight && !isCave) { bt = GetBlockType(ref noise, xpos, (int)ypos, zpos, (int)upperGroundHeight, isRoad, false, out fullVoxel); } else { if (ypos < waterLevel) { float temperature = GetTemperature(ref noise, (int)xpos, (int)ypos, zpos); if (IsFrozen(temperature, GetHumidity(ref noise, xpos, zpos))) { bt = EVoxelBlockType.Ice; } else { bt = EVoxelBlockType.Water; } } else { bt = EVoxelBlockType.Air; } } if (bt == EVoxelBlockType.Air) { if (y == 0) { isEmptyAtBottom = true; } if (waterDepth > 0 && !isEmptyAtBottom) { float temperature = GetTemperature(ref noise, xpos, (int)ypos, zpos); if (IsFrozen(temperature, GetHumidity(ref noise, xpos, zpos))) { bt = EVoxelBlockType.Ice; } else { bt = EVoxelBlockType.Water; } waterDepth--; solid = true; } else { air = true; } } else { solid = true; } if (fullVoxel) { chunk.voxeldata[ofs] = bt.WithFlags(EVoxelBlockFlags.FullVoxel); } else { chunk.voxeldata[ofs] = bt; } } } } if (solid) { chunk.flags |= EChunkFlags.SOLID; } if (air) { chunk.flags |= EChunkFlags.AIR; } if (solid && air) { for (int x = 0; x < VOXEL_CHUNK_SIZE_XZ; ++x) { for (int z = 0; z < VOXEL_CHUNK_SIZE_XZ; ++z) { var xpos = (int)v3.x + x; var zpos = (int)v3.z + z; for (int y = VOXEL_CHUNK_SIZE_Y - 1; y >= 0; --y) { var ofs = x + (z * VOXEL_CHUNK_SIZE_XZ) + (y * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); var ypos = (int)v3.y + y; var bt = chunk.voxeldata[ofs].type; if (bt != EVoxelBlockType.Air) { if (bt == EVoxelBlockType.Water || bt == EVoxelBlockType.Leaves || bt == EVoxelBlockType.Needles || bt == EVoxelBlockType.Wood) { break; } float rock = GetRock(ref noise, xpos, ypos, zpos); float rockCutoff = 0.35f; if (rock > rockCutoff) { float rockLimit = (1.0f - Mathf.Pow((rock - rockCutoff) / (1.0f - rockCutoff), 0.5f)) * 100 + 1; if (GetWhiteNoise(ref noise, xpos, ypos, zpos) < 1.0f / rockLimit) { BuildRock(ref noise, x, y, z, chunk); } } if (bt == EVoxelBlockType.Ice || bt == EVoxelBlockType.Sand) { break; } float humidity = GetHumidity(ref noise, xpos, zpos); float forestPower = (1.0f - (GetPerlinNormal(ref noise, xpos, zpos, NoiseFloatScale._01) * GetPerlinNormal(ref noise, xpos + 64325, zpos + 6543, NoiseFloatScale._005))) * Mathf.Pow(humidity, 2) * (1.0f - Mathf.Pow(rock, 4)); float cutoff = 0.05f; if (forestPower > cutoff) { float forestLimit = Mathf.Pow(1.0f - (forestPower - cutoff) / (1.0f - cutoff), 8) * 100 + 4; if (GetWhiteNoise(ref noise, xpos, ypos, zpos) < 1.0f / forestLimit) { float temperature = GetTemperature(ref noise, xpos, ypos, zpos); int treeType; // dead if (humidity + temperature / 100.0f + GetPerlinNormal(ref noise, xpos, zpos, NoiseFloatScale._1) * 1.5f < 1.5f) { if (temperature + 30 * GetPerlinNormal(ref noise, xpos + 422, zpos + 5357, NoiseFloatScale._1) > 60) { treeType = 3; } else { treeType = 2; // pine } } else if (IsFrozen(temperature, humidity)) { treeType = 0; } else { treeType = 1; } BuildTree(ref noise, x, y, z, treeType, chunk); break; } } if (bt == EVoxelBlockType.Grass || bt == EVoxelBlockType.Dirt) { if (y < VOXEL_CHUNK_SIZE_Y - 1) { float flowerPower1 = 0.3f * GetPerlinNormal(ref noise, xpos, zpos, NoiseFloatScale._5) + 0.2f * GetPerlinNormal(ref noise, xpos + 67435, zpos + 653, NoiseFloatScale._01) + 0.5f * GetPerlinNormal(ref noise, xpos + 6435, zpos + 65453, NoiseFloatScale._005); float flowerPower2 = 0.4f * GetPerlinNormal(ref noise, xpos + 256, zpos + 54764, NoiseFloatScale._5) + 0.3f * GetPerlinNormal(ref noise, xpos + 6746435, zpos + 63, NoiseFloatScale._01) + 0.3f * GetPerlinNormal(ref noise, xpos + 649835, zpos + 6543, NoiseFloatScale._005); float flowerPower3 = 0.2f * GetPerlinNormal(ref noise, xpos + 7657376, zpos + 5421, NoiseFloatScale._5) + 0.3f * GetPerlinNormal(ref noise, xpos + 67435, zpos + 658963, NoiseFloatScale._01) + 0.5f * GetPerlinNormal(ref noise, xpos + 64935, zpos + 695453, NoiseFloatScale._005); float flowerPower4 = 0.3f * GetPerlinNormal(ref noise, xpos + 15, zpos + 6532, NoiseFloatScale._5) + 0.1f * GetPerlinNormal(ref noise, xpos + 6735, zpos + 63, NoiseFloatScale._01) + 0.6f * GetPerlinNormal(ref noise, xpos + 645, zpos + 6553, NoiseFloatScale._005); cutoff = 0.75f; int flowerType = 0; float flowerPower = 0; if (flowerPower1 > flowerPower) { flowerPower = flowerPower1; flowerType = 0; } if (flowerPower2 > flowerPower) { flowerPower = flowerPower2; flowerType = 1; } if (flowerPower3 > flowerPower) { flowerPower = flowerPower3; flowerType = 2; } if (flowerPower4 > flowerPower) { flowerPower = flowerPower4; flowerType = 3; } if (flowerPower > cutoff) { var ofs2 = x + (z * VOXEL_CHUNK_SIZE_XZ) + ((y + 1) * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.voxeldata[ofs2] = (EVoxelBlockType)((int)EVoxelBlockType.Flowers1 + flowerType); } } } //else if (blockType == BlockType.Grass && r.Next((int)(1000 * forestPower) + 10) == 0) //{ // chunk.setBlock(x, (byte)y, z, new Block(BlockType.RedFlower)); //} //else if (blockType == BlockType.Grass && r.Next((int)(50 * forestPower) + 1) == 1) //{ // chunk.setBlock(x, (byte)y, z, new Block(BlockType.LongGrass)); //} break; } } } } if (noise.GetWhiteNoise(cpos.cx, cpos.cy, cpos.cz) > 0.98f) { ConstructTower(16, 0, 16, chunk); } } return(chunk); }
static void BuildTree(ref FastNoise_t noise, int x, int y, int z, int treeType, PinnedChunkData_t chunk) { // Foliage if (treeType == 0) { // Trunk int height = 1 + x % 4 + y % 4 + z % 4; for (int i = y; i < y + height && i < VOXEL_CHUNK_SIZE_Y; i++) { var ofs = x + (z * VOXEL_CHUNK_SIZE_XZ) + (i * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Wood; } } else if (treeType == 1) { // Trunk int height = 2 + x % 3 + y % 3 + z % 3; for (int i = y; i < y + height && i < VOXEL_CHUNK_SIZE_Y; i++) { var ofs = x + (z * VOXEL_CHUNK_SIZE_XZ) + (i * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Wood; } int radius = x % 2 + y % 2 + z % 2; if (radius > 0) { for (int i = -radius; i <= radius; i++) { for (int j = -radius; j <= radius; j++) { for (int k = -radius; k <= radius; k++) { int lx = x + i; int lz = z + j; int ly = y + k + height; if (lx >= 0 && lx < VOXEL_CHUNK_SIZE_XZ && ly >= 0 && ly < VOXEL_CHUNK_SIZE_Y && lz >= 0 && lz < VOXEL_CHUNK_SIZE_XZ) { var ofs = lx + (lz * VOXEL_CHUNK_SIZE_XZ) + (ly * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Leaves.WithFlags(EVoxelBlockFlags.FullVoxel); } } } } } } else if (treeType == 2) { int height = 3 + x % 2 + y % 2 + z % 2; for (int i = y; i < y + height && i < VOXEL_CHUNK_SIZE_Y; i++) { var ofs = x + (z * VOXEL_CHUNK_SIZE_XZ) + (i * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Wood; } int radius = 1 + x % 2 + y % 2 + z % 2; if (radius > 0) { for (int k = -radius; k <= radius * 2; k++) { int r = radius - (k + radius) / 3; for (int i = -r; i <= r; i++) { for (int j = -r; j <= r; j++) { int lx = x + i; int ly = y + k + height; int lz = z + j; if (lx >= 0 && lx < VOXEL_CHUNK_SIZE_XZ && ly >= 0 && ly < VOXEL_CHUNK_SIZE_Y && lz >= 0 && lz < VOXEL_CHUNK_SIZE_XZ) { var ofs = lx + (lz * VOXEL_CHUNK_SIZE_XZ) + (ly * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Needles; } } } } } } else if (treeType == 3) { int height = 4 + x % 10 + y % 10 + z % 10; for (int i = y; i < y + height && i < VOXEL_CHUNK_SIZE_Y; i++) { var ofs = x + (z * VOXEL_CHUNK_SIZE_XZ) + (i * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Wood; } for (int i = 3; i <= height; i++) { int radius = (int)((1.0f - (float)(i - 3) / (height - 3)) * height / 3 + 1) + (x + y + z * z + i * i) % 2; Vector2Int branchDir; float density = (float)((x + y + z + i * i) % 4 + 1) / 6f; if (radius > 1) { for (int dir = 0; dir < 4; dir++) { if ((x + y + z + i + dir + radius) % 6 < 6 * density) { if (dir == 0) { branchDir = new Vector2Int(0, 1); } else if (dir == 1) { branchDir = new Vector2Int(0, -1); } else if (dir == 2) { branchDir = new Vector2Int(-1, 0); } else { branchDir = new Vector2Int(1, 0); } int ly = y + i; for (int k = 1; k <= radius; k++) { int lx = x + branchDir.x * k; int lz = z + branchDir.y * k; if (lx >= 0 && lx < VOXEL_CHUNK_SIZE_XZ && ly >= 0 && ly < VOXEL_CHUNK_SIZE_Y && lz >= 0 && lz < VOXEL_CHUNK_SIZE_XZ) { var ofs = lx + (lz * VOXEL_CHUNK_SIZE_XZ) + (ly * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = k == 1 ? EVoxelBlockType.Wood : EVoxelBlockType.Needles.WithFlags(EVoxelBlockFlags.FullVoxel); } if (k < radius) { lx = x + branchDir.x * k + branchDir.y; lz = z + branchDir.y * k + branchDir.x; if (lx >= 0 && lx < VOXEL_CHUNK_SIZE_XZ && ly >= 0 && ly < VOXEL_CHUNK_SIZE_Y && lz >= 0 && lz < VOXEL_CHUNK_SIZE_XZ) { var ofs = lx + (lz * VOXEL_CHUNK_SIZE_XZ) + (ly * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Needles.WithFlags(EVoxelBlockFlags.FullVoxel); } lx = x + branchDir.x * k - branchDir.y; lz = z + branchDir.y * k - branchDir.x; if (lx >= 0 && lx < VOXEL_CHUNK_SIZE_XZ && ly >= 0 && ly < VOXEL_CHUNK_SIZE_Y && lz >= 0 && lz < VOXEL_CHUNK_SIZE_XZ) { var ofs = lx + (lz * VOXEL_CHUNK_SIZE_XZ) + (ly * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Needles.WithFlags(EVoxelBlockFlags.FullVoxel); } } } } } } } } }
static void ConstructTower(int x, int y, int z, PinnedChunkData_t chunk) { int towerHeight = 120; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { Vector3Int pos = new Vector3Int(x + i, 0, z + j); int groundHeight = 0; for (int k = towerHeight; k >= groundHeight; k--) { pos.y = k + y; if (pos.x >= 0 && pos.x < VOXEL_CHUNK_SIZE_XZ && pos.z >= 0 && pos.z < VOXEL_CHUNK_SIZE_XZ && pos.y >= 0 && pos.y < VOXEL_CHUNK_SIZE_Y) { var ofs = pos.x + (pos.z * VOXEL_CHUNK_SIZE_XZ) + (pos.y * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; chunk.voxeldata[ofs] = EVoxelBlockType.Rock; } } } } for (int i = -3; i <= 3; i++) { for (int j = -3; j <= 3; j++) { if (i > 1 || i < -1 || j > 1 || j < -1) { Vector3Int pos = new Vector3Int(x + i, 0, z + j); int groundHeight = 0; for (int k = towerHeight; k >= groundHeight; k--) { int stepIndex = 0; if (j < -1) { if (i < -1) { stepIndex = 0; } else if (i < 2) { stepIndex = 1; } else { stepIndex = 2; } } else if (j < 2) { if (i > 1) { stepIndex = 3; } else { stepIndex = 7; } } else { if (i > 1) { stepIndex = 4; } else if (i > -2) { stepIndex = 5; } else { stepIndex = 6; } } int modElevation = (k + stepIndex) % 7; if (modElevation < 2) { pos.y = k + y; if (pos.x >= 0 && pos.x < VOXEL_CHUNK_SIZE_XZ && pos.z >= 0 && pos.z < VOXEL_CHUNK_SIZE_XZ && pos.y >= 0 && pos.y < VOXEL_CHUNK_SIZE_Y) { var ofs = pos.x + (pos.z * VOXEL_CHUNK_SIZE_XZ) + (pos.y * VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ); chunk.flags |= EChunkFlags.SOLID; if (modElevation == 0 && i != 3 && i != 3 && j != -3 && j != 3 && k != towerHeight) { chunk.voxeldata[ofs] = EVoxelBlockType.Rock; } else { chunk.voxeldata[ofs] = EVoxelBlockType.Rock.WithFlags(EVoxelBlockFlags.FullVoxel); } } } } } } } }
public static unsafe PinnedChunkData_t DecompressChunkData(byte *ptr, int len, PinnedChunkData_t chunk, FinalMeshVerts_t verts) { var src = ptr; { var decorationCount = *((int *)src); src += 4; for (int i = 0; i < decorationCount; ++i) { var d = default(Decoration_t); d.pos.x = *((float *)src); src += 4; d.pos.y = *((float *)src); src += 4; d.pos.z = *((float *)src); src += 4; d.type = (EDecorationType)(*((int *)src)); src += 4; chunk.AddDecoration(d); } } if ((chunk.flags & EChunkFlags.SOLID) == 0) { // empty chunk chunk.voxeldata.Broadcast(EVoxelBlockType.Air); for (int i = 0; i < verts.counts.Length; ++i) { verts.counts[i] = 0; } for (int i = 0; i < verts.submeshes.Length; ++i) { verts.submeshes[i] = 0; } return(chunk); } { var voxeldata = chunk.voxeldata; var count = chunk.voxeldata.length; for (int i = 0; i < count; ++i) { voxeldata[i] = new Voxel_t(src[i]); } } src += chunk.voxeldata.length; for (int i = 0; i < verts.counts.Length; ++i) { verts.counts[i] = *((int *)src); src += 4; } for (int i = 0; i < verts.submeshes.Length; ++i) { verts.submeshes[i] = *((int *)src); src += 4; } int totalVerts = *((int *)src); src += 4; int totalIndices = *((int *)src); src += 4; for (int i = 0; i < totalVerts; ++i) { Vector3 v3; v3.x = *((float *)src); src += 4; v3.y = *((float *)src); src += 4; v3.z = *((float *)src); src += 4; verts.positions[i] = v3; } for (int i = 0; i < totalVerts; ++i) { Vector3 v3; v3.x = *((float *)src); src += 4; v3.y = *((float *)src); src += 4; v3.z = *((float *)src); src += 4; verts.normals[i] = v3; } for (int i = 0; i < totalVerts; ++i) { uint c = *((uint *)src); src += 4; verts.colors[i] = Utils.GetColor32FromUIntRGBA(c); } for (int i = 0; i < totalIndices; ++i) { verts.indices[i] = *((int *)src); src += 4; } return(chunk); }
void Run(PinnedChunkData_t chunk) { _smoothVerts.Init(); _numVoxels = 0; if ((chunk.flags & EChunkFlags.SOLID) == 0) { // no solid blocks in this chunk it can't have any visible faces. _smoothVerts.Finish(); return; } for (int y = -BORDER_SIZE; y < VOXEL_CHUNK_SIZE_Y + BORDER_SIZE; ++y) { var ywrap = Wrap(y, VOXEL_CHUNK_SIZE_Y); var ymin = (ywrap == 0); var ymax = (ywrap == (VOXEL_CHUNK_SIZE_Y - 1)); var yofs = VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ * ywrap; var cy = (y < 0) ? 0 : (y < VOXEL_CHUNK_SIZE_Y) ? 1 : 2; for (int z = -BORDER_SIZE; z < VOXEL_CHUNK_SIZE_XZ + BORDER_SIZE; ++z) { var zwrap = Wrap(z, VOXEL_CHUNK_SIZE_XZ); var zmin = (zwrap == 0); var zmax = (zwrap == (VOXEL_CHUNK_SIZE_XZ - 1)); var zofs = VOXEL_CHUNK_SIZE_XZ * zwrap; var cz = (z < 0) ? 0 : (z < VOXEL_CHUNK_SIZE_XZ) ? 1 : 2; for (int x = -BORDER_SIZE; x < VOXEL_CHUNK_SIZE_XZ + BORDER_SIZE; ++x) { var xwrap = Wrap(x, VOXEL_CHUNK_SIZE_XZ); var xmin = (xwrap == 0); var xmax = (xwrap == (VOXEL_CHUNK_SIZE_XZ - 1)); var xofs = xwrap; var cx = (x < 0) ? 0 : (x < VOXEL_CHUNK_SIZE_XZ) ? 1 : 2; var chunkIndex = cx + (cy * Y_PITCH) + (cz * Z_PITCH); var POS_X = chunkIndex + 1; var NEG_X = chunkIndex - 1; var POS_Y = chunkIndex + Y_PITCH; var NEG_Y = chunkIndex - Y_PITCH; var POS_Z = chunkIndex + Z_PITCH; var NEG_Z = chunkIndex - Z_PITCH; var neighbor = _area[chunkIndex]; if (neighbor.valid != 0) { var voxel = neighbor.voxeldata[zofs + yofs + xofs]; if (_tables.blockContents[(int)voxel.type] == EVoxelBlockContents.None) { continue; } var blocktype = voxel.type; // avoid contents-change with neighbor blocks in unloaded-space _vn[0] = blocktype; _vn[1] = blocktype; _vn[2] = blocktype; _vn[3] = blocktype; _vn[4] = blocktype; _vn[5] = blocktype; if (xmin) { _vn[0] = neighbor.voxeldata[zofs + yofs + xofs + 1].type; if (_area[NEG_X].valid != 0) { _vn[1] = _area[NEG_X].voxeldata[zofs + yofs + VOXEL_CHUNK_SIZE_XZ - 1].type; } } else if (xmax) { if (_area[POS_X].valid != 0) { _vn[0] = _area[POS_X].voxeldata[zofs + yofs].type; } _vn[1] = neighbor.voxeldata[zofs + yofs + xofs - 1].type; } else { _vn[0] = neighbor.voxeldata[zofs + yofs + xofs + 1].type; _vn[1] = neighbor.voxeldata[zofs + yofs + xofs - 1].type; } if (ymin) { _vn[2] = neighbor.voxeldata[yofs + (VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ) + zofs + xofs].type; if (_area[NEG_Y].valid != 0) { _vn[3] = _area[NEG_Y].voxeldata[(VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ * (VOXEL_CHUNK_SIZE_Y - 1)) + zofs + xofs].type; } } else if (ymax) { if (_area[POS_Y].valid != 0) { _vn[2] = _area[POS_Y].voxeldata[zofs + xofs].type; } _vn[3] = neighbor.voxeldata[yofs - (VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ) + zofs + xofs].type; } else { _vn[2] = neighbor.voxeldata[yofs + (VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ) + zofs + xofs].type; _vn[3] = neighbor.voxeldata[yofs - (VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ) + zofs + xofs].type; } if (zmin) { _vn[4] = neighbor.voxeldata[yofs + (zofs + VOXEL_CHUNK_SIZE_XZ) + xofs].type; if (_area[NEG_Z].valid != 0) { _vn[5] = _area[NEG_Z].voxeldata[yofs + (VOXEL_CHUNK_SIZE_XZ * (VOXEL_CHUNK_SIZE_XZ - 1)) + xofs].type; } } else if (zmax) { if (_area[POS_Z].valid != 0) { _vn[4] = _area[POS_Z].voxeldata[yofs + xofs].type; } _vn[5] = neighbor.voxeldata[yofs + (zofs - VOXEL_CHUNK_SIZE_XZ) + xofs].type; } else { _vn[4] = neighbor.voxeldata[yofs + (zofs + VOXEL_CHUNK_SIZE_XZ) + xofs].type; _vn[5] = neighbor.voxeldata[yofs + (zofs - VOXEL_CHUNK_SIZE_XZ) + xofs].type; } for (int i = 0; i < 6; ++i) { _vnc[i] = _tables.blockContents[(int)_vn[i]]; } var isBorderVoxel = (x < 0) || (x >= VOXEL_CHUNK_SIZE_XZ) || (y < 0) || (y >= VOXEL_CHUNK_SIZE_Y) || (z < 0) || (z >= VOXEL_CHUNK_SIZE_XZ); EmitVoxelFaces((x + BORDER_SIZE) + ((z + BORDER_SIZE) * NUM_VOXELS_XZ) + ((y + BORDER_SIZE) * NUM_VOXELS_XZ * NUM_VOXELS_XZ), x + BORDER_SIZE, y + BORDER_SIZE, z + BORDER_SIZE, voxel, isBorderVoxel); } } } } _smoothVerts.Finish(); }
protected abstract Unity.Jobs.JobHandle CreateGenVoxelsJob(WorldChunkPos_t pos, PinnedChunkData_t chunk);
void Run(PinnedChunkData_t chunk) { _smoothVerts.Init(); if ((chunk.flags & EChunkFlags.SOLID) == 0) { // no solid blocks in this chunk it can't have any visible faces. _smoothVerts.Finish(); return; } byte * grid = stackalloc byte[8]; int * x = stackalloc int[3]; int * edges = stackalloc int[12]; byte * edgeBlocks = stackalloc byte[24]; float *nv = stackalloc float[3]; for (x[2] = -2; x[2] < VOXEL_CHUNK_SIZE_Y + 1; ++x[2]) { for (x[1] = -2; x[1] < VOXEL_CHUNK_SIZE_XZ + 1; ++x[1]) { for (x[0] = -2; x[0] < VOXEL_CHUNK_SIZE_XZ + 1; ++x[0]) { // read voxels around this vertex // note the mask, and grid verts for the cubes are X/Y/Z, but unity // is Y up so we have to swap Z/Y bool isBorder = (x[0] < 0) || (x[0] >= VOXEL_CHUNK_SIZE_XZ) || (x[1] < 0) || (x[1] >= VOXEL_CHUNK_SIZE_XZ) || (x[2] < 0) || (x[2] >= VOXEL_CHUNK_SIZE_Y); int cubeIndex = 0; for (int i = 0; i < 8; ++i) { var v = _tables.mc_cubeVerts[i]; var iz = x[2] + v[2]; var zwrap = Wrap(iz, VOXEL_CHUNK_SIZE_Y); var zofs = VOXEL_CHUNK_SIZE_XZ * VOXEL_CHUNK_SIZE_XZ * zwrap; // zofs is really yofs in voxel data var cz = (iz < 0) ? 0 : (iz < VOXEL_CHUNK_SIZE_Y) ? 1 : 2; var iy = x[1] + v[1]; var ywrap = Wrap(iy, VOXEL_CHUNK_SIZE_XZ); var yofs = VOXEL_CHUNK_SIZE_XZ * ywrap; // yofs is really zofs in voxel data var cy = (iy < 0) ? 0 : (iy < VOXEL_CHUNK_SIZE_XZ) ? 1 : 2; var ix = x[0] + v[0]; var xwrap = Wrap(ix, VOXEL_CHUNK_SIZE_XZ); var xofs = xwrap; var cx = (ix < 0) ? 0 : (ix < VOXEL_CHUNK_SIZE_XZ) ? 1 : 2; var chunkIndex = cx + (cz * Y_PITCH) + (cy * Z_PITCH); var POS_X = chunkIndex + 1; var NEG_X = chunkIndex - 1; var POS_Y = chunkIndex + Y_PITCH; var NEG_Y = chunkIndex - Y_PITCH; var POS_Z = chunkIndex + Z_PITCH; var NEG_Z = chunkIndex - Z_PITCH; var neighbor = _area[chunkIndex]; var voxel = neighbor.valid != 0 ? neighbor.voxeldata[xofs + yofs + zofs] : EVoxelBlockType.Air; grid[i] = voxel.raw; if (_tables.blockContents[(int)voxel.type] == EVoxelBlockContents.None) { cubeIndex |= 1 << i; } } var edgeMask = _tables.mc_edgeTable[cubeIndex]; if (edgeMask == 0) { // no contents change continue; } for (int i = 0; i < 12; ++i) { edges[i] = -1; if ((edgeMask & (1 << i)) == 0) { continue; } nv[0] = 0; nv[1] = 0; nv[2] = 0; var e = _tables.mc_edgeIndex[i]; var v0 = _tables.mc_cubeVerts[e[0]]; var v1 = _tables.mc_cubeVerts[e[1]]; edgeBlocks[i * 2 + 0] = grid[e[0]]; edgeBlocks[i * 2 + 1] = grid[e[1]]; var t = 0.5f; for (int j = 0; j < 3; ++j) { nv[j] = (x[j] + v0[j] + 0.5f) + t * (v1[j] - v0[j]); } edges[i] = _smoothVerts.EmitVert(new Vector3(nv[0], nv[2], nv[1])); } var faces = _tables.mc_triTable[cubeIndex]; for (int i = 0; (i < faces.length) && (faces[i] != -1); i += 3) { BoundsCheckAndThrow(faces[i + 0], 0, 12); BoundsCheckAndThrow(faces[i + 1], 0, 12); BoundsCheckAndThrow(faces[i + 2], 0, 12); Voxel_t voxel = default(Voxel_t); EVoxelBlockContents vc = default(EVoxelBlockContents); for (int j = 0; j < 3; ++j) { var v0v = new Voxel_t(edgeBlocks[faces[i + j] * 2 + 0]); var v1v = new Voxel_t(edgeBlocks[faces[i + j] * 2 + 1]); var v0c = _tables.blockContents[(int)v0v.type]; var v1c = _tables.blockContents[(int)v1v.type]; if (j > 0) { if (v0c > v1c) { if (v0c > vc) { vc = v0c; voxel = v0v; } } else if (v1c > vc) { vc = v1c; voxel = v1v; } } else { vc = (v0c > v1c) ? v0c : v1c; voxel = (v0c > v1c) ? v0v : v1v; } } int mat, layer; uint smg; Color32 color; float smoothing; GetBlockColorAndSmoothing(voxel.type, out color, out smg, out smoothing, out layer); mat = _blockMaterials[(int)voxel.type - 1]; _smoothVerts.EmitTri(edges[faces[i]], edges[faces[i + 2]], edges[faces[i + 1]], smg, smoothing, color, layer, mat, isBorder); } } } } _smoothVerts.Finish(); }