protected override bool ProcessNode(CommandBuffer cmd) { // Force the double buffering for multi-pass flooding rtSettings.doubleBuffered = true; if (!base.ProcessNode(cmd) || input == null) { return(false); } UpdateTempRenderTexture(ref output); cmd.SetComputeFloatParam(computeShader, "_Threshold", threshold); cmd.SetComputeVectorParam(computeShader, "_Size", new Vector4(output.width, 1.0f / output.width)); cmd.SetComputeFloatParam(computeShader, "_Distance", distance / 100.0f); cmd.SetComputeIntParam(computeShader, "_ThresholdMode", (int)thresholdMode); cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode); cmd.SetComputeIntParam(computeShader, "_Mode", (int)mode); output.doubleBuffered = true; output.EnsureDoubleBufferConsistency(); var rt = output.GetDoubleBufferRenderTexture(); rt.Release(); rt.enableRandomWrite = true; rt.Create(); MixtureUtils.SetupComputeDimensionKeyword(computeShader, input.dimension); cmd.SetComputeTextureParam(computeShader, fillUvKernel, "_Input", input); cmd.SetComputeTextureParam(computeShader, fillUvKernel, "_Output", output); cmd.SetComputeTextureParam(computeShader, fillUvKernel, "_FinalOutput", rt); cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode); cmd.SetComputeFloatParam(computeShader, "_InputScaleFactor", (float)input.width / (float)output.width); DispatchCompute(cmd, fillUvKernel, output.width, output.height, output.volumeDepth); int maxLevels = (int)Mathf.Log(input.width, 2); for (int i = 0; i <= maxLevels; i++) { float offset = 1 << (maxLevels - i); cmd.SetComputeFloatParam(computeShader, "_InputScaleFactor", 1); cmd.SetComputeFloatParam(computeShader, "_Offset", offset); cmd.SetComputeTextureParam(computeShader, jumpFloodingKernel, "_Input", output); cmd.SetComputeTextureParam(computeShader, jumpFloodingKernel, "_Output", rt); cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode); DispatchCompute(cmd, jumpFloodingKernel, output.width, output.height, output.volumeDepth); cmd.CopyTexture(rt, output); } cmd.SetComputeFloatParam(computeShader, "_InputScaleFactor", (float)input.width / (float)output.width); cmd.SetComputeTextureParam(computeShader, finalPassKernel, "_Input", input); cmd.SetComputeTextureParam(computeShader, finalPassKernel, "_Output", rt); cmd.SetComputeIntParam(computeShader, "_DistanceMode", (int)distanceMode); cmd.SetComputeTextureParam(computeShader, finalPassKernel, "_FinalOutput", output); DispatchCompute(cmd, finalPassKernel, output.width, output.height, output.volumeDepth); return(true); }
public static void UpdateCustomRenderTexture(CommandBuffer cmd, CustomRenderTexture crt, int updateCount, int mipLevel = 0, MaterialPropertyBlock block = null) { // Prepare "self" texture for reading in the shader for double buffered custom textures RenderTexture textureSelf2D = null; RenderTexture textureSelf3D = null; RenderTexture textureSelfCube = null; if (crt.doubleBuffered) { if (crt.dimension == TextureDimension.Tex2D) { textureSelf2D = crt; } if (crt.dimension == TextureDimension.Cube) { textureSelfCube = crt; } if (crt.dimension == TextureDimension.Tex3D) { textureSelf3D = crt; } } if (crt.doubleBuffered) { // Update the internal double buffered render texture (resize / alloc / ect.) crt.EnsureDoubleBufferConsistency(); } if (block == null) { block = new MaterialPropertyBlock(); } // If the user didn't called the update on CRT, we still process it because it's realtime for (int i = 0; i < updateCount; i++) { // TODO: cache everything List <CustomRenderTextureUpdateZone> updateZones = new List <CustomRenderTextureUpdateZone>(); crt.GetUpdateZones(updateZones); if (updateZones.Count == 0) { updateZones.Add(new CustomRenderTextureUpdateZone { needSwap = false, updateZoneCenter = new Vector3(0.5f, 0.5f, 0.5f), updateZoneSize = Vector3.one, rotation = 0, passIndex = 0 }); } foreach (var zone in updateZones) { var zoneCenters = updateZones.Select(z => new Vector4(z.updateZoneCenter.x, z.updateZoneCenter.y, z.updateZoneCenter.z, 0)).ToList(); var zoneSizesAndRotation = updateZones.Select(z => new Vector4(z.updateZoneSize.x, z.updateZoneSize.y, z.updateZoneSize.z, z.rotation)).ToList(); var zonePrimitiveIDs = Enumerable.Range(0, updateZones.Count).Select(j => (float)j).ToList();// updateZones.Select(z => 0.0f).ToList(); int sliceCount = GetSliceCount(crt, mipLevel); // Copy all the slices in case the texture is double buffered if (zone.needSwap) { var doubleBuffer = crt.GetDoubleBufferRenderTexture(); if (doubleBuffer != null) { // For now, it's just a copy, once we actually do the swap of pointer, be careful to reset the Active Render Texture for (int sliceIndex = 0; sliceIndex < sliceCount; sliceIndex++) { cmd.CopyTexture(doubleBuffer, sliceIndex, crt, sliceIndex); } } } for (int slice = 0; slice < sliceCount; slice++) { RenderTexture renderTexture = crt.doubleBuffered ? crt.GetDoubleBufferRenderTexture() : crt; cmd.SetRenderTarget(renderTexture, mipLevel, (crt.dimension == TextureDimension.Cube) ? (CubemapFace)slice : CubemapFace.Unknown, (crt.dimension == TextureDimension.Tex3D) ? slice : 0); cmd.SetViewport(new Rect(0, 0, Mathf.Max(1, crt.width >> mipLevel), Mathf.Max(1, crt.height >> mipLevel))); block.SetVector(kCustomRenderTextureInfo, GetTextureInfos(crt, slice, mipLevel)); block.SetVector(kCustomRenderTextureParameters, GetTextureParameters(crt, slice, mipLevel)); block.SetFloat(kMipLevel, mipLevel); if (textureSelf2D != null) { block.SetTexture(kSelf2D, textureSelf2D); } if (textureSelf3D != null) { block.SetTexture(kSelf3D, textureSelf3D); } if (textureSelfCube != null) { block.SetTexture(kSelfCube, textureSelfCube); } int passIndex = zone.passIndex == -1 ? 0 : zone.passIndex; block.SetVectorArray(kUpdateDataCenters, zoneCenters); block.SetVectorArray(kUpdateDataSizesAndRotation, zoneSizesAndRotation); block.SetFloatArray(kUpdateDataPrimitiveIDs, zonePrimitiveIDs); cmd.DrawProcedural(Matrix4x4.identity, crt.material, passIndex, MeshTopology.Triangles, 6 * updateZones.Count, 1, block); } } } }
// Update one custom render texture. public static void UpdateCustomRenderTexture(CommandBuffer cmd, CustomRenderTexture crt) { bool firstPass = crt.updateCount == 0; // Handle initialization here too: if (crt.initializationMode == CustomRenderTextureUpdateMode.Realtime || needsInitialization.Contains(crt) || (firstPass && crt.initializationMode == CustomRenderTextureUpdateMode.OnLoad)) { switch (crt.initializationSource) { case CustomRenderTextureInitializationSource.Material: // TODO break; case CustomRenderTextureInitializationSource.TextureAndColor: // TODO break; } needsInitialization.Remove(crt); } needsUpdate.TryGetValue(crt, out int updateCount); if (crt.material != null && (crt.updateMode == CustomRenderTextureUpdateMode.Realtime || updateCount > 0 || (firstPass && crt.updateMode == CustomRenderTextureUpdateMode.OnLoad))) { onBeforeCustomTextureUpdated?.Invoke(cmd, crt); #if CUSTOM_TEXTURE_PROFILING customRenderTextureSamplers.TryGetValue(crt, out var sampler); if (sampler == null) { sampler = customRenderTextureSamplers[crt] = CustomSampler.Create($"{crt.name} - {crt.GetInstanceID()}", true); sampler.GetRecorder().enabled = true; } cmd.BeginSample(sampler); #endif using (new ProfilingScope(cmd, new ProfilingSampler($"Update {crt.name}"))) { // Prepare "self" texture for reading in the shader for double buffered custom textures RenderTexture textureSelf2D = null; RenderTexture textureSelf3D = null; RenderTexture textureSelfCube = null; if (crt.doubleBuffered) { if (crt.dimension == TextureDimension.Tex2D) { textureSelf2D = crt; } if (crt.dimension == TextureDimension.Cube) { textureSelfCube = crt; } if (crt.dimension == TextureDimension.Tex3D) { textureSelf3D = crt; } } if (crt.doubleBuffered) { // Update the internal double buffered render texture (resize / alloc / ect.) crt.EnsureDoubleBufferConsistency(); } MaterialPropertyBlock block = new MaterialPropertyBlock(); // If the user didn't called the update on CRT, we still process it because it's realtime updateCount = Mathf.Max(updateCount, 1); for (int i = 0; i < updateCount; i++) { // TODO: cache everything List <CustomRenderTextureUpdateZone> updateZones = new List <CustomRenderTextureUpdateZone>(); crt.GetUpdateZones(updateZones); if (updateZones.Count == 0) { updateZones.Add(new CustomRenderTextureUpdateZone { needSwap = false, updateZoneCenter = new Vector3(0.5f, 0.5f, 0.5f), updateZoneSize = Vector3.one, rotation = 0, passIndex = 0 }); } foreach (var zone in updateZones) // int sliceCount = GetSliceCount(crt); // for (int slice = 0; slice < sliceCount; slice++) { var zoneCenters = updateZones.Select(z => new Vector4(z.updateZoneCenter.x, z.updateZoneCenter.y, z.updateZoneCenter.z, 0)).ToList(); var zoneSizesAndRotation = updateZones.Select(z => new Vector4(z.updateZoneSize.x, z.updateZoneSize.y, z.updateZoneSize.z, z.rotation)).ToList(); var zonePrimitiveIDs = Enumerable.Range(0, updateZones.Count).Select(j => (float)j).ToList();// updateZones.Select(z => 0.0f).ToList(); int sliceCount = GetSliceCount(crt); // Copy all the slices in case the texture is double buffered if (zone.needSwap) { var doubleBuffer = crt.GetDoubleBufferRenderTexture(); if (doubleBuffer != null) { // For now, it's just a copy, once we actually do the swap of pointer, be careful to reset the Active Render Texture for (int slice = 0; slice < sliceCount; slice++) { cmd.CopyTexture(doubleBuffer, slice, crt, slice); } } } // foreach (var zone in updateZones) for (int slice = 0; slice < sliceCount; slice++) { RenderTexture renderTexture = crt.doubleBuffered ? crt.GetDoubleBufferRenderTexture() : crt; cmd.SetRenderTarget(renderTexture, 0, (crt.dimension == TextureDimension.Cube) ? (CubemapFace)slice : 0, (crt.dimension == TextureDimension.Tex3D) ? slice : 0); cmd.SetViewport(new Rect(0, 0, crt.width, crt.height)); block.SetVector(kCustomRenderTextureInfo, GetTextureInfos(crt, slice)); block.SetVector(kCustomRenderTextureParameters, GetTextureParameters(crt, slice)); if (textureSelf2D != null) { block.SetTexture(kSelf2D, textureSelf2D); } if (textureSelf3D != null) { block.SetTexture(kSelf3D, textureSelf3D); } if (textureSelfCube != null) { block.SetTexture(kSelfCube, textureSelfCube); } int passIndex = zone.passIndex == -1 ? 0 : zone.passIndex; block.SetVectorArray(kUpdateDataCenters, zoneCenters); block.SetVectorArray(kUpdateDataSizesAndRotation, zoneSizesAndRotation); block.SetFloatArray(kUpdateDataPrimitiveIDs, zonePrimitiveIDs); cmd.DrawProcedural(Matrix4x4.identity, crt.material, passIndex, MeshTopology.Triangles, 6 * updateZones.Count, 1, block); } } } needsUpdate.Remove(crt); } #if CUSTOM_TEXTURE_PROFILING cmd.EndSample(sampler); #endif crt.IncrementUpdateCount(); } }