diff --git a/Source/Shaders/Packing.hlsl b/Source/Shaders/Packing.hlsl new file mode 100644 index 000000000..55f8d4dc3 --- /dev/null +++ b/Source/Shaders/Packing.hlsl @@ -0,0 +1,68 @@ +// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. + +#ifndef __PACKING__ +#define __PACKING__ + +// https://github.com/turanszkij/WickedEngine/blob/4a6171fdd584fcf9d41045e6dd2a13c03fa2e4d9/WickedEngine/shaders/globals.hlsli#L1103-L1118 +inline uint PackUnitVector(in float3 value) +{ + uint result = 0; + result |= (uint)((value.x * 0.5 + 0.5) * 255.0) << 0u; + result |= (uint)((value.y * 0.5 + 0.5) * 255.0) << 8u; + result |= (uint)((value.z * 0.5 + 0.5) * 255.0) << 16u; + return result; +} +inline float3 UnpackUnitVector(in uint value) +{ + float3 result; + result.x = (float)((value >> 0u) & 0xFF) / 255.0 * 2 - 1; + result.y = (float)((value >> 8u) & 0xFF) / 255.0 * 2 - 1; + result.z = (float)((value >> 16u) & 0xFF) / 255.0 * 2 - 1; + return result; +} + +// https://github.com/turanszkij/WickedEngine/blob/4a6171fdd584fcf9d41045e6dd2a13c03fa2e4d9/WickedEngine/shaders/PixelPacking_RGBE.hlsli +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// Developed by Minigraph +// Author: James Stanard +// RGBE, aka R9G9B9E5_SHAREDEXP, is an unsigned float HDR pixel format where red, green, +// and blue all share the same exponent. The color channels store a 9-bit value ranging +// from [0/512, 511/512] which multiplies by 2^Exp and Exp ranges from [-15, 16]. +// Floating point specials are not encoded. +uint PackRGBE(float3 rgb) +{ + // To determine the shared exponent, we must clamp the channels to an expressible range + const float kMaxVal = asfloat(0x477F8000); // 1.FF x 2^+15 + const float kMinVal = asfloat(0x37800000); // 1.00 x 2^-16 + + // Non-negative and <= kMaxVal + rgb = clamp(rgb, 0, kMaxVal); + + // From the maximum channel we will determine the exponent. We clamp to a min value + // so that the exponent is within the valid 5-bit range. + float MaxChannel = max(max(kMinVal, rgb.r), max(rgb.g, rgb.b)); + + // 'Bias' has to have the biggest exponent plus 15 (and nothing in the mantissa). When + // added to the three channels, it shifts the explicit '1' and the 8 most significant + // mantissa bits into the low 9 bits. IEEE rules of float addition will round rather + // than truncate the discarded bits. Channels with smaller natural exponents will be + // shifted further to the right (discarding more bits). + float Bias = asfloat((asuint(MaxChannel) + 0x07804000) & 0x7F800000); + + // Shift bits into the right places + uint3 RGB = asuint(rgb + Bias); + uint E = (asuint(Bias) << 4) + 0x10000000; + return E | RGB.b << 18 | RGB.g << 9 | (RGB.r & 0x1FF); +} +float3 UnpackRGBE(uint p) +{ + float3 rgb = uint3(p, p >> 9, p >> 18) & 0x1FF; + return ldexp(rgb, (int)(p >> 27) - 24); +} + +#endif