コード例 #1
0
ファイル: TextureLayer.cs プロジェクト: zameran/SpaceW
        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);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        /// <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);
        }
コード例 #5
0
ファイル: ColorCoreProducer.cs プロジェクト: zameran/SpaceW
        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);
        }
コード例 #6
0
        /// <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);
        }