You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

175 lines
8.8 KiB

using System;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering.HighDefinition
{
partial class VolumetricCloudsSystem
{
RTHandle m_AdvancedCloudMap;
int m_CloudMapHash;
int m_EvaluateCloudMapKernel;
ComputeShader m_CloudMapGeneratorCS;
void InitializeVolumetricCloudsMap()
{
// Grab the kernels we need
m_CloudMapGeneratorCS = m_RuntimeResources.volumetricCloudMapGeneratorCS;
m_EvaluateCloudMapKernel = m_CloudMapGeneratorCS.FindKernel("EvaluateCloudMap");
m_CloudMapHash = 0;
}
void ReleaseVolumetricCloudsMap()
{
RTHandles.Release(m_AdvancedCloudMap);
}
// This function evaluates for the current advanced configuration it hash, for identification, storage and retrieval.
static int EvaluateCurrentAdvancedHash(in VolumetricClouds settings)
{
unchecked
{
int hash = HDUtils.GetTextureHash(settings.cumulusMap.value != null ? settings.cumulusMap.value : Texture2D.blackTexture);
hash = 23 * hash + settings.cumulusMapMultiplier.value.GetHashCode();
hash = 23 * hash + HDUtils.GetTextureHash(settings.altoStratusMap.value != null ? settings.altoStratusMap.value : Texture2D.blackTexture);
hash = 23 * hash + settings.altoStratusMapMultiplier.value.GetHashCode();
hash = 23 * hash + HDUtils.GetTextureHash(settings.cumulonimbusMap.value != null ? settings.cumulonimbusMap.value : Texture2D.blackTexture);
hash = 23 * hash + settings.cumulonimbusMapMultiplier.value.GetHashCode();
hash = 23 * hash + HDUtils.GetTextureHash(settings.rainMap.value != null ? settings.rainMap.value : Texture2D.blackTexture);
hash = 23 * hash + settings.cloudMapResolution.value.GetHashCode();
return hash;
}
}
bool RequiresCloudMapBaking(HDCamera hdCamera, in VolumetricClouds settings)
{
// Evaluate if we need to recompute the texture
bool status = (HasVolumetricClouds(hdCamera, in settings)
&& settings.cloudControl.value == VolumetricClouds.CloudControl.Advanced);
if (status)
{
// Evaluate the hash of the current configuration
int currentHash = EvaluateCurrentAdvancedHash(in settings);
if (m_CloudMapHash == currentHash)
status = false;
else
m_CloudMapHash = currentHash;
}
return status;
}
bool IsWrapModeClamp(TextureParameter tex) => tex.value != null && tex.value.wrapMode == TextureWrapMode.Clamp;
void AdjustCloudMapTextureSize(in VolumetricClouds settings)
{
int cloudMapRes = (int)settings.cloudMapResolution.value;
bool clamp = IsWrapModeClamp(settings.cumulusMap) || IsWrapModeClamp(settings.altoStratusMap) || IsWrapModeClamp(settings.cumulonimbusMap);
// Evaluate if a (re)allocation is required
bool needAllocation = m_AdvancedCloudMap == null;
if (m_AdvancedCloudMap != null && (m_AdvancedCloudMap.rt.width != cloudMapRes || (m_AdvancedCloudMap.rt.wrapMode == TextureWrapMode.Clamp) != clamp))
{
RTHandles.Release(m_AdvancedCloudMap);
needAllocation = true;
}
if (needAllocation)
{
var wrapMode = clamp ? TextureWrapMode.Clamp : TextureWrapMode.Repeat;
m_AdvancedCloudMap = RTHandles.Alloc(cloudMapRes, cloudMapRes, 1, colorFormat: GraphicsFormat.R8G8B8A8_UNorm,
enableRandomWrite: true, useDynamicScale: false, useMipMap: false, filterMode: FilterMode.Bilinear, wrapMode: wrapMode, name: "Volumetric Clouds Map");
}
}
struct CloudMapGenerationParameters
{
public int cloudMapResolution;
public ComputeShader generationCS;
public int generationKernel;
public Texture cumulusMap;
public float cumulusMapMultiplier;
public Texture altostratusMap;
public float altoStratusMapMultiplier;
public Texture cumulonimbusMap;
public float cumulonimbusMapMultiplier;
public Texture rainMap;
}
CloudMapGenerationParameters PrepareCloudMapGenerationParameters(in VolumetricClouds settings)
{
CloudMapGenerationParameters parameters = new CloudMapGenerationParameters();
parameters.cloudMapResolution = (int)settings.cloudMapResolution.value;
parameters.generationCS = m_CloudMapGeneratorCS;
parameters.generationKernel = m_EvaluateCloudMapKernel;
parameters.cumulusMap = settings.cumulusMap.value != null ? settings.cumulusMap.value : Texture2D.blackTexture;
parameters.cumulusMapMultiplier = settings.cumulusMapMultiplier.value;
parameters.altostratusMap = settings.altoStratusMap.value != null ? settings.altoStratusMap.value : Texture2D.blackTexture;
parameters.altoStratusMapMultiplier = settings.altoStratusMapMultiplier.value;
parameters.cumulonimbusMap = settings.cumulonimbusMap.value != null ? settings.cumulonimbusMap.value : Texture2D.blackTexture;
parameters.cumulonimbusMapMultiplier = settings.cumulonimbusMapMultiplier.value;
parameters.rainMap = settings.rainMap.value != null ? settings.rainMap.value : Texture2D.blackTexture;
return parameters;
}
static void EvaluateVolumetricCloudMap(CommandBuffer cmd, CloudMapGenerationParameters parameters, RTHandle outputCloudMap)
{
using (new ProfilingScope(cmd, ProfilingSampler.Get(HDProfileId.VolumetricCloudMapGeneration)))
{
// Compute the final resolution parameters
int resolutionRounded = HDUtils.DivRoundUp(parameters.cloudMapResolution, 8);
cmd.SetComputeIntParam(parameters.generationCS, HDShaderIDs._CloudMapResolution, parameters.cloudMapResolution);
cmd.SetComputeTextureParam(parameters.generationCS, parameters.generationKernel, HDShaderIDs._CumulusMap, parameters.cumulusMap);
cmd.SetComputeFloatParam(parameters.generationCS, HDShaderIDs._CumulusMapMultiplier, parameters.cumulusMapMultiplier);
cmd.SetComputeTextureParam(parameters.generationCS, parameters.generationKernel, HDShaderIDs._AltostratusMap, parameters.altostratusMap);
cmd.SetComputeFloatParam(parameters.generationCS, HDShaderIDs._AltostratusMapMultiplier, parameters.altoStratusMapMultiplier);
cmd.SetComputeTextureParam(parameters.generationCS, parameters.generationKernel, HDShaderIDs._CumulonimbusMap, parameters.cumulonimbusMap);
cmd.SetComputeFloatParam(parameters.generationCS, HDShaderIDs._CumulonimbusMapMultiplier, parameters.cumulonimbusMapMultiplier);
cmd.SetComputeTextureParam(parameters.generationCS, parameters.generationKernel, HDShaderIDs._RainMap, parameters.rainMap);
cmd.SetComputeTextureParam(parameters.generationCS, parameters.generationKernel, HDShaderIDs._CloudMapTextureRW, outputCloudMap);
cmd.DispatchCompute(parameters.generationCS, parameters.generationKernel, resolutionRounded, resolutionRounded, 1);
}
}
class VolumetricCloudsMapData
{
public CloudMapGenerationParameters parameters;
public TextureHandle cloudMapTexture;
}
void PreRenderVolumetricCloudMap(RenderGraph renderGraph, HDCamera hdCamera, in VolumetricClouds settings)
{
// If we don't need to bake the volumetric cloud map, skip right away
if (!RequiresCloudMapBaking(hdCamera, settings))
return;
// Make sure the cloud map is at the right size
AdjustCloudMapTextureSize(in settings);
using (var builder = renderGraph.AddUnsafePass<VolumetricCloudsMapData>("Volumetric cloud map generation", out var passData, ProfilingSampler.Get(HDProfileId.VolumetricCloudMapGeneration)))
{
passData.parameters = PrepareCloudMapGenerationParameters(in settings);
passData.cloudMapTexture = renderGraph.ImportTexture(m_AdvancedCloudMap);
builder.UseTexture(passData.cloudMapTexture, AccessFlags.Write);
builder.SetRenderFunc(
(VolumetricCloudsMapData data, UnsafeGraphContext ctx) =>
{
EvaluateVolumetricCloudMap(CommandBufferHelpers.GetNativeCommandBuffer(ctx.cmd), data.parameters, data.cloudMapTexture);
});
}
}
}
}