public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot) { var gpuSlot = slot[0] as GPUTileStorage.GPUSlot; if (gpuSlot == null) { throw new NullReferenceException("gpuSlot"); } if (TargetTextureBuffer == null) { TargetTextureBuffer = new RenderTexture(gpuSlot.Texture.descriptor); } GPUTileStorage.GPUSlot sourceGpuSlot = null; var sourceTile = SourceProducer.FindTile(level, tx, ty, false, true); if (sourceTile != null) { sourceGpuSlot = sourceTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find source producer tile failed"); } if (sourceGpuSlot == null) { throw new MissingTileException("Find source tile failed"); } var coords = Vector3.forward; var targetSize = TargetProducer.Cache.GetStorage(0).TileSize; var sourceSize = SourceProducer.Cache.GetStorage(0).TileSize; if (targetSize == sourceSize - 1) { coords.x = 1.0f / (float)sourceSize; coords.y = 1.0f / (float)sourceSize; coords.z = 1.0f - coords.x; } Graphics.Blit(gpuSlot.Texture, TargetTextureBuffer); LayerMaterial.SetTexture("_Target", TargetTextureBuffer); LayerMaterial.SetTexture("_Source", sourceGpuSlot.Texture); LayerMaterial.SetVector("_Coords", coords); Graphics.Blit(null, gpuSlot.Texture, LayerMaterial); }
public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot) { var gpuSlot = slot[0] as GPUTileStorage.GPUSlot; var elevationTile = ElevationProducer.FindTile(level, tx, ty, false, true); GPUTileStorage.GPUSlot elevationGpuSlot = null; if (elevationTile != null) { elevationGpuSlot = elevationTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find elevation tile failed"); } if (gpuSlot == null) { throw new NullReferenceException("gpuSlot"); } if (elevationGpuSlot == null) { throw new NullReferenceException("elevationGpuSlot"); } var tileWidth = gpuSlot.Owner.TileSize; var elevationTex = elevationGpuSlot.Texture; var elevationOSL = new Vector4(0.25f / (float)elevationTex.width, 0.25f / (float)elevationTex.height, 1.0f / (float)elevationTex.width, 0.0f); if (TerrainNode.Deformation.GetType() == typeof(DeformationSpherical)) { var D = TerrainNode.TerrainQuadRoot.Length; var R = D / 2.0; var x0 = (double)(tx) / (double)(1 << level) * D - R; var x1 = (double)(tx + 1) / (double)(1 << level) * D - R; var y0 = (double)(ty) / (double)(1 << level) * D - R; var y1 = (double)(ty + 1) / (double)(1 << level) * D - R; var p0 = new Vector3d(x0, y0, R); var p1 = new Vector3d(x1, y0, R); var p2 = new Vector3d(x0, y1, R); var p3 = new Vector3d(x1, y1, R); var pc = new Vector3d((x0 + x1) * 0.5, (y0 + y1) * 0.5, R); double l0 = 0, l1 = 0, l2 = 0, l3 = 0; var v0 = p0.Normalized(ref l0); var v1 = p1.Normalized(ref l1); var v2 = p2.Normalized(ref l2); var v3 = p3.Normalized(ref l3); var vc = (v0 + v1 + v2 + v3) * 0.25; var deformedCorners = new Matrix4x4d(v0.x * R - vc.x * R, v1.x * R - vc.x * R, v2.x * R - vc.x * R, v3.x * R - vc.x * R, v0.y * R - vc.y * R, v1.y * R - vc.y * R, v2.y * R - vc.y * R, v3.y * R - vc.y * R, v0.z * R - vc.z * R, v1.z * R - vc.z * R, v2.z * R - vc.z * R, v3.z * R - vc.z * R, 1.0, 1.0, 1.0, 1.0); var deformedVerticals = new Matrix4x4d(v0.x, v1.x, v2.x, v3.x, v0.y, v1.y, v2.y, v3.y, v0.z, v1.z, v2.z, v3.z, 0.0, 0.0, 0.0, 0.0); var uz = pc.Normalized(); var ux = new Vector3d(0.0, 1.0, 0.0).Cross(uz).Normalized(); var uy = uz.Cross(ux); var worldToTangentFrame = new Matrix4x4d(ux.x, ux.y, ux.z, 0.0, uy.x, uy.y, uy.z, 0.0, uz.x, uz.y, uz.z, 0.0, 0.0, 0.0, 0.0, 0.0); NormalsMaterial.SetMatrix("_PatchCorners", deformedCorners.ToMatrix4x4()); NormalsMaterial.SetMatrix("_PatchVerticals", deformedVerticals.ToMatrix4x4()); NormalsMaterial.SetVector("_PatchCornerNorms", new Vector4((float)l0, (float)l1, (float)l2, (float)l3)); NormalsMaterial.SetVector("_Deform", new Vector4((float)x0, (float)y0, (float)D / (float)(1 << level), (float)R)); NormalsMaterial.SetMatrix("_WorldToTangentFrame", worldToTangentFrame.ToMatrix4x4()); } else { var D = TerrainNode.TerrainQuadRoot.Length; var R = D / 2.0; var x0 = (double)tx / (double)(1 << level) * D - R; var y0 = (double)ty / (double)(1 << level) * D - R; NormalsMaterial.SetVector("_Deform", new Vector4((float)x0, (float)y0, (float)D / (float)(1 << level), 0.0f)); NormalsMaterial.SetMatrix("_WorldToTangentFrame", Matrix4x4.identity); } NormalsMaterial.SetVector("_TileSD", new Vector2((float)tileWidth, (float)(tileWidth - 1) / (float)(TerrainNode.Body.GridResolution - 1))); NormalsMaterial.SetTexture("_ElevationSampler", elevationTex); NormalsMaterial.SetVector("_ElevationOSL", elevationOSL); Graphics.Blit(null, gpuSlot.Texture, NormalsMaterial); base.DoCreateTile(level, tx, ty, slot); }
public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot) { var gpuSlot = slot[0] as GPUTileStorage.GPUSlot; if (gpuSlot == null) { throw new NullReferenceException("gpuSlot"); } var tileWidth = gpuSlot.Owner.TileSize; var tileSize = tileWidth - (1 + GetBorder() * 2); var rootQuadSize = TerrainNode.TerrainQuadRoot.Length; if (ResidualProducer != null) { if (ResidualProducer.HasTile(level, tx, ty)) { GPUTileStorage.GPUSlot residualGpuSlot = null; var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true); if (residualTile != null) { residualGpuSlot = residualTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find residual tile failed"); } if (residualGpuSlot == null) { throw new MissingTileException("Find parent tile failed"); } ElevationMaterial.SetTexture("_ResidualSampler", residualGpuSlot.Texture); ElevationMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f)); } else { ElevationMaterial.SetTexture("_ResidualSampler", null); ElevationMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); Debug.LogError(string.Format("Residual producer exist, but can't find any suitable tile at {0}:{1}:{2}!", level, tx, ty)); } } else { ElevationMaterial.SetTexture("_ResidualSampler", null); ElevationMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } var tileWSD = Vector4.zero; tileWSD.x = (float)tileWidth; tileWSD.y = (float)rootQuadSize / (float)(1 << level) / (float)tileSize; tileWSD.z = (float)tileSize / (float)(TerrainNode.ParentBody.GridResolution - 1); tileWSD.w = 0.0f; var tileSD = Vector2d.zero; tileSD.x = (0.5 + (float)GetBorder()) / (tileWSD.x - 1 - (float)GetBorder() * 2); tileSD.y = (1.0 + tileSD.x * 2.0); var offset = Vector4d.zero; offset.x = ((double)tx / (1 << level) - 0.5) * rootQuadSize; offset.y = ((double)ty / (1 << level) - 0.5) * rootQuadSize; offset.z = rootQuadSize / (1 << level); offset.w = TerrainNode.ParentBody.Size; ElevationMaterial.SetVector("_TileWSD", tileWSD); ElevationMaterial.SetVector("_TileSD", tileSD.ToVector2()); ElevationMaterial.SetFloat("_Amplitude", TerrainNode.ParentBody.Amplitude); ElevationMaterial.SetFloat("_Frequency", TerrainNode.ParentBody.Frequency); ElevationMaterial.SetVector("_Offset", offset.ToVector4()); ElevationMaterial.SetMatrix("_LocalToWorld", TerrainNode.FaceToLocal.ToMatrix4x4()); if (TerrainNode.ParentBody.TCCPS != null) { TerrainNode.ParentBody.TCCPS.SetUniforms(ElevationMaterial); } Graphics.Blit(null, gpuSlot.Texture, ElevationMaterial); base.DoCreateTile(level, tx, ty, slot); }
/// <summary> /// This function creates the elevations data and is called by the <see cref="Tile.Tasks.CreateTileTask"/> when the task is run by the <see cref="Utilities.Schedular"/>. /// The functions needs the tiles parent data to have already been created. If it has not the program will abort. /// </summary> /// <param name="level"></param> /// <param name="tx"></param> /// <param name="ty"></param> /// <param name="slot"></param> public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot) { var gpuSlot = slot[0] as GPUTileStorage.GPUSlot; if (gpuSlot == null) { throw new NullReferenceException("gpuSlot"); } var tileWidth = gpuSlot.Owner.TileSize; var tileSize = tileWidth - (1 + GetBorder() * 2); GPUTileStorage.GPUSlot parentGpuSlot = null; var upsample = level > 0; var parentTile = FindTile(level - 1, tx / 2, ty / 2, false, true); if (ResidualProducer != null) { if (ResidualProducer.HasTile(level, tx, ty)) { GPUTileStorage.GPUSlot residualGpuSlot = null; var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true); if (residualTile != null) { residualGpuSlot = residualTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find residual tile failed"); } if (residualGpuSlot == null) { throw new MissingTileException("Find parent tile failed"); } UpSampleMaterial.SetTexture("_ResidualSampler", residualGpuSlot.Texture); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f)); } else { UpSampleMaterial.SetTexture("_ResidualSampler", null); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); Debug.LogError(string.Format("Residual producer exist, but can't find any suitable tile at {0}:{1}:{2}!", level, tx, ty)); } } else { UpSampleMaterial.SetTexture("_ResidualSampler", null); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } if (upsample) { if (parentTile != null) { parentGpuSlot = parentTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find parent tile failed"); } } if (parentGpuSlot == null && upsample) { throw new NullReferenceException("parentGpuSlot"); } var rootQuadSize = TerrainNode.TerrainQuadRoot.Length; var tileWSD = Vector4.zero; tileWSD.x = (float)tileWidth; tileWSD.y = (float)rootQuadSize / (float)(1 << level) / (float)tileSize; tileWSD.z = (float)tileSize / (float)(TerrainNode.ParentBody.GridResolution - 1); tileWSD.w = 0.0f; var tileSD = Vector2d.zero; tileSD.x = (0.5 + (float)GetBorder()) / (tileWSD.x - 1 - (float)GetBorder() * 2); tileSD.y = (1.0 + tileSD.x * 2.0); UpSampleMaterial.SetVector("_TileWSD", tileWSD); UpSampleMaterial.SetVector("_TileSD", tileSD.ToVector2()); if (upsample) { var parentTexture = parentGpuSlot.Texture; var dx = (float)(tx % 2) * (float)(tileSize / 2.0f); var dy = (float)(ty % 2) * (float)(tileSize / 2.0f); var coarseLevelOSL = new Vector4(dx / (float)parentTexture.width, dy / (float)parentTexture.height, 1.0f / (float)parentTexture.width, 0.0f); UpSampleMaterial.SetTexture("_CoarseLevelSampler", parentTexture); UpSampleMaterial.SetVector("_CoarseLevelOSL", coarseLevelOSL); } else { UpSampleMaterial.SetTexture("_CoarseLevelSampler", null); UpSampleMaterial.SetVector("_CoarseLevelOSL", new Vector4(-1.0f, -1.0f, -1.0f, -1.0f)); } var rs = level < NoiseAmplitudes.Length ? NoiseAmplitudes[level] : 0.0f; rs = rs / AmplitudeDiviner; var offset = Vector4d.zero; offset.x = ((double)tx / (1 << level) - 0.5) * rootQuadSize; offset.y = ((double)ty / (1 << level) - 0.5) * rootQuadSize; offset.z = rootQuadSize / (1 << level); offset.w = TerrainNode.ParentBody.Size; UpSampleMaterial.SetFloat("_Amplitude", rs * 1); UpSampleMaterial.SetFloat("_Frequency", TerrainNode.ParentBody.Frequency * (1 << level)); UpSampleMaterial.SetVector("_Offset", offset.ToVector4()); UpSampleMaterial.SetMatrix("_LocalToWorld", TerrainNode.FaceToLocal.ToMatrix4x4()); if (TerrainNode.ParentBody.TCCPS != null) { TerrainNode.ParentBody.TCCPS.SetUniforms(UpSampleMaterial); } Graphics.Blit(null, gpuSlot.Texture, UpSampleMaterial); base.DoCreateTile(level, tx, ty, slot); }
public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot) { var gpuSlot = slot[0] as GPUTileStorage.GPUSlot; var normalsTile = NormalsProducer.FindTile(level, tx, ty, false, true); var elevationTile = ElevationProducer.FindTile(level, tx, ty, false, true); GPUTileStorage.GPUSlot normalsGpuSlot = null; if (normalsTile != null) { normalsGpuSlot = normalsTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find normals tile failed"); } GPUTileStorage.GPUSlot elevationGpuSlot = null; if (elevationTile != null) { elevationGpuSlot = elevationTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find elevation tile failed"); } if (gpuSlot == null) { throw new NullReferenceException("gpuSlot"); } if (elevationGpuSlot == null) { throw new NullReferenceException("elevationGpuSlot"); } if (normalsGpuSlot == null) { throw new NullReferenceException("normalsGpuSlot"); } var tileWidth = gpuSlot.Owner.TileSize; var normalsTex = normalsGpuSlot.Texture; var elevationTex = elevationGpuSlot.Texture; var normalsOSL = new Vector4(0.25f / (float)normalsTex.width, 0.25f / (float)normalsTex.height, 1.0f / (float)normalsTex.width, 0.0f); var elevationOSL = new Vector4(0.25f / (float)elevationTex.width, 0.25f / (float)elevationTex.height, 1.0f / (float)elevationTex.width, 0.0f); var tileSize = tileWidth - (float)(1 + GetBorder() * 2); var rootQuadSize = TerrainNode.TerrainQuadRoot.Length; var tileWSD = Vector4.zero; tileWSD.x = (float)tileWidth; tileWSD.y = (float)rootQuadSize / (float)(1 << level) / (float)tileSize; tileWSD.z = (float)tileSize / (float)(TerrainNode.ParentBody.GridResolution - 1); tileWSD.w = 0.0f; var tileScreenSize = (0.5 + (float)GetBorder()) / (tileWSD.x - 1 - (float)GetBorder() * 2); var tileSD = new Vector2d(tileScreenSize, 1.0 + tileScreenSize * 2.0); var offset = new Vector4d(((double)tx / (1 << level) - 0.5) * rootQuadSize, ((double)ty / (1 << level) - 0.5) * rootQuadSize, rootQuadSize / (1 << level), TerrainNode.ParentBody.Size); ColorMaterial.SetTexture("_NormalsSampler", normalsTex); ColorMaterial.SetVector("_NormalsOSL", normalsOSL); ColorMaterial.SetTexture("_ElevationSampler", elevationTex); ColorMaterial.SetVector("_ElevationOSL", elevationOSL); ColorMaterial.SetFloat("_Level", level); ColorMaterial.SetVector("_TileWSD", tileWSD); ColorMaterial.SetVector("_TileSD", tileSD.ToVector2()); ColorMaterial.SetVector("_Offset", offset.ToVector4()); ColorMaterial.SetMatrix("_LocalToWorld", TerrainNode.FaceToLocal.ToMatrix4x4()); if (TerrainNode.ParentBody.TCCPS != null) { TerrainNode.ParentBody.TCCPS.SetUniforms(ColorMaterial); } if (TerrainNode.ParentBody.TCCPS != null) { TerrainNode.ParentBody.TCCPS.ToggleKeywords(ColorMaterial); } Graphics.Blit(null, gpuSlot.Texture, ColorMaterial); base.DoCreateTile(level, tx, ty, slot); }
/// <summary> /// This function creates the elevations data and is called by the <see cref="Tile.Tasks.CreateTileTask"/> when the task is run by the <see cref="Utilities.Schedular"/>. /// The functions needs the tiles parent data to have already been created. If it has not the program will abort. /// </summary> /// <param name="level"></param> /// <param name="tx"></param> /// <param name="ty"></param> /// <param name="slot"></param> public override void DoCreateTile(int level, int tx, int ty, List <TileStorage.Slot> slot) { var gpuSlot = slot[0] as GPUTileStorage.GPUSlot; if (gpuSlot == null) { throw new NullReferenceException("gpuSlot"); } var tileWidth = gpuSlot.Owner.TileSize; var tileSize = tileWidth - (1 + GetBorder() * 2); GPUTileStorage.GPUSlot parentGpuSlot = null; var upsample = level > 0; var parentTile = FindTile(level - 1, tx / 2, ty / 2, false, true); // TODO : Make it classwide... var residualTileSize = GetTileSize(0); var residualTexture = RTExtensions.CreateRTexture(residualTileSize, 0, RenderTextureFormat.RFloat, FilterMode.Point, TextureWrapMode.Clamp); var residualBuffer = new ComputeBuffer(residualTileSize * residualTileSize, sizeof(float)); if (ResidualProducer != null) { if (ResidualProducer.HasTile(level, tx, ty)) { if (ResidualProducer.IsGPUProducer) { GPUTileStorage.GPUSlot residualGpuSlot = null; var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true); if (residualTile != null) { residualGpuSlot = residualTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException("Find residual tile failed"); } if (residualGpuSlot == null) { throw new MissingTileException("Find parent tile failed"); } UpSampleMaterial.SetTexture("_ResidualSampler", residualGpuSlot.Texture); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f)); } else { CPUTileStorage.CPUSlot <float> residualCPUSlot = null; var residualTile = ResidualProducer.FindTile(level, tx, ty, false, true); if (residualTile != null) { residualCPUSlot = residualTile.GetSlot(0) as CPUTileStorage.CPUSlot <float>; } else { throw new MissingTileException("Find residual tile failed"); } if (residualCPUSlot == null) { throw new MissingTileException("Find parent tile failed"); } residualBuffer.SetData(residualCPUSlot.Data); RTUtility.ClearColor(residualTexture); CBUtility.WriteIntoRenderTexture(residualTexture, CBUtility.Channels.R, residualBuffer, GodManager.Instance.WriteData); //RTUtility.SaveAs8bit(residualTileSize, residualTileSize, CBUtility.Channels.R, string.Format("Residual_{0}_{1}-{2}-{3}", TerrainNode.name, level, tx, ty), "/Resources/Preprocess/Textures/Debug/", residualCPUSlot.Data); UpSampleMaterial.SetTexture("_ResidualSampler", residualTexture); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.25f / (float)tileWidth, 0.25f / (float)tileWidth, 2.0f / (float)tileWidth, 1.0f)); } } else { UpSampleMaterial.SetTexture("_ResidualSampler", null); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } } else { UpSampleMaterial.SetTexture("_ResidualSampler", null); UpSampleMaterial.SetVector("_ResidualOSH", new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } if (upsample) { if (parentTile != null) { parentGpuSlot = parentTile.GetSlot(0) as GPUTileStorage.GPUSlot; } else { throw new MissingTileException(string.Format("Find parent tile failed! {0}:{1}-{2}", level - 1, tx / 2, ty / 2)); } } if (parentGpuSlot == null && upsample) { throw new NullReferenceException("parentGpuSlot"); } var rootQuadSize = TerrainNode.TerrainQuadRoot.Length; var tileWSD = Vector4.zero; tileWSD.x = (float)tileWidth; tileWSD.y = (float)rootQuadSize / (float)(1 << level) / (float)tileSize; tileWSD.z = (float)tileSize / (float)(TerrainNode.ParentBody.GridResolution - 1); tileWSD.w = 0.0f; var tileScreenSize = (0.5 + (float)GetBorder()) / (tileWSD.x - 1 - (float)GetBorder() * 2); var tileSD = new Vector2d(tileScreenSize, 1.0 + tileScreenSize * 2.0); UpSampleMaterial.SetVector("_TileWSD", tileWSD); UpSampleMaterial.SetVector("_TileSD", tileSD.ToVector2()); if (upsample) { var parentTexture = parentGpuSlot.Texture; var dx = (float)(tx % 2) * (float)(tileSize / 2.0f); var dy = (float)(ty % 2) * (float)(tileSize / 2.0f); var coarseLevelOSL = new Vector4(dx / (float)parentTexture.width, dy / (float)parentTexture.height, 1.0f / (float)parentTexture.width, 0.0f); UpSampleMaterial.SetTexture("_CoarseLevelSampler", parentTexture); UpSampleMaterial.SetVector("_CoarseLevelOSL", coarseLevelOSL); } else { UpSampleMaterial.SetTexture("_CoarseLevelSampler", null); UpSampleMaterial.SetVector("_CoarseLevelOSL", new Vector4(-1.0f, -1.0f, -1.0f, -1.0f)); } var rs = level < NoiseAmplitudes.Length ? NoiseAmplitudes[level] : 0.0f; var offset = new Vector4d(((double)tx / (1 << level) - 0.5) * rootQuadSize, ((double)ty / (1 << level) - 0.5) * rootQuadSize, rootQuadSize / (1 << level), TerrainNode.ParentBody.Size); UpSampleMaterial.SetFloat("_Amplitude", rs / (TerrainNode.ParentBody.Amplitude / 10.0f)); UpSampleMaterial.SetFloat("_Frequency", TerrainNode.ParentBody.Frequency * (1 << level)); UpSampleMaterial.SetVector("_Offset", offset.ToVector4()); UpSampleMaterial.SetMatrix("_LocalToWorld", TerrainNode.FaceToLocal.ToMatrix4x4()); if (TerrainNode.ParentBody.TCCPS != null) { TerrainNode.ParentBody.TCCPS.SetUniforms(UpSampleMaterial); } Graphics.Blit(null, gpuSlot.Texture, UpSampleMaterial); residualTexture.ReleaseAndDestroy(); residualBuffer.ReleaseAndDisposeBuffer(); base.DoCreateTile(level, tx, ty, slot); }