protected override void Awake() { base.Awake(); int tileSize = TileSize; int capacity = Capacity; for (int i = 0; i < capacity; i++) { RenderTexture texture = new RenderTexture(tileSize, tileSize, 0, m_internalFormat, m_readWrite); texture.filterMode = m_filterMode; texture.wrapMode = m_wrapMode; texture.useMipMap = m_mipmaps; texture.enableRandomWrite = m_enableRandomWrite; GPUSlot slot = new GPUSlot(this, texture); AddSlot(i, slot); } }
/// <summary> /// Sets the uniforms necessary to access the texture tile for the given quad. /// The samplers producer must be using a GPUTileStorage at the first slot /// for this function to work /// </summary> private void SetTile(ref RenderTexture tex, ref Vector3 coord, ref Vector3 size, int level, int tx, int ty) { if (!Producer.IsGPUProducer) { return; } Tile t = null; int b = Producer.Border; int s = Producer.Cache.GetStorage(0).TileSize; float dx = 0; float dy = 0; float dd = 1; float ds0 = (s / 2) * 2.0f - 2.0f * b; float ds = ds0; if (!Producer.HasTile(level, tx, ty)) { throw new MissingTileException("Producer should have tile."); } QuadTree tt = m_root; QuadTree tc; int tl = 0; while (tl != level && (tc = tt.Children[((tx >> (level - tl - 1)) & 1) | ((ty >> (level - tl - 1)) & 1) << 1]) != null) { tl += 1; tt = tc; } t = tt.Tile; dx = dx * ((s / 2) * 2 - 2 * b) / dd; dy = dy * ((s / 2) * 2 - 2 * b) / dd; if (t == null) { throw new NullReferenceException("tile is null"); } GPUSlot gpuSlot = t.GetSlot(0) as GPUSlot; if (gpuSlot == null) { throw new NullReferenceException("gpuSlot is null"); } float w = gpuSlot.Texture.width; float h = gpuSlot.Texture.height; Vector4 coords; if (s % 2 == 0) { coords = new Vector4((dx + b) / w, (dy + b) / h, 0.0f, ds / w); } else { coords = new Vector4((dx + b + 0.5f) / w, (dy + b + 0.5f) / h, 0.0f, ds / w); } tex = gpuSlot.Texture; coord = new Vector3(coords.x, coords.y, coords.z); size = new Vector3(coords.w, coords.w, (s / 2) * 2.0f - 2.0f * b); }
public override void DoCreateTile(int level, int tx, int ty, List <Slot> slot) { GPUSlot gpuSlot = slot[0] as GPUSlot; Tile elevationTile = m_elevationProducer.FindTile(level, tx, ty, false, true); GPUSlot elevationGpuSlot = null; if (elevationTile != null) { elevationGpuSlot = elevationTile.GetSlot(0) as GPUSlot; } else { throw new MissingTileException("Find elevation tile failed"); } int tileWidth = gpuSlot.Owner.TileSize; m_normalsMat.SetVector(m_uniforms.tileSD, new Vector2(tileWidth, (tileWidth - 1.0f) / (World.GridResolution - 1.0f))); RenderTexture elevationTex = elevationGpuSlot.Texture; m_normalsMat.SetTexture(m_uniforms.elevationSampler, elevationTex); Vector4 elevationOSL = new Vector4(0.25f / elevationTex.width, 0.25f / elevationTex.height, 1.0f / elevationTex.width, 0.0f); m_normalsMat.SetVector(m_uniforms.elevationOSL, elevationOSL); if (World.IsDeformed) { double D = TerrainNode.Root.Length; double R = D / 2.0; double len = 1 << level; double x0 = tx / len * D - R; double x1 = (tx + 1) / len * D - R; double y0 = ty / len * D - R; double y1 = (ty + 1) / len * D - R; Vector3d p0 = new Vector3d(x0, y0, R); Vector3d p1 = new Vector3d(x1, y0, R); Vector3d p2 = new Vector3d(x0, y1, R); Vector3d p3 = new Vector3d(x1, y1, R); Vector3d pc = new Vector3d((x0 + x1) * 0.5, (y0 + y1) * 0.5, R); double l0 = p0.Magnitude; double l1 = p1.Magnitude; double l2 = p2.Magnitude; double l3 = p3.Magnitude; Vector3d v0 = p0.Normalized; Vector3d v1 = p1.Normalized; Vector3d v2 = p2.Normalized; Vector3d v3 = p3.Normalized; Vector3d vc = (v0 + v1 + v2 + v3) * 0.25; Matrix4x4d 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); Matrix4x4d 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); Vector3d uz = pc.Normalized; Vector3d ux = (new Vector3d(0, 1, 0)).Cross(uz).Normalized; Vector3d uy = uz.Cross(ux); Matrix4x4d 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); m_normalsMat.SetMatrix(m_uniforms.patchCorners, MathConverter.ToMatrix4x4(deformedCorners)); m_normalsMat.SetMatrix(m_uniforms.patchVerticals, MathConverter.ToMatrix4x4(deformedVerticals)); m_normalsMat.SetVector(m_uniforms.patchCornerNorms, new Vector4((float)l0, (float)l1, (float)l2, (float)l3)); m_normalsMat.SetVector(m_uniforms.deform, new Vector4((float)x0, (float)y0, (float)(D / len), (float)R)); m_normalsMat.SetMatrix(m_uniforms.worldToTangentFrame, MathConverter.ToMatrix4x4(worldToTangentFrame)); } else { double D = TerrainNode.Root.Length; double R = D / 2.0; double len = 1 << level; double x0 = tx / len * D - R; double y0 = ty / len * D - R; m_normalsMat.SetMatrix(m_uniforms.worldToTangentFrame, Matrix4x4.identity); m_normalsMat.SetVector(m_uniforms.deform, new Vector4((float)x0, (float)y0, (float)(D / len), 0.0f)); } Graphics.Blit(null, gpuSlot.Texture, m_normalsMat); base.DoCreateTile(level, tx, ty, slot); }
public override void DoCreateTile(int level, int tx, int ty, List <Slot> slot) { GPUSlot gpuSlot = slot[0] as GPUSlot; int tileWidth = gpuSlot.Owner.TileSize; int tileSize = tileWidth - 4; GPUSlot parentGpuSlot = null; Tile parentTile = null; if (level > 0) { parentTile = FindTile(level - 1, tx / 2, ty / 2, false, true); if (parentTile != null) { parentGpuSlot = parentTile.GetSlot(0) as GPUSlot; } else { throw new MissingTileException("Find parent tile failed"); } } m_upsampleMat.SetFloat(m_uniforms.tileWidth, tileWidth); if (level > 0) { RenderTexture tex = parentGpuSlot.Texture; m_upsampleMat.SetTexture(m_uniforms.coarseLevelSampler, tex); float dx = (tx % 2) * (tileSize / 2); float dy = (ty % 2) * (tileSize / 2); Vector4 coarseLevelOSL = new Vector4((dx + 0.5f) / tex.width, (dy + 0.5f) / tex.height, 1.0f / tex.width, 0.0f); m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, coarseLevelOSL); } else { m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, new Vector4(-1.0f, -1.0f, -1.0f, -1.0f)); } if (m_orthoCPUProducer != null && m_orthoCPUProducer.HasTile(level, tx, ty)) { Tile orthoCPUTile = m_orthoCPUProducer.FindTile(level, tx, ty, false, true); CPUSlot <byte> orthoCPUSlot = null; if (orthoCPUTile != null) { orthoCPUSlot = orthoCPUTile.GetSlot(0) as CPUSlot <byte>; } else { throw new MissingTileException("Find orthoCPU tile failed"); } int c = m_orthoCPUProducer.Channels; Color32 col = new Color32(); byte[] data = orthoCPUSlot.Data; for (int x = 0; x < tileWidth; x++) { for (int y = 0; y < tileWidth; y++) { col.r = data[(x + y * tileWidth) * c]; if (c > 1) { col.g = data[(x + y * tileWidth) * c + 1]; } if (c > 2) { col.b = data[(x + y * tileWidth) * c + 2]; } if (c > 3) { col.a = data[(x + y * tileWidth) * c + 3]; } m_residueTex.SetPixel(x, y, col); } } m_residueTex.Apply(); m_upsampleMat.SetTexture(m_uniforms.residualSampler, m_residueTex); m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.5f / tileWidth, 0.5f / tileWidth, 1.0f / tileWidth, 0.0f)); } else { m_upsampleMat.SetTexture(m_uniforms.residualSampler, null); m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(-1, -1, -1, -1)); } float rs = level < m_noiseAmp.Length ? m_noiseAmp[level] : 0.0f; int noiseL = 0; int face = TerrainNode.Face; if (rs != 0.0f) { if (face == 1) { int offset = 1 << level; int bottomB = m_noise.Noise2D(tx + 0.5f, ty + offset) > 0.0f ? 1 : 0; int rightB = (tx == offset - 1 ? m_noise.Noise2D(ty + offset + 0.5f, offset) : m_noise.Noise2D(tx + 1.0f, ty + offset + 0.5f)) > 0.0f ? 2 : 0; int topB = (ty == offset - 1 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, offset) : m_noise.Noise2D(tx + 0.5f, ty + offset + 1.0f)) > 0.0f ? 4 : 0; int leftB = (tx == 0 ? m_noise.Noise2D((4.0f * offset - 1.0f - ty) + 0.5f, offset) : m_noise.Noise2D(tx, ty + offset + 0.5f)) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } else if (face == 6) { int offset = 1 << level; int bottomB = (ty == 0 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, 0) : m_noise.Noise2D(tx + 0.5f, ty - offset)) > 0.0f ? 1 : 0; int rightB = (tx == offset - 1.0f ? m_noise.Noise2D((2.0f * offset - 1.0f - ty) + 0.5f, 0) : m_noise.Noise2D(tx + 1.0f, ty - offset + 0.5f)) > 0.0f ? 2 : 0; int topB = m_noise.Noise2D(tx + 0.5f, ty - offset + 1.0f) > 0.0f ? 4 : 0; int leftB = (tx == 0 ? m_noise.Noise2D(3.0f * offset + ty + 0.5f, 0) : m_noise.Noise2D(tx, ty - offset + 0.5f)) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } else { int offset = (1 << level) * (face - 2); int bottomB = m_noise.Noise2D(tx + offset + 0.5f, ty) > 0.0f ? 1 : 0; int rightB = m_noise.Noise2D((tx + offset + 1) % (4 << level), ty + 0.5f) > 0.0f ? 2 : 0; int topB = m_noise.Noise2D(tx + offset + 0.5f, ty + 1.0f) > 0.0f ? 4 : 0; int leftB = m_noise.Noise2D(tx + offset, ty + 0.5f) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } } int[] noiseRs = new int[] { 0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 1, 3, 2, 2, 1, 0 }; int noiseR = noiseRs[noiseL]; int[] noiseLs = new int[] { 0, 1, 1, 2, 1, 3, 2, 4, 1, 2, 3, 4, 2, 4, 4, 5 }; noiseL = noiseLs[noiseL]; m_upsampleMat.SetTexture(m_uniforms.noiseSampler, m_noiseTextures[noiseL]); m_upsampleMat.SetVector(m_uniforms.noiseUVLH, new Vector4(noiseR, (noiseR + 1) % 4, 0.0f, m_hsv ? 1.0f : 0.0f)); if (m_hsv) { Vector4 col = m_noiseColor * rs / 255.0f; col.w *= 2.0f; m_upsampleMat.SetVector(m_uniforms.noiseColor, col); } else { Vector4 col = m_noiseColor * rs * 2.0f / 255.0f; col.w *= 2.0f; m_upsampleMat.SetVector(m_uniforms.noiseColor, col); } m_upsampleMat.SetVector(m_uniforms.noiseRootColor, m_rootNoiseColor); Graphics.Blit(null, gpuSlot.Texture, m_upsampleMat); base.DoCreateTile(level, tx, ty, slot); }
/// <summary> /// This function creates the elevations data and is called by the CreateTileTask when the task is run by the schedular /// The functions needs the tiles parent data to have already been created. If it has not the program will abort. /// </summary> public override void DoCreateTile(int level, int tx, int ty, List <Slot> slot) { GPUSlot gpuSlot = slot[0] as GPUSlot; int tileWidth = gpuSlot.Owner.TileSize; int b = Border * 2 + 1; int tileSize = tileWidth - b; GPUSlot parentGpuSlot = null; Tile parentTile = null; if (level > 0) { parentTile = FindTile(level - 1, tx / 2, ty / 2, false, true); if (parentTile != null) { parentGpuSlot = parentTile.GetSlot(0) as GPUSlot; } else { throw new MissingTileException("Find parent tile failed"); } } float rootQuadSize = (float)TerrainNode.Root.Length; Vector4 tileWSD = new Vector4(); tileWSD.x = tileWidth; tileWSD.y = rootQuadSize / (1 << level) / tileSize; tileWSD.z = (tileWidth - b) / (World.GridResolution - 1.0f); tileWSD.w = 0.0f; m_upsampleMat.SetVector(m_uniforms.tileWSD, tileWSD); if (level > 0) { RenderTexture tex = parentGpuSlot.Texture; m_upsampleMat.SetTexture(m_uniforms.coarseLevelSampler, tex); float dx = (tx % 2) * (tileSize / 2); float dy = (ty % 2) * (tileSize / 2); Vector4 coarseLevelOSL = new Vector4(dx / tex.width, dy / tex.height, 1.0f / tex.width, 0.0f); m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, coarseLevelOSL); } else { m_upsampleMat.SetVector(m_uniforms.coarseLevelOSL, new Vector4(-1.0f, -1.0f, -1.0f, -1.0f)); } if (m_residualProducer != null && m_residualProducer.HasTile(level, tx, ty)) { Tile residualTile = m_residualProducer.FindTile(level, tx, ty, false, true); CPUSlot <float> residualSlot = null; if (residualTile != null) { residualSlot = residualTile.GetSlot(0) as CPUSlot <float>; } else { throw new MissingTileException("Find residual tile failed"); } //Must clear residual tex before use or terrain will have artifacts at the seams. Not sure why. RTUtility.ClearColor(m_residualTex, Color.clear); m_residualBuffer.SetData(residualSlot.Data); CBUtility.WriteIntoRenderTexture(m_residualTex, 1, m_residualBuffer, World.WriteData); m_upsampleMat.SetTexture(m_uniforms.residualSampler, m_residualTex); m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.25f / tileWidth, 0.25f / tileWidth, 2.0f / tileWidth, 1.0f)); } else { m_upsampleMat.SetTexture(m_uniforms.residualSampler, null); m_upsampleMat.SetVector(m_uniforms.residualOSH, new Vector4(0.0f, 0.0f, 1.0f, 0.0f)); } float rs = level < m_noiseAmp.Length ? m_noiseAmp[level] : 0.0f; int noiseL = 0; int face = TerrainNode.Face; if (rs != 0.0f) { if (face == 1) { int offset = 1 << level; int bottomB = m_noise.Noise2D(tx + 0.5f, ty + offset) > 0.0f ? 1 : 0; int rightB = (tx == offset - 1 ? m_noise.Noise2D(ty + offset + 0.5f, offset) : m_noise.Noise2D(tx + 1.0f, ty + offset + 0.5f)) > 0.0f ? 2 : 0; int topB = (ty == offset - 1 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, offset) : m_noise.Noise2D(tx + 0.5f, ty + offset + 1.0f)) > 0.0f ? 4 : 0; int leftB = (tx == 0 ? m_noise.Noise2D((4.0f * offset - 1.0f - ty) + 0.5f, offset) : m_noise.Noise2D(tx, ty + offset + 0.5f)) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } else if (face == 6) { int offset = 1 << level; int bottomB = (ty == 0 ? m_noise.Noise2D((3.0f * offset - 1.0f - tx) + 0.5f, 0) : m_noise.Noise2D(tx + 0.5f, ty - offset)) > 0.0f ? 1 : 0; int rightB = (tx == offset - 1.0f ? m_noise.Noise2D((2.0f * offset - 1.0f - ty) + 0.5f, 0) : m_noise.Noise2D(tx + 1.0f, ty - offset + 0.5f)) > 0.0f ? 2 : 0; int topB = m_noise.Noise2D(tx + 0.5f, ty - offset + 1.0f) > 0.0f ? 4 : 0; int leftB = (tx == 0 ? m_noise.Noise2D(3.0f * offset + ty + 0.5f, 0) : m_noise.Noise2D(tx, ty - offset + 0.5f)) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } else { int offset = (1 << level) * (face - 2); int bottomB = m_noise.Noise2D(tx + offset + 0.5f, ty) > 0.0f ? 1 : 0; int rightB = m_noise.Noise2D((tx + offset + 1) % (4 << level), ty + 0.5f) > 0.0f ? 2 : 0; int topB = m_noise.Noise2D(tx + offset + 0.5f, ty + 1.0f) > 0.0f ? 4 : 0; int leftB = m_noise.Noise2D(tx + offset, ty + 0.5f) > 0.0f ? 8 : 0; noiseL = bottomB + rightB + topB + leftB; } } int[] noiseRs = new int[] { 0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 1, 3, 2, 2, 1, 0 }; int noiseR = noiseRs[noiseL]; int[] noiseLs = new int[] { 0, 1, 1, 2, 1, 3, 2, 4, 1, 2, 3, 4, 2, 4, 4, 5 }; noiseL = noiseLs[noiseL]; m_upsampleMat.SetTexture(m_uniforms.noiseSampler, m_noiseTextures[noiseL]); m_upsampleMat.SetVector(m_uniforms.noiseUVLH, new Vector4(noiseR, (noiseR + 1) % 4, 0, rs)); Graphics.Blit(null, gpuSlot.Texture, m_upsampleMat); base.DoCreateTile(level, tx, ty, slot); }