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(); }
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); }
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); }
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); }
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; }
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); }