void RenderModelsInVoxels(VoxelChunk chunk, FastList <ModelInVoxel> mivs) { instancingManager.ClearChunk(chunk); Quaternion rotation = Misc.quaternionZero; Vector3 position; for (int k = 0; k < mivs.count; k++) { ModelInVoxel miv = mivs.values [k]; VoxelDefinition voxelDefinition = miv.vd; bool createGO = voxelDefinition.createGameObject || !voxelDefinition.gpuInstancing; if (createGO) { VoxelPlaceholder placeholder = GetVoxelPlaceholder(chunk, miv.voxelIndex, true); bool createModel = true; if (placeholder.modelInstance != null) { if (placeholder.modelTemplate != voxelDefinition.model) { DestroyImmediate(placeholder.modelInstance); } else { createModel = false; } } MeshFilter mf; Mesh mesh = null; if (createModel || placeholder.modelMeshFilter == null || placeholder.modelMeshFilter.sharedMesh == null || placeholder.modelMeshRenderer == null) { if (voxelDefinition.model == null) { continue; } placeholder.modelTemplate = voxelDefinition.model; placeholder.modelInstance = Instantiate(voxelDefinition.model); placeholder.modelInstance.name = "DynamicVoxelInstance"; // Note: placeHolder.modelInstance layer must be different from layerVoxels to allow dynamic voxels collide with terrain. So don't set its layer to layer voxels placeholder.modelMeshRenderer = placeholder.modelInstance.GetComponent <MeshRenderer> (); if (voxelDefinition.gpuInstancing) { if (placeholder.modelMeshRenderer != null) { placeholder.modelMeshRenderer.enabled = false; } } else { mf = placeholder.modelMeshFilter = placeholder.modelInstance.GetComponent <MeshFilter> (); if (mf != null) { mesh = mf.sharedMesh = Instantiate <Mesh> (mf.sharedMesh); mesh.hideFlags = HideFlags.DontSave; } } } else { mf = placeholder.modelMeshFilter; if (mf != null) { mesh = mf.sharedMesh; } } // Parent model to the placeholder Transform tModel = placeholder.modelInstance.transform; tModel.SetParent(placeholder.transform, false); tModel.transform.localPosition = Misc.vector3zero; tModel.transform.localScale = voxelDefinition.scale; if (voxelDefinition.gpuInstancing) { rotation = placeholder.transform.localRotation; } else { // Adjust lighting if (effectiveGlobalIllumination || chunk.voxels [miv.voxelIndex].isColored) { // Update mesh colors float voxelLight = chunk.voxels [miv.voxelIndex].lightMesh / 15f; Color32 color = chunk.voxels [miv.voxelIndex].color; color.r = (byte)(color.r * voxelLight); color.g = (byte)(color.g * voxelLight); color.b = (byte)(color.b * voxelLight); modelMeshColors.Clear(); for (int c = 0; c < mesh.vertexCount; c++) { modelMeshColors.Add(color); } mesh.SetColors(modelMeshColors); mesh.UploadMeshData(false); } } if (!tModel.gameObject.activeSelf) { tModel.gameObject.SetActive(true); } position = placeholder.transform.position; } else { // pure gpu instancing, no gameobject position = GetVoxelPosition(chunk, miv.voxelIndex); rotation = voxelDefinition.GetRotation(position); // deterministic rotation // User rotation float rot = chunk.voxels [miv.voxelIndex].GetTextureRotationDegrees(); if (rot != 0) { rotation *= Quaternion.Euler(0, rot, 0); } // Custom position position = position + rotation * voxelDefinition.GetOffset(position); } if (voxelDefinition.gpuInstancing) { instancingManager.AddVoxel(chunk, miv.voxelIndex, position, rotation, voxelDefinition.scale); } } }
/// <summary> /// Uses geometry-shader-based materials and mesh to render the chunk /// </summary> void GenerateMeshData_Geo(int jobIndex) { VoxelChunk chunk = meshJobs [jobIndex].chunk; tempChunkVertices = meshJobs [jobIndex].vertices; tempChunkUV0 = meshJobs [jobIndex].uv0; tempChunkUV2 = meshJobs [jobIndex].uv2; tempChunkColors32 = meshJobs [jobIndex].colors; meshColliderVertices = meshJobs [jobIndex].colliderVertices; meshColliderIndices = meshJobs [jobIndex].colliderIndices; navMeshVertices = meshJobs [jobIndex].navMeshVertices; navMeshIndices = meshJobs [jobIndex].navMeshIndices; mivs = meshJobs [jobIndex].mivs; tempChunkVertices.Clear(); tempChunkUV0.Clear(); tempChunkColors32.Clear(); if (enableColliders) { meshColliderIndices.Clear(); meshColliderVertices.Clear(); if (enableNavMesh) { navMeshIndices.Clear(); navMeshVertices.Clear(); } } mivs.Clear(); Voxel[] voxels = chunk.voxels; Vector4 uvAux, uv2Aux; tempChunkUV2.Clear(); int chunkUVIndex = -1; int chunkVoxelCount = 0; Color32 tintColor = Misc.color32White; Vector3 pos = Misc.vector3zero; ModelInVoxel miv = new ModelInVoxel(); const int V_ONE_Y_ROW = 18 * 18; const int V_ONE_Z_ROW = 18; int voxelIndex = 0; int voxelSignature = 1; for (int y = 0; y < 16; y++) { int vy = (y + 1) * 18 * 18; for (int z = 0; z < 16; z++) { int vyz = vy + (z + 1) * 18; for (int x = 0; x < 16; x++, voxelIndex++) { voxels [voxelIndex].lightMesh = voxels [voxelIndex].light; if (voxels [voxelIndex].hasContent != 1) { continue; } int vxyz = vyz + x + 1; int vindex = vxyz - 1; Voxel[] chunk_middle_middle_left = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_middle_left = virtualChunk [vindex].voxelIndex; vindex = vxyz + 1; Voxel[] chunk_middle_middle_right = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_middle_right = virtualChunk [vindex].voxelIndex; vindex = vxyz + V_ONE_Y_ROW; Voxel[] chunk_top_middle_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int top_middle_middle = virtualChunk [vindex].voxelIndex; vindex = vxyz - V_ONE_Y_ROW; Voxel[] chunk_bottom_middle_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_middle_middle = virtualChunk [vindex].voxelIndex; vindex = vxyz + V_ONE_Z_ROW; Voxel[] chunk_middle_forward_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_forward_middle = virtualChunk [vindex].voxelIndex; vindex = vxyz - V_ONE_Z_ROW; Voxel[] chunk_middle_back_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_back_middle = virtualChunk [vindex].voxelIndex; // If voxel is surrounded by material, don't render int v1u = chunk_top_middle_middle [top_middle_middle].opaque; int v1f = chunk_middle_forward_middle [middle_forward_middle].opaque; int v1b = chunk_middle_back_middle [middle_back_middle].opaque; int v1l = chunk_middle_middle_left [middle_middle_left].opaque; int v1r = chunk_middle_middle_right [middle_middle_right].opaque; int v1d = chunk_bottom_middle_middle [bottom_middle_middle].opaque; if (v1u + v1f + v1b + v1l + v1r + v1d == 90) // 90 = 15 * 6 { continue; } // top vindex = vxyz + V_ONE_Y_ROW + V_ONE_Z_ROW - 1; Voxel[] chunk_top_forward_left = chunk9 [virtualChunk [vindex].chunk9Index]; int top_forward_left = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_top_forward_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int top_forward_middle = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_top_forward_right = chunk9 [virtualChunk [vindex].chunk9Index]; int top_forward_right = virtualChunk [vindex].voxelIndex; vindex = vxyz + V_ONE_Y_ROW - 1; Voxel[] chunk_top_middle_left = chunk9 [virtualChunk [vindex].chunk9Index]; int top_middle_left = virtualChunk [vindex].voxelIndex; vindex += 2; Voxel[] chunk_top_middle_right = chunk9 [virtualChunk [vindex].chunk9Index]; int top_middle_right = virtualChunk [vindex].voxelIndex; vindex = vxyz + V_ONE_Y_ROW - V_ONE_Z_ROW - 1; Voxel[] chunk_top_back_left = chunk9 [virtualChunk [vindex].chunk9Index]; int top_back_left = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_top_back_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int top_back_middle = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_top_back_right = chunk9 [virtualChunk [vindex].chunk9Index]; int top_back_right = virtualChunk [vindex].voxelIndex; // middle vindex = vxyz + V_ONE_Z_ROW - 1; Voxel[] chunk_middle_forward_left = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_forward_left = virtualChunk [vindex].voxelIndex; vindex += 2; Voxel[] chunk_middle_forward_right = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_forward_right = virtualChunk [vindex].voxelIndex; vindex = vxyz - V_ONE_Z_ROW - 1; Voxel[] chunk_middle_back_left = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_back_left = virtualChunk [vindex].voxelIndex; vindex += 2; Voxel[] chunk_middle_back_right = chunk9 [virtualChunk [vindex].chunk9Index]; int middle_back_right = virtualChunk [vindex].voxelIndex; // bottom vindex = vxyz - V_ONE_Y_ROW + V_ONE_Z_ROW - 1; Voxel[] chunk_bottom_forward_left = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_forward_left = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_bottom_forward_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_forward_middle = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_bottom_forward_right = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_forward_right = virtualChunk [vindex].voxelIndex; vindex = vxyz - V_ONE_Y_ROW - 1; Voxel[] chunk_bottom_middle_left = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_middle_left = virtualChunk [vindex].voxelIndex; vindex += 2; Voxel[] chunk_bottom_middle_right = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_middle_right = virtualChunk [vindex].voxelIndex; vindex = vxyz - V_ONE_Y_ROW - V_ONE_Z_ROW - 1; Voxel[] chunk_bottom_back_left = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_back_left = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_bottom_back_middle = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_back_middle = virtualChunk [vindex].voxelIndex; vindex++; Voxel[] chunk_bottom_back_right = chunk9 [virtualChunk [vindex].chunk9Index]; int bottom_back_right = virtualChunk [vindex].voxelIndex; pos.y = y - 7.5f; pos.z = z - 7.5f; pos.x = x - 7.5f; voxelSignature += voxelIndex; chunkVoxelCount++; VoxelDefinition type = voxelDefinitions [voxels [voxelIndex].typeIndex]; FastFixedBuffer <int> indices = tempGeoIndices[type.materialBufferIndex]; uvAux.x = type.textureIndexSide; uvAux.y = type.textureIndexTop; uvAux.z = type.textureIndexBottom; uvAux.w = 0; int occlusionX = 0; int occlusionY = 0; int occlusionZ = 0; int occlusionW = 0; int occ = 0; RenderType rt = type.renderType; switch (rt) { case RenderType.Water: { ++chunkUVIndex; indices.Add(chunkUVIndex); uvAux.w = voxels [voxelIndex].light / 15f; int hf = chunk_middle_forward_middle [middle_forward_middle].GetWaterLevel(); int hb = chunk_middle_back_middle [middle_back_middle].GetWaterLevel(); int hr = chunk_middle_middle_right [middle_middle_right].GetWaterLevel(); int hl = chunk_middle_middle_left [middle_middle_left].GetWaterLevel(); // compute water neighbours and account for foam // back occ = chunk_middle_back_middle [middle_back_middle].hasContent; if (occ == 1) { // occlusionX bit = 0 means that face is visible occlusionX |= 1; if (hb == 0) { occlusionY |= 1; } } // front occ = chunk_middle_forward_middle [middle_forward_middle].hasContent; if (occ == 1) { occlusionX |= (1 << 1); if (hf == 0) { occlusionY |= 2; } } int wh = voxels [voxelIndex].GetWaterLevel(); int th = chunk_top_middle_middle [top_middle_middle].GetWaterLevel(); // top (hide only if water level is full or voxel on top is water) if (wh == 15 || th > 0) { occlusionX += ((chunk_top_middle_middle [top_middle_middle].hasContent & 1) << 2); } // down occlusionX += ((chunk_bottom_middle_middle [bottom_middle_middle].hasContent & 1) << 3); // left occ = chunk_middle_middle_left [middle_middle_left].hasContent; if (occ == 1) { occlusionX |= (1 << 4); if (hl == 0) { occlusionY |= 4; } } // right occ = chunk_middle_middle_right [middle_middle_right].hasContent; if (occ == 1) { occlusionX += (1 << 5); if (hr == 0) { occlusionY |= 8; } } // If there's water on top, full size if (th > 0) { occlusionW = 15 + (15 << 4) + (15 << 8) + (15 << 12); // full height occlusionY += (1 << 8) + (1 << 10); // neutral/no flow } else { // Get corners heights int hfr = chunk_middle_forward_right [middle_forward_right].GetWaterLevel(); int hbr = chunk_middle_back_right [middle_back_right].GetWaterLevel(); int hbl = chunk_middle_back_left [middle_back_left].GetWaterLevel(); int hfl = chunk_middle_forward_left [middle_forward_left].GetWaterLevel(); // corner foam if (type.showFoam) { if (hbl == 0) { occlusionY |= chunk_middle_back_left [middle_back_left].hasContent << 4; } if (hfl == 0) { occlusionY |= chunk_middle_forward_left [middle_forward_left].hasContent << 5; } if (hfr == 0) { occlusionY |= chunk_middle_forward_right [middle_forward_right].hasContent << 6; } if (hbr == 0) { occlusionY |= chunk_middle_back_right [middle_back_right].hasContent << 7; } } int tf = chunk_top_forward_middle [top_forward_middle].GetWaterLevel(); int tfr = chunk_top_forward_right [top_forward_right].GetWaterLevel(); int tr = chunk_top_middle_right [top_middle_right].GetWaterLevel(); int tbr = chunk_top_back_right [top_back_right].GetWaterLevel(); int tb = chunk_top_back_middle [top_back_middle].GetWaterLevel(); int tbl = chunk_top_back_left [top_back_left].GetWaterLevel(); int tl = chunk_top_middle_left [top_middle_left].GetWaterLevel(); int tfl = chunk_top_forward_left [top_forward_left].GetWaterLevel(); // forward right corner if (tf * hf + tfr * hfr + tr * hr > 0) { hfr = 15; } else { hfr = wh > hfr ? wh : hfr; if (hf > hfr) { hfr = hf; } if (hr > hfr) { hfr = hr; } } // bottom right corner if (tr * hr + tbr * hbr + tb * hb > 0) { hbr = 15; } else { hbr = wh > hbr ? wh : hbr; if (hr > hbr) { hbr = hr; } if (hb > hbr) { hbr = hb; } } // bottom left corner if (tb * hb + tbl * hbl + tl * hl > 0) { hbl = 15; } else { hbl = wh > hbl ? wh : hbl; if (hb > hbl) { hbl = hb; } if (hl > hbl) { hbl = hl; } } // forward left corner if (tl * hl + tfl * hfl + tf * hf > 0) { hfl = 15; } else { hfl = wh > hfl ? wh : hfl; if (hl > hfl) { hfl = hl; } if (hf > hfl) { hfl = hf; } } occlusionW = hfr + (hbr << 4) + (hbl << 8) + (hfl << 12); // flow int fx = hfr + hbr - hfl - hbl; if (fx > 0) { fx = 2; } else if (fx < 0) { fx = 0; } else { fx = 1; } int fz = hfl + hfr - hbl - hbr; if (fz > 0) { fz = 2; } else if (fz < 0) { fz = 0; } else { fz = 1; } occlusionY += (fx << 8) + (fz << 10); } if (!type.showFoam) { occlusionY &= 0xFF00; } pos.y -= 0.5f; tempChunkVertices.Add(pos); } break; case RenderType.CutoutCross: { ++chunkUVIndex; indices.Add(chunkUVIndex); uvAux.w = voxels [voxelIndex].light / 15f; Vector3 aux = pos; float random = WorldRand.GetValue(pos); uvAux.w *= 1f + (random - 0.45f) * type.colorVariation; // * (1f + random * 0.3f; // adds color variation pos.x += random * 0.5f - 0.25f; aux.x += 1f; random = WorldRand.GetValue(aux); pos.z += random * 0.5f - 0.25f; pos.y -= random * 0.1f; tempChunkVertices.Add(pos); } break; case RenderType.OpaqueNoAO: ++chunkUVIndex; tempChunkVertices.Add(pos); v1b = (v1b + 1) >> 4; // substitutes a comparisson with FULL_OPAQUE (15) v1f = (v1f + 1) >> 4; v1u = (v1u + 1) >> 4; v1d = (v1d + 1) >> 4; v1l = (v1l + 1) >> 4; v1r = (v1r + 1) >> 4; uvAux.w = v1b + (v1f << 1) + (v1u << 2) + (v1d << 3) + (v1l << 4) + (v1r << 5); indices.Add(chunkUVIndex); break; case RenderType.Transp6tex: { ++chunkUVIndex; indices.Add(chunkUVIndex); int rotation = voxels [voxelIndex].GetTextureRotation(); uvAux = type.textureSideIndices [rotation].xyzw; uvAux.w = voxels [voxelIndex].light; // Avoid overlapping faces of same glass material int typeIndex = voxels [voxelIndex].typeIndex; // back if (v1b == FULL_OPAQUE || chunk_middle_back_middle [middle_back_middle].typeIndex == typeIndex) { // occlusionX bit = 0 means that face is visible occlusionX |= 1; } // front if (v1f == FULL_OPAQUE || chunk_middle_forward_middle [middle_forward_middle].typeIndex == typeIndex) { occlusionX |= 2; } // up if (v1u == FULL_OPAQUE || chunk_top_middle_middle [top_middle_middle].typeIndex == typeIndex) { occlusionX |= 4; } // down if (v1d == FULL_OPAQUE || chunk_bottom_middle_middle [bottom_middle_middle].typeIndex == typeIndex) { occlusionX |= 8; } // left if (v1l == FULL_OPAQUE || chunk_middle_middle_left [middle_middle_left].typeIndex == typeIndex) { occlusionX |= 16; } // right if (v1r == FULL_OPAQUE || chunk_middle_middle_right [middle_middle_right].typeIndex == typeIndex) { occlusionX |= 32; } tempChunkVertices.Add(pos); // Pass custom alpha occlusionY = (int)(255 * type.alpha); // Add collider data if (enableColliders) { if (v1b == 0) { greedyCollider.AddQuad(FaceDirection.Back, x, y, z); } if (v1f == 0) { greedyCollider.AddQuad(FaceDirection.Forward, x, y, z); } if (v1u == 0) { greedyCollider.AddQuad(FaceDirection.Top, x, z, y); } if (v1d == 0) { greedyCollider.AddQuad(FaceDirection.Bottom, x, z, y); } if (v1l == 0) { greedyCollider.AddQuad(FaceDirection.Left, z, y, x); } if (v1r == 0) { greedyCollider.AddQuad(FaceDirection.Right, z, y, x); } if (enableNavMesh && type.navigatable) { if (v1b == 0) { greedyNavMesh.AddQuad(FaceDirection.Back, x, y, z); } if (v1f == 0) { greedyNavMesh.AddQuad(FaceDirection.Forward, x, y, z); } if (v1u == 0) { greedyNavMesh.AddQuad(FaceDirection.Top, x, z, y); } if (v1l == 0) { greedyNavMesh.AddQuad(FaceDirection.Left, z, y, x); } if (v1r == 0) { greedyNavMesh.AddQuad(FaceDirection.Right, z, y, x); } } } } break; default: //case RenderType.Custom: miv.voxelIndex = voxelIndex; miv.vd = type; mivs.Add(miv); continue; case RenderType.Empty: { v1b = (v1b + 1) >> 4; // substitutes a comparison with FULL_OPAQUE (15) v1f = (v1f + 1) >> 4; v1u = (v1u + 1) >> 4; v1d = (v1d + 1) >> 4; v1l = (v1l + 1) >> 4; v1r = (v1r + 1) >> 4; // Add collider data if (enableColliders) { if (v1b == 0) { greedyCollider.AddQuad(FaceDirection.Back, x, y, z); } if (v1f == 0) { greedyCollider.AddQuad(FaceDirection.Forward, x, y, z); } if (v1u == 0) { greedyCollider.AddQuad(FaceDirection.Top, x, z, y); } if (v1d == 0) { greedyCollider.AddQuad(FaceDirection.Bottom, x, z, y); } if (v1l == 0) { greedyCollider.AddQuad(FaceDirection.Left, z, y, x); } if (v1r == 0) { greedyCollider.AddQuad(FaceDirection.Right, z, y, x); } if (enableNavMesh && type.navigatable) { if (v1b == 0) { greedyNavMesh.AddQuad(FaceDirection.Back, x, y, z); } if (v1f == 0) { greedyNavMesh.AddQuad(FaceDirection.Forward, x, y, z); } if (v1u == 0) { greedyNavMesh.AddQuad(FaceDirection.Top, x, z, y); } if (v1l == 0) { greedyNavMesh.AddQuad(FaceDirection.Left, z, y, x); } if (v1r == 0) { greedyNavMesh.AddQuad(FaceDirection.Right, z, y, x); } } } } continue; // loop case RenderType.Opaque: case RenderType.Opaque6tex: case RenderType.Cutout: // Opaque & Cutout ++chunkUVIndex; tempChunkVertices.Add(pos); if (rt == RenderType.Cutout) { indices.Add(chunkUVIndex); } else { indices.Add(chunkUVIndex); int rotation = voxels [voxelIndex].GetTextureRotation(); uvAux = type.textureSideIndices [rotation].xyzw; } if (denseTrees && rt == RenderType.Cutout) { uvAux.w = 0; } else { v1b = (v1b + 1) >> 4; // substitutes a comparisson with FULL_OPAQUE (15) v1f = (v1f + 1) >> 4; v1u = (v1u + 1) >> 4; v1d = (v1d + 1) >> 4; v1l = (v1l + 1) >> 4; v1r = (v1r + 1) >> 4; uvAux.w = v1b + (v1f << 1) + (v1u << 2) + (v1d << 3) + (v1l << 4) + (v1r << 5); // Add collider data if (enableColliders && rt != RenderType.Cutout) { if (v1b == 0) { greedyCollider.AddQuad(FaceDirection.Back, x, y, z); } if (v1f == 0) { greedyCollider.AddQuad(FaceDirection.Forward, x, y, z); } if (v1u == 0) { greedyCollider.AddQuad(FaceDirection.Top, x, z, y); } if (v1d == 0) { greedyCollider.AddQuad(FaceDirection.Bottom, x, z, y); } if (v1l == 0) { greedyCollider.AddQuad(FaceDirection.Left, z, y, x); } if (v1r == 0) { greedyCollider.AddQuad(FaceDirection.Right, z, y, x); } if (enableNavMesh && type.navigatable) { if (v1b == 0) { greedyNavMesh.AddQuad(FaceDirection.Back, x, y, z); } if (v1f == 0) { greedyNavMesh.AddQuad(FaceDirection.Forward, x, y, z); } if (v1u == 0) { greedyNavMesh.AddQuad(FaceDirection.Top, x, z, y); } if (v1l == 0) { greedyNavMesh.AddQuad(FaceDirection.Left, z, y, x); } if (v1r == 0) { greedyNavMesh.AddQuad(FaceDirection.Right, z, y, x); } } } } if (rt == RenderType.Cutout) { // Add color variation float random = WorldRand.GetValue(pos); int r = (int)(255f * (1f + (random - 0.45f) * type.colorVariation)); uvAux.w += (r << 6); if (type.windAnimation) { uvAux.w += 65536; //1 << 16; } } int lu = chunk_top_middle_middle [top_middle_middle].light; int ll = chunk_middle_middle_left [middle_middle_left].light; int lf = chunk_middle_forward_middle [middle_forward_middle].light; int lr = chunk_middle_middle_right [middle_middle_right].light; int lb = chunk_middle_back_middle [middle_back_middle].light; int ld = chunk_bottom_middle_middle [bottom_middle_middle].light; #if UNITY_EDITOR if (enableSmoothLighting && !draftModeActive) { #else if (enableSmoothLighting) { #endif int v2r = chunk_top_middle_right [top_middle_right].light; int v2br = chunk_top_back_right [top_back_right].light; int v2b = chunk_top_back_middle [top_back_middle].light; int v2bl = chunk_top_back_left [top_back_left].light; int v2l = chunk_top_middle_left [top_middle_left].light; int v2fl = chunk_top_forward_left [top_forward_left].light; int v2f = chunk_top_forward_middle [top_forward_middle].light; int v2fr = chunk_top_forward_right [top_forward_right].light; int v1fr = chunk_middle_forward_right [middle_forward_right].light; int v1br = chunk_middle_back_right [middle_back_right].light; int v1bl = chunk_middle_back_left [middle_back_left].light; int v1fl = chunk_middle_forward_left [middle_forward_left].light; int v0r = chunk_bottom_middle_right [bottom_middle_right].light; int v0br = chunk_bottom_back_right [bottom_back_right].light; int v0b = chunk_bottom_back_middle [bottom_back_middle].light; int v0bl = chunk_bottom_back_left [bottom_back_left].light; int v0l = chunk_bottom_middle_left [bottom_middle_left].light; int v0fl = chunk_bottom_forward_left [bottom_forward_left].light; int v0f = chunk_bottom_forward_middle [bottom_forward_middle].light; int v0fr = chunk_bottom_forward_right [bottom_forward_right].light; // Backwards face // Vertex 0 occ = ((lb + v0b + v0bl + v1bl) >> 2); occlusionX += occ; // Vertex 1 occ = ((lb + v0b + v0br + v1br) >> 2); occlusionX += occ << 4; // Vertex 2 occ = ((lb + v1bl + v2bl + v2b) >> 2); occlusionX += occ << 8; // Vertex 3 occ = ((lb + v2b + v2br + v1br) >> 2); occlusionX += occ << 12; // Forward face // Vertex 5 occ = ((lf + v0f + v0fr + v1fr) >> 2); occlusionX += occ << 16; // Vertex 4 occ = ((lf + v0f + v0fl + v1fl) >> 2); occlusionX += occ << 20; // Vertex 6 occ = ((lf + v1fr + v2fr + v2f) >> 2); occlusionY += occ; // Vertex 7 occ = ((lf + v2f + v2fl + v1fl) >> 2); occlusionY += occ << 4; // Top face // Vertex 2 occ = ((lu + v2b + v2bl + v2l) >> 2); occlusionY += occ << 8; // Vertex 3 occ = ((lu + v2b + v2br + v2r) >> 2); occlusionY += occ << 12; // Vertex 7 occ = ((lu + v2l + v2fl + v2f)) >> 2; occlusionY += occ << 16; // Vertex 6 occ = ((lu + v2r + v2fr + v2f) >> 2); occlusionY += occ << 20; // Left face // Vertex 0 occ = ((ll + v1bl + v0l + v0bl) >> 2); occlusionZ += occ; // Vertex 4 occ = ((ll + v1fl + v0l + v0fl) >> 2); occlusionZ += occ << 4; // Vertex 2 occ = ((ll + v2l + v2bl + v1bl) >> 2); occlusionZ += occ << 8; // Vertex 7 occ = ((ll + v2l + v2fl + v1fl) >> 2); occlusionZ += occ << 12; // Right face // Vertex 1 occ = ((lr + v1br + v0r + v0br) >> 2); occlusionZ += occ << 16; // Vertex 5 occ = ((lr + v1fr + v0r + v0fr) >> 2); occlusionZ += occ << 20; // Vertex 3 occ = ((lr + v2r + v2br + v1br) >> 2); occlusionW += occ; // Vertex 6 occ = ((lr + v2r + v2fr + v1fr) >> 2); occlusionW += occ << 4; // Bottom face // Vertex 0 occ = ((ld + v0b + v0l + v0bl) >> 2); occlusionW += occ << 8; // Vertex 1 occ = ((ld + v0b + v0r + v0br) >> 2); occlusionW += occ << 12; // Vertex 4 occ = ((ld + v0f + v0l + v0fl) >> 2); occlusionW += occ << 16; // Vertex 5 occ = ((ld + v0f + v0r + v0fr) >> 2); occlusionW += occ << 20; } else { occlusionX = lb; // back occlusionX += lf << 4; // forward occlusionX += lu << 8; // top occlusionX += ll << 12; // // left occlusionX += lr << 16; // right occlusionX += ld << 20; // bottom } break; } tempChunkUV0.Add(uvAux); uv2Aux.x = occlusionX; uv2Aux.y = occlusionY; uv2Aux.z = occlusionZ; uv2Aux.w = occlusionW; tempChunkUV2.Add(uv2Aux); if (enableTinting) { tintColor.r = voxels [voxelIndex].red; tintColor.g = voxels [voxelIndex].green; tintColor.b = voxels [voxelIndex].blue; tempChunkColors32.Add(tintColor); } } } } meshJobs [jobIndex].chunk = chunk; // chunkVoxelCount includes MIVs int nonMivsCount = chunkUVIndex + 1; meshJobs [jobIndex].totalVisibleVoxels = nonMivsCount; if (chunkVoxelCount == 0) { return; } if (voxelSignature != chunk.voxelSignature) { chunk.needsColliderRebuild = true; } chunk.voxelSignature = voxelSignature; if (enableColliders) { if (chunk.needsColliderRebuild) { greedyCollider.FlushTriangles(meshColliderVertices, meshColliderIndices); if (enableNavMesh) { greedyNavMesh.FlushTriangles(navMeshVertices, navMeshIndices); } } else { greedyCollider.Clear(); greedyNavMesh.Clear(); } } // job index 0 lists are used as generic buffers but we need to convert them to array to use SetIndices API :( int subMeshCount = 0; for (int k = 0; k < MAX_MATERIALS_PER_CHUNK; k++) { if (tempGeoIndices [k].count > 0) { subMeshCount++; meshJobs [jobIndex].buffers [k].indicesArray = tempGeoIndices [k].ToArray(); meshJobs [jobIndex].buffers [k].indicesCount = meshJobs [jobIndex].buffers [k].indicesArray.Length; } } meshJobs [jobIndex].subMeshCount = subMeshCount; meshJobs [jobIndex].colliderVertices = meshColliderVertices; meshJobs [jobIndex].colliderIndices = meshColliderIndices; meshJobs [jobIndex].navMeshVertices = navMeshVertices; meshJobs [jobIndex].navMeshIndices = navMeshIndices; meshJobs [jobIndex].mivs = mivs; } }
void RenderModelsInVoxels(VoxelChunk chunk, FastList <ModelInVoxel> mivs) { instancedRenderer.ClearChunk(chunk); // deactivate all models in this chunk // we need to iterate the placeholders list entirely to address the case when the voxel is not using GPU instancing. In this case the gameobject renderer needs to be disabled // and we need to do this way because mivs won't contain the custom voxel since it may be termporarily converted to a transparent voxels due to see-through effect if (chunk.placeholders != null) { int count = chunk.placeholders.Count; for (int k = 0; k < count; k++) { if (chunk.placeholders.entries [k].key >= 0) { VoxelPlaceholder placeHolder = chunk.placeholders.entries [k].value; if (placeHolder != null) { placeHolder.ToggleRenderers(false); } } } } Quaternion rotation = Misc.quaternionZero; Vector3 position; for (int k = 0; k < mivs.count; k++) { ModelInVoxel miv = mivs.values [k]; VoxelDefinition voxelDefinition = miv.vd; bool createGO = voxelDefinition.createGameObject || !voxelDefinition.gpuInstancing; if (VoxelIsHidden(chunk, miv.voxelIndex)) { continue; } if (createGO) { VoxelPlaceholder placeholder = GetVoxelPlaceholder(chunk, miv.voxelIndex, true); bool createModel = true; if (placeholder.modelInstance != null) { if (placeholder.modelTemplate != voxelDefinition.prefab) { DestroyImmediate(placeholder.modelInstance); placeholder.originalMeshColors32 = null; placeholder.lastMivTintColor = Misc.color32White; } else { createModel = false; } } if (createModel || placeholder.modelInstance == null) { if (voxelDefinition.prefab == null) { continue; } placeholder.modelTemplate = voxelDefinition.prefab; placeholder.modelInstance = Instantiate(voxelDefinition.prefab); placeholder.modelInstance.name = "DynamicVoxelInstance"; // Note: placeHolder.modelInstance layer must be different from layerVoxels to allow dynamic voxels collide with terrain. So don't set its layer to layer voxels placeholder.modelMeshRenderers = placeholder.modelInstance.GetComponentsInChildren <MeshRenderer> (); if (voxelDefinition.gpuInstancing) { placeholder.ToggleRenderers(false); } else { placeholder.modelMeshFilter = placeholder.modelInstance.GetComponentInChildren <MeshFilter> (true); } // Parent model to the placeholder Transform tModel = placeholder.modelInstance.transform; tModel.SetParent(placeholder.transform, false); tModel.transform.localPosition = Misc.vector3zero; tModel.transform.localScale = voxelDefinition.scale; } else { placeholder.ToggleRenderers(true); } if (voxelDefinition.gpuInstancing) { rotation = placeholder.transform.localRotation; } else { // Adjust lighting if (effectiveGlobalIllumination || chunk.voxels [miv.voxelIndex].isColored) { // Update mesh colors MeshFilter mf = placeholder.modelMeshFilter; if (mf != null) { Mesh mesh = mf.sharedMesh; if (mesh != null) { Color32 tintColor = chunk.voxels [miv.voxelIndex].color; tintColor.a = (byte)(chunk.voxels[miv.voxelIndex].lightMesh + (chunk.voxels[miv.voxelIndex].torchLight << 4)); if (placeholder.lastMivTintColor.a != tintColor.a || placeholder.lastMivTintColor.r != tintColor.r || placeholder.lastMivTintColor.g != tintColor.g || placeholder.lastMivTintColor.b != tintColor.b) { mf.sharedMesh = BakeMeshLighting(mf, tintColor); placeholder.lastMivTintColor = tintColor; } } } } } if (!placeholder.modelInstance.gameObject.activeSelf) { placeholder.modelInstance.gameObject.SetActive(true); } position = placeholder.transform.position; } else { // pure gpu instancing, no gameobject position = GetVoxelPosition(chunk, miv.voxelIndex); rotation = voxelDefinition.GetRotation(position); // deterministic rotation // User rotation float rot = chunk.voxels [miv.voxelIndex].GetTextureRotationDegrees(); if (rot != 0) { rotation *= Quaternion.Euler(0, rot, 0); } // Custom position position += rotation * voxelDefinition.GetOffset(position); } if (voxelDefinition.gpuInstancing) { instancedRenderer.AddVoxel(chunk, miv.voxelIndex, position, rotation, voxelDefinition.scale); } } }