コード例 #1
0
        private void CreateRTHandles(Vector2Int dim)
        {
            m_RTSize = dim;

            var r    = RTUtils.GetDescriptorRW(dim.x, dim.y, 0, RenderTextureFormat.RFloat);
            var rg   = RTUtils.GetDescriptorRW(dim.x, dim.y, 0, RenderTextureFormat.RGFloat);
            var argb = RTUtils.GetDescriptorRW(dim.x, dim.y, 0, RenderTextureFormat.ARGBFloat);

            for (int i = 0; i < 2; i++)
            {
                m_HeightmapRT[i] = RTUtils.GetNewHandle(r).WithName("HydroErosion_Height" + i);
                m_WaterRT[i]     = RTUtils.GetNewHandle(r).WithName("HydroErosion_Water" + i);
                m_WaterVelRT[i]  = RTUtils.GetNewHandle(rg).WithName("HydroErosion_WaterVel" + i);
                m_FluxRT[i]      = RTUtils.GetNewHandle(argb).WithName("HydroErosion_Flux" + i);
                m_SedimentRT[i]  = RTUtils.GetNewHandle(r).WithName("HydroErosion_Sediment" + i);

                m_HeightmapRT[i].RT.Create();
                m_WaterRT[i].RT.Create();
                m_WaterVelRT[i].RT.Create();
                m_FluxRT[i].RT.Create();
                m_SedimentRT[i].RT.Create();
            }

            m_ErodedRT = RTUtils.GetNewHandle(r).WithName("HydroErosion_Eroded");
            m_ErodedRT.RT.Create();

            m_HardnessRT = RTUtils.GetNewHandle(r).WithName("HydroErosion_Hardness");
            m_HardnessRT.RT.Create();
        }
コード例 #2
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            commonUI.OnPaint(terrain, editContext);

            if (!commonUI.allowPaint)
            {
                return(true);
            }

            Vector2 uv = editContext.uv;

            if (commonUI.ScatterBrushStamp(ref terrain, ref uv))
            {
                using (IBrushRenderUnderCursor brushRender = new BrushRenderUIGroupUnderCursor(commonUI, "WindErosion", editContext.brushTexture))
                {
                    if (brushRender.CalculateBrushTransform(out BrushTransform brushXform))
                    {
                        var          brushBounds  = brushXform.GetBrushXYBounds();
                        PaintContext paintContext = brushRender.AcquireHeightmap(true, brushBounds, 4);
                        paintContext.sourceRenderTexture.filterMode = FilterMode.Bilinear;

                        //paintContext.sourceRenderTexture = input heightmap
                        //Add Velocity (user wind direction and strength, or texture input, noise, forces, drag etc...)
                        float angle = commonUI.brushRotation; //m_WindAngleDegrees + r;
                        float r     = 0.5f * (2.0f * UnityEngine.Random.value - 1.0f) * 0.01f * m_Eroder.m_WindSpeedJitter;
                        float speed = m_Eroder.m_WindSpeed.value + r;

                        float rad = angle * Mathf.Deg2Rad;
                        m_Eroder.m_WindVel = speed * (new Vector4(-Mathf.Sin(rad), Mathf.Cos(rad), 0.0f, 0.0f));
                        m_Eroder.inputTextures["Height"] = paintContext.sourceRenderTexture;

                        var     heightRT  = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW((int)brushBounds.width, (int)brushBounds.height, 0, RenderTextureFormat.RFloat));
                        Vector2 texelSize = new Vector2(terrain.terrainData.size.x / terrain.terrainData.heightmapResolution,
                                                        terrain.terrainData.size.z / terrain.terrainData.heightmapResolution);
                        m_Eroder.ErodeHeightmap(heightRT, terrain.terrainData.size, brushBounds, texelSize);

                        //Blit the result onto the new height map
                        Material mat       = GetPaintMaterial();
                        var      brushMask = RTUtils.GetTempHandle(paintContext.sourceRenderTexture.width, paintContext.sourceRenderTexture.height, 0, FilterUtility.defaultFormat);
                        Utility.SetFilterRT(commonUI, paintContext.sourceRenderTexture, brushMask, mat);
                        Vector4 brushParams = new Vector4(commonUI.brushStrength, 0.0f, 0.0f, 0.0f);
                        mat.SetTexture("_BrushTex", editContext.brushTexture);
                        mat.SetTexture("_NewHeightTex", heightRT);
                        mat.SetVector("_BrushParams", brushParams);

                        brushRender.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat);
                        brushRender.RenderBrush(paintContext, mat, 0);
                        brushRender.Release(paintContext);
                        RTUtils.Release(brushMask);
                        RTUtils.Release(heightRT);
                    }
                }
            }

            return(true);
        }
コード例 #3
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            commonUI.OnPaint(terrain, editContext);

            if (!commonUI.allowPaint)
            {
                return(false);
            }

            int[] numWorkGroups = { 8, 8, 1 };

            using (IBrushRenderUnderCursor brushRender = new BrushRenderUIGroupUnderCursor(commonUI, "ThermalErosion", editContext.brushTexture))
            {
                if (brushRender.CalculateBrushTransform(out BrushTransform brushXform))
                {
                    PaintContext paintContext = brushRender.AcquireHeightmap(true, brushXform.GetBrushXYBounds(), 1);
                    paintContext.sourceRenderTexture.filterMode = FilterMode.Bilinear;

                    //figure out what size we need our render targets to be
                    Rect brushRect = brushXform.GetBrushXYBounds();

                    m_Eroder.inputTextures["Height"] = paintContext.sourceRenderTexture;

                    var     heightRT  = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW((int)brushRect.width, (int)brushRect.height, 0, RenderTextureFormat.RFloat));
                    Vector2 texelSize = new Vector2(terrain.terrainData.size.x / terrain.terrainData.heightmapResolution,
                                                    terrain.terrainData.size.z / terrain.terrainData.heightmapResolution);
                    m_Eroder.ErodeHeightmap(heightRT, terrain.terrainData.size, brushRect, texelSize);

                    Material mat       = GetPaintMaterial();
                    var      brushMask = RTUtils.GetTempHandle(paintContext.sourceRenderTexture.width, paintContext.sourceRenderTexture.height, 0, FilterUtility.defaultFormat);
                    Utility.SetFilterRT(commonUI, paintContext.sourceRenderTexture, brushMask, mat);
                    Vector4 brushParams = new Vector4(commonUI.brushStrength, 0.0f, 0.0f, 0.0f);
                    mat.SetTexture("_BrushTex", editContext.brushTexture);
                    mat.SetTexture("_NewHeightTex", heightRT);
                    mat.SetVector("_BrushParams", brushParams);

                    brushRender.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat);
                    brushRender.RenderBrush(paintContext, mat, 0);
                    RTUtils.Release(brushMask);
                    RTUtils.Release(heightRT);
                }
            }

            return(true);
        }
コード例 #4
0
        public override bool OnPaint(Terrain terrain, IOnPaint editContext)
        {
            commonUI.OnPaint(terrain, editContext);

            if (!commonUI.allowPaint)
            {
                return(true);
            }

            using (IBrushRenderUnderCursor brushRender = new BrushRenderUIGroupUnderCursor(commonUI, "HydroErosion", editContext.brushTexture))
            {
                if (brushRender.CalculateBrushTransform(out BrushTransform brushXform))
                {
                    var          brushBounds  = brushXform.GetBrushXYBounds();
                    PaintContext paintContext = brushRender.AcquireHeightmap(true, brushBounds, 1);
                    paintContext.sourceRenderTexture.filterMode = FilterMode.Bilinear;

                    m_Eroder.inputTextures["Height"] = paintContext.sourceRenderTexture;

                    var     heightRT  = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW((int)brushBounds.width, (int)brushBounds.height, 0, RenderTextureFormat.RFloat));
                    Vector2 texelSize = new Vector2(terrain.terrainData.size.x / terrain.terrainData.heightmapResolution,
                                                    terrain.terrainData.size.z / terrain.terrainData.heightmapResolution);
                    m_Eroder.ErodeHeightmap(heightRT, terrain.terrainData.size, brushXform.GetBrushXYBounds(), texelSize, Event.current.control); // TODO(wyatt): commonUI.ModifierActive(BrushModifierKey.BRUSH_MOD_INVERT)

                    Material mat       = GetPaintMaterial();
                    var      brushMask = RTUtils.GetTempHandle(paintContext.sourceRenderTexture.width, paintContext.sourceRenderTexture.height, 0, FilterUtility.defaultFormat);
                    Utility.SetFilterRT(commonUI, paintContext.sourceRenderTexture, brushMask, mat);
                    Vector4 brushParams = new Vector4(commonUI.brushStrength, 0.0f, 0.0f, 0.0f);
                    mat.SetTexture("_BrushTex", editContext.brushTexture);
                    mat.SetTexture("_NewHeightTex", heightRT);
                    mat.SetVector("_BrushParams", brushParams);

                    brushRender.SetupTerrainToolMaterialProperties(paintContext, brushXform, mat);
                    brushRender.RenderBrush(paintContext, mat, 0);
                    RTUtils.Release(brushMask);
                    RTUtils.Release(heightRT);
                }
            }

            return(true);
        }
コード例 #5
0
        private void ErodeHelper(RenderTexture dest, Vector3 terrainScale, Rect domainRect, Vector2 texelSize, bool invertEffect, bool lowRes)
        {
            RenderTexture tmpRT = UnityEngine.RenderTexture.active;

            //this one is mandatory
            if (!inputTextures.ContainsKey("Height"))
            {
                throw (new Exception("No input heightfield specified!"));
            }

            //Find Compute Kernels
            ComputeShader advectionCS = GetComputeShader("Advection");
            ComputeShader projectionCS = GetComputeShader("Projection");
            ComputeShader diffusionCS = GetComputeShader("Diffusion");
            ComputeShader utilityCS = GetComputeShader("ImageUtility");
            ComputeShader aeolianCS = GetComputeShader("Aeolian");
            ComputeShader thermalCS = GetComputeShader("Thermal");

            int advectKernelIdx = advectionCS.FindKernel("Advect");
            int divergenceKernelIdx = projectionCS.FindKernel("Divergence");
            int gradientSubtractKernelIdx = projectionCS.FindKernel("GradientSubtract");
            int diffuseKernelIdx = diffusionCS.FindKernel("Diffuse");
            int remapKernelIdx = utilityCS.FindKernel("RemapValues");
            int addConstantIdx = utilityCS.FindKernel("AddConstant");
            int applyDragKernelIdx = aeolianCS.FindKernel("ApplyHeightfieldDrag");
            int erodeKernelIdx = aeolianCS.FindKernel("WindSedimentErode");
            int thermalKernelIdx = thermalCS.FindKernel("ThermalErosion");

            int[] numWorkGroups = { 1, 1, 1 };

            int xRes = (int)inputTextures["Height"].width;
            int yRes = (int)inputTextures["Height"].height;

            var r = RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat);
            var rg = RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RGFloat);

            var heightmapRT = RTUtils.GetTempHandle(r);
            var heightmapPrevRT = RTUtils.GetTempHandle(r);
            var collisionRT = RTUtils.GetTempHandle(r);
            var sedimentPrevRT = RTUtils.GetTempHandle(r);
            var sedimentRT = RTUtils.GetTempHandle(r);
            var windVelRT = RTUtils.GetTempHandle(rg);
            var windVelPrevRT = RTUtils.GetTempHandle(rg);
            var divergenceRT = RTUtils.GetTempHandle(r);
            var thermalSedimentRT = RTUtils.GetTempHandle(r);

            //Setup input textures, clear the render textures
            Graphics.Blit(Texture2D.blackTexture, sedimentRT);
            Graphics.Blit(Texture2D.blackTexture, collisionRT);
            Graphics.Blit(Texture2D.blackTexture, windVelRT);
            Graphics.Blit(Texture2D.blackTexture, windVelPrevRT);

            Graphics.Blit(inputTextures["Height"], heightmapPrevRT);
            Graphics.Blit(inputTextures["Height"], heightmapRT);

            //precompute some values on the CPU (these become uniform constants in the shader)
            float dx = (float)texelSize.x * m_SimulationScale.value;
            float dy = (float)texelSize.y * m_SimulationScale.value;

            float dxy = Mathf.Sqrt(dx * dx + dy * dy);
            Vector4 dxdy = new Vector4(dx, dy, 1.0f / dx, 1.0f / dy); //TODO: make this the same for all compute shaders

            advectionCS.SetFloat("dt", m_dt.value);
            advectionCS.SetFloat("velScale", m_AdvectionVelScale.value);
            advectionCS.SetVector("dxdy", dxdy);
            advectionCS.SetVector("DomainRes", new Vector4((float)xRes, (float)yRes, 1.0f / (float)xRes, 1.0f / (float)yRes));

            diffusionCS.SetFloat("dt", m_dt.value);

            projectionCS.SetVector("dxdy", dxdy);

            aeolianCS.SetFloat("dt", m_dt.value);
            aeolianCS.SetFloat("SuspensionRate", m_SuspensionRate.value);
            aeolianCS.SetFloat("DepositionRate", m_DepositionRate.value);
            aeolianCS.SetFloat("SlopeFactor", m_SlopeFactor.value);
            aeolianCS.SetFloat("DragCoefficient", m_DragCoefficient.value);
            aeolianCS.SetFloat("ReflectionCoefficient", m_ReflectionCoefficient.value);
            aeolianCS.SetFloat("AbrasivenessCoefficient", m_AbrasivenessCoefficient.value * 1000.0f);
            aeolianCS.SetVector("DomainDim", new Vector4((float)xRes, (float)yRes, 0.0f, 0.0f));
            aeolianCS.SetVector("terrainScale", new Vector4(terrainScale.x, terrainScale.y, terrainScale.z, 0.0f));
            aeolianCS.SetVector("dxdy", dxdy);

            //use full tile res here?
            diffusionCS.SetVector("texDim", new Vector4((float)inputTextures["Height"].width, (float)inputTextures["Height"].height, 0.0f, 0.0f));
            for (int i = 0; i < m_Iterations.value; i++)
            {
                //Velocity step
                utilityCS.SetTexture(addConstantIdx, "OutputTex", windVelPrevRT);
                utilityCS.SetVector("Constant", m_WindVel);
                utilityCS.Dispatch(addConstantIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                //Apply drag from heightfield
                aeolianCS.SetTexture(applyDragKernelIdx, "InHeightMap", heightmapPrevRT);
                aeolianCS.SetTexture(applyDragKernelIdx, "WindVel", windVelPrevRT);
                aeolianCS.SetTexture(applyDragKernelIdx, "OutWindVel", windVelRT);
                aeolianCS.Dispatch(applyDragKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                //Diffuse Velocity
                diffusionCS.SetFloat("diff", m_Viscosity.value);
                for (int j = 0; j < m_DiffuseSteps; j++)
                {
                    diffusionCS.SetTexture(diffuseKernelIdx, "InputTex", windVelRT);
                    diffusionCS.SetTexture(diffuseKernelIdx, "OutputTex", windVelPrevRT);

                    diffusionCS.Dispatch(diffuseKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
                    Graphics.Blit(windVelPrevRT, windVelRT);
                }

                //Project Velocity
                for (int j = 0; j < m_ProjectionSteps; j++)
                {
                    projectionCS.SetTexture(divergenceKernelIdx, "VelocityTex2D", windVelRT);
                    projectionCS.SetTexture(divergenceKernelIdx, "DivergenceTex2D", divergenceRT);
                    projectionCS.Dispatch(divergenceKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                    projectionCS.SetTexture(gradientSubtractKernelIdx, "PressureTex2D", divergenceRT);
                    projectionCS.SetTexture(gradientSubtractKernelIdx, "VelocityTex2D", windVelRT);
                    projectionCS.SetTexture(gradientSubtractKernelIdx, "VelocityOutTex2D", windVelPrevRT);
                    projectionCS.Dispatch(gradientSubtractKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                    Graphics.Blit(windVelPrevRT, windVelRT);
                }

                //Advect velocity along previous iteration's velocity field
                advectionCS.SetTexture(advectKernelIdx, "InputTex", windVelRT);
                advectionCS.SetTexture(advectKernelIdx, "OutputTex", windVelPrevRT);
                advectionCS.SetTexture(advectKernelIdx, "VelocityTex", windVelRT);

                advectionCS.Dispatch(advectKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                Graphics.Blit(windVelPrevRT, windVelRT);

                //Density Step
                //Diffuse Sediment
                diffusionCS.SetFloat("diff", m_DiffusionRate.value);
                for (int j = 0; j < m_DiffuseSteps; j++)
                {
                    diffusionCS.SetTexture(diffuseKernelIdx, "InputTex", sedimentRT);
                    diffusionCS.SetTexture(diffuseKernelIdx, "OutputTex", sedimentPrevRT);

                    diffusionCS.Dispatch(diffuseKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
                    Graphics.Blit(sedimentPrevRT, sedimentRT);
                }

                //Advect Sediment
                advectionCS.SetTexture(advectKernelIdx, "InputTexFloat", sedimentRT);
                advectionCS.SetTexture(advectKernelIdx, "OutputTexFloat", sedimentPrevRT);
                advectionCS.SetTexture(advectKernelIdx, "VelocityTex", windVelRT);

                advectionCS.Dispatch(advectKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                //Erosion Step
                //Erode Sediment (pick sediment up off the heightmap and store in sediment RT)
                aeolianCS.SetTexture(erodeKernelIdx, "InHeightMap", heightmapPrevRT);
                aeolianCS.SetTexture(erodeKernelIdx, "InSediment", sedimentPrevRT);
                aeolianCS.SetTexture(erodeKernelIdx, "WindVel", windVelRT);
                aeolianCS.SetTexture(erodeKernelIdx, "OutSediment", sedimentRT);
                aeolianCS.SetTexture(erodeKernelIdx, "OutHeightMap", heightmapRT);
                aeolianCS.Dispatch(erodeKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                //Thermal/Diffusion step
                thermalCS.SetFloat("dt", m_ThermalTimeDelta.value * m_dt.value);
                thermalCS.SetFloat("InvDiagMag", 1.0f / Mathf.Sqrt(dx * dx + dy * dy));
                thermalCS.SetVector("dxdy", new Vector4(dx, dy, 1.0f / dx, 1.0f / dy));
                thermalCS.SetVector("terrainDim", new Vector4(terrainScale.x, terrainScale.y, terrainScale.z));
                thermalCS.SetVector("texDim", new Vector4((float)xRes, (float)yRes, 0.0f, 0.0f));

                thermalCS.SetTexture(thermalKernelIdx, "TerrainHeightPrev", heightmapPrevRT);
                thermalCS.SetTexture(thermalKernelIdx, "TerrainHeight", heightmapRT);
                thermalCS.SetTexture(thermalKernelIdx, "Sediment", thermalSedimentRT);
                thermalCS.SetTexture(thermalKernelIdx, "ReposeMask", collisionRT); //TODO
                thermalCS.SetTexture(thermalKernelIdx, "Collision", collisionRT);
                thermalCS.SetTexture(thermalKernelIdx, "Hardness", collisionRT); //TODO

                Graphics.Blit(heightmapRT, heightmapPrevRT);
                for (int j = 0; j < m_ThermalIterations; j++)
                {
                    Vector2 m = new Vector2(Mathf.Tan(m_AngleOfRepose * Mathf.Deg2Rad), Mathf.Tan(m_AngleOfRepose * Mathf.Deg2Rad));
                    thermalCS.SetVector("angleOfRepose", new Vector4(m.x, m.y, 0.0f, 0.0f));

                    thermalCS.Dispatch(thermalKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);
                    Graphics.Blit(heightmapRT, heightmapPrevRT);
                }

                //swap buffers for next iteration
                //Graphics.Blit(heightmapRT, heightmapPrevRT);
                Graphics.Blit(sedimentRT, sedimentPrevRT);

            }

            Graphics.Blit(heightmapRT, dest);

            RTUtils.Release(heightmapRT);
            RTUtils.Release(heightmapPrevRT);
            RTUtils.Release(collisionRT);
            RTUtils.Release(sedimentRT);
            RTUtils.Release(sedimentPrevRT);
            RTUtils.Release(windVelRT);
            RTUtils.Release(windVelPrevRT);
            RTUtils.Release(divergenceRT);
            RTUtils.Release(thermalSedimentRT);

            UnityEngine.RenderTexture.active = tmpRT;
        }
コード例 #6
0
ファイル: ThermalEroder.cs プロジェクト: Reflex21/Moba
        private void ErodeHelper(Vector3 terrainScale, Rect domainRect, Vector2 texelSize, bool invertEffect, bool lowRes)
        {
            ComputeShader cs     = GetComputeShader();
            RenderTexture prevRT = RenderTexture.active;

            int[] numWorkGroups = { 1, 1, 1 };

            //this one is mandatory
            if (!inputTextures.ContainsKey("Height"))
            {
                throw (new Exception("No input heightfield specified!"));
            }

            //figure out what size we need our render targets to be
            int xRes = (int)inputTextures["Height"].width;
            int yRes = (int)inputTextures["Height"].height;

            /*
             * int rx = xRes - (numWorkGroups[0] * (xRes / numWorkGroups[0]));
             * int ry = yRes - (numWorkGroups[1] * (yRes / numWorkGroups[1]));
             *
             * xRes += numWorkGroups[0] - rx;
             * yRes += numWorkGroups[1] - ry;
             */

            var heightmapRT0 = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat));
            var heightmapRT1 = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat));

            var sedimentRT    = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat));
            var hardnessRT    = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat));
            var reposeAngleRT = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat));
            var collisionRT   = RTUtils.GetTempHandle(RTUtils.GetDescriptorRW(xRes, yRes, 0, RenderTextureFormat.RFloat));

            //clear the render textures (also calls rt.Create())
            Graphics.Blit(inputTextures["Height"], heightmapRT0);
            Graphics.Blit(inputTextures["Height"], heightmapRT1);
            Graphics.Blit(Texture2D.blackTexture, sedimentRT);
            Graphics.Blit(Texture2D.blackTexture, hardnessRT);
            Graphics.Blit(Texture2D.blackTexture, reposeAngleRT);
            Graphics.Blit(Texture2D.blackTexture, collisionRT);

            int thermalKernelIdx = cs.FindKernel("ThermalErosion");

            //precompute some values on the CPU (constants in the shader)
            float dx   = (float)texelSize.x;
            float dy   = (float)texelSize.y;
            float dxdy = Mathf.Sqrt(dx * dx + dy * dy);

            cs.SetFloat("dt", m_dt);
            cs.SetFloat("InvDiagMag", 1.0f / dxdy);
            cs.SetVector("dxdy", new Vector4(dx, dy, 1.0f / dx, 1.0f / dy));
            cs.SetVector("terrainDim", new Vector4(terrainScale.x, terrainScale.y, terrainScale.z));
            cs.SetVector("texDim", new Vector4((float)xRes, (float)yRes, 0.0f, 0.0f));

            cs.SetTexture(thermalKernelIdx, "Sediment", sedimentRT);
            cs.SetTexture(thermalKernelIdx, "ReposeMask", reposeAngleRT);
            cs.SetTexture(thermalKernelIdx, "Collision", collisionRT);
            cs.SetTexture(thermalKernelIdx, "Hardness", hardnessRT);

            for (int i = 0; i < m_ThermalIterations; i++)
            {
                cs.SetTexture(thermalKernelIdx, "TerrainHeightPrev", heightmapRT0);
                cs.SetTexture(thermalKernelIdx, "TerrainHeight", heightmapRT1);

                //jitter tau (want a new value each iteration)
                Vector2 jitteredTau = m_AngleOfRepose + new Vector2(0.9f * (float)m_ReposeJitter * (UnityEngine.Random.value - 0.5f), 0.9f * (float)m_ReposeJitter * (UnityEngine.Random.value - 0.5f));
                jitteredTau.x = Mathf.Clamp(jitteredTau.x, 0.0f, 89.9f);
                jitteredTau.y = Mathf.Clamp(jitteredTau.y, 0.0f, 89.9f);

                Vector2 m = new Vector2(Mathf.Tan(jitteredTau.x * Mathf.Deg2Rad), Mathf.Tan(jitteredTau.y * Mathf.Deg2Rad));
                cs.SetVector("angleOfRepose", new Vector4(m.x, m.y, 0.0f, 0.0f));

                cs.Dispatch(thermalKernelIdx, xRes / numWorkGroups[0], yRes / numWorkGroups[1], numWorkGroups[2]);

                // swap
                var temp = heightmapRT0;
                heightmapRT0 = heightmapRT1;
                heightmapRT1 = temp;
            }

            Graphics.Blit((m_ThermalIterations - 1) % 2 == 0 ? heightmapRT1 : heightmapRT0, outputTextures["Height"]);

            //reset the active render texture so weird stuff doesn't happen (Blit overwrites this)
            RenderTexture.active = prevRT;

            RTUtils.Release(heightmapRT0);
            RTUtils.Release(heightmapRT1);
            RTUtils.Release(sedimentRT);
            RTUtils.Release(hardnessRT);
            RTUtils.Release(reposeAngleRT);
            RTUtils.Release(collisionRT);
        }