using System; using System.Runtime.InteropServices; using UnityEngine; using UnityEngine.Rendering; namespace FidelityFX { public static class FfxUtils { public static float GetMipmapBiasOffset(int renderWidth, int displayWidth) { return Mathf.Log((float)renderWidth / displayWidth, 2.0f) - 1.0f; } public static int GetJitterPhaseCount(int renderWidth, int displayWidth) { const float basePhaseCount = 8.0f; int jitterPhaseCount = (int)(basePhaseCount * Mathf.Pow((float)displayWidth / renderWidth, 2.0f)); return jitterPhaseCount; } public static void GetJitterOffset(out float outX, out float outY, int index, int phaseCount) { outX = Halton((index % phaseCount) + 1, 2) - 0.5f; outY = Halton((index % phaseCount) + 1, 3) - 0.5f; } // Calculate halton number for index and base. private static float Halton(int index, int @base) { float f = 1.0f, result = 0.0f; for (int currentIndex = index; currentIndex > 0;) { f /= @base; result += f * (currentIndex % @base); currentIndex = (int)Mathf.Floor((float)currentIndex / @base); } return result; } public static float Lanczos2(float value) { return Mathf.Abs(value) < Mathf.Epsilon ? 1.0f : Mathf.Sin(Mathf.PI * value) / (Mathf.PI * value) * (Mathf.Sin(0.5f * Mathf.PI * value) / (0.5f * Mathf.PI * value)); } public static float[] GenerateLanczos2Table(int width) { float[] lanczos2Weights = new float[width]; for (int currentLanczosWidthIndex = 0; currentLanczosWidthIndex < width; ++currentLanczosWidthIndex) { float x = 2.0f * currentLanczosWidthIndex / (width - 1); float y = Lanczos2(x); lanczos2Weights[currentLanczosWidthIndex] = y; } return lanczos2Weights; } public static Vector4 SetupDeviceDepthToViewSpaceDepthParams(Vector2Int renderSize, float cameraNear, float cameraFar, float cameraFovAngleVertical, bool inverted, bool infinite) { // make sure it has no impact if near and far plane values are swapped in dispatch params // the flags "inverted" and "infinite" will decide what transform to use float min = Mathf.Min(cameraNear, cameraFar); float max = Mathf.Max(cameraNear, cameraFar); if (inverted) { (min, max) = (max, min); } float q = max / (min - max); float d = -1.0f; Vector4 matrixElemC = new Vector4(q, -1.0f - Mathf.Epsilon, q, 0.0f + Mathf.Epsilon); Vector4 matrixElemE = new Vector4(q * min, -min - Mathf.Epsilon, q * min, max); // Revert x and y coords float aspect = (float)renderSize.x / renderSize.y; float cotHalfFovY = Mathf.Cos(0.5f * cameraFovAngleVertical) / Mathf.Sin(0.5f * cameraFovAngleVertical); int matrixIndex = (inverted ? 2 : 0) + (infinite ? 1 : 0); return new Vector4( d * matrixElemC[matrixIndex], matrixElemE[matrixIndex], aspect / cotHalfFovY, 1.0f / cotHalfFovY); } #if !UNITY_2021_1_OR_NEWER internal static void SetBufferData(this CommandBuffer commandBuffer, ComputeBuffer computeBuffer, Array data) { commandBuffer.SetComputeBufferData(computeBuffer, data); } #endif /// /// Alternative for CommandBuffer.SetComputeTextureParam that guards against attempts to bind mip levels that don't exist. /// internal static void SetComputeTextureMipParam(this CommandBuffer commandBuffer, ComputeShader computeShader, int kernelIndex, int nameID, Texture texture, int mipLevel) { mipLevel = Math.Min(mipLevel, texture.mipmapCount - 1); commandBuffer.SetComputeTextureParam(computeShader, kernelIndex, nameID, texture, mipLevel); } internal static void SetComputeResourceParam(this CommandBuffer commandBuffer, ComputeShader computeShader, int kernelIndex, int nameID, in ResourceView resource) { commandBuffer.SetComputeTextureParam(computeShader, kernelIndex, nameID, resource.RenderTarget, resource.MipLevel, resource.SubElement); } internal static void SetComputeConstantBufferParam(this CommandBuffer commandBuffer, ComputeShader computeShader, int nameID, ComputeBuffer buffer) where TBuf: struct { commandBuffer.SetComputeConstantBufferParam(computeShader, nameID, buffer, 0, Marshal.SizeOf()); } } }