diff --git a/WickedEngine/shaders/ColorSpaceUtility.hlsli b/WickedEngine/shaders/ColorSpaceUtility.hlsli new file mode 100644 index 000000000..3024a9d3b --- /dev/null +++ b/WickedEngine/shaders/ColorSpaceUtility.hlsli @@ -0,0 +1,164 @@ +// +// 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 +// + +#pragma warning( disable : 3571 ) + +#ifndef __COLOR_SPACE_UTILITY_HLSLI__ +#define __COLOR_SPACE_UTILITY_HLSLI__ + +// +// Gamma ramps and encoding transfer functions +// +// Orthogonal to color space though usually tightly coupled. For instance, sRGB is both a +// color space (defined by three basis vectors and a white point) and a gamma ramp. Gamma +// ramps are designed to reduce perceptual error when quantizing floats to integers with a +// limited number of bits. More variation is needed in darker colors because our eyes are +// more sensitive in the dark. The way the curve helps is that it spreads out dark values +// across more code words allowing for more variation. Likewise, bright values are merged +// together into fewer code words allowing for less variation. +// +// The sRGB curve is not a true gamma ramp but rather a piecewise function comprising a linear +// section and a power function. When sRGB-encoded colors are passed to an LCD monitor, they +// look correct on screen because the monitor expects the colors to be encoded with sRGB, and it +// removes the sRGB curve to linearize the values. When textures are encoded with sRGB--as many +// are--the sRGB curve needs to be removed before involving the colors in linear mathematics such +// as physically based lighting. + +float3 ApplySRGBCurve( float3 x ) +{ + // Approximately pow(x, 1.0 / 2.2) + return x < 0.0031308 ? 12.92 * x : 1.055 * pow(x, 1.0 / 2.4) - 0.055; +} + +float3 RemoveSRGBCurve( float3 x ) +{ + // Approximately pow(x, 2.2) + return x < 0.04045 ? x / 12.92 : pow( (x + 0.055) / 1.055, 2.4 ); +} + +// These functions avoid pow() to efficiently approximate sRGB with an error < 0.4%. +float3 ApplySRGBCurve_Fast( float3 x ) +{ + return x < 0.0031308 ? 12.92 * x : 1.13005 * sqrt(x - 0.00228) - 0.13448 * x + 0.005719; +} + +float3 RemoveSRGBCurve_Fast( float3 x ) +{ + return x < 0.04045 ? x / 12.92 : -7.43605 * x - 31.24297 * sqrt(-0.53792 * x + 1.279924) + 35.34864; +} + +// The OETF recommended for content shown on HDTVs. This "gamma ramp" may increase contrast as +// appropriate for viewing in a dark environment. Always use this curve with Limited RGB as it is +// used in conjunction with HDTVs. +float3 ApplyREC709Curve( float3 x ) +{ + return x < 0.0181 ? 4.5 * x : 1.0993 * pow(x, 0.45) - 0.0993; +} + +float3 RemoveREC709Curve( float3 x ) +{ + return x < 0.08145 ? x / 4.5 : pow((x + 0.0993) / 1.0993, 1.0 / 0.45); +} + +// This is the new HDR transfer function, also called "PQ" for perceptual quantizer. Note that REC2084 +// does not also refer to a color space. REC2084 is typically used with the REC2020 color space. +float3 ApplyREC2084Curve(float3 L) +{ + float m1 = 2610.0 / 4096.0 / 4; + float m2 = 2523.0 / 4096.0 * 128; + float c1 = 3424.0 / 4096.0; + float c2 = 2413.0 / 4096.0 * 32; + float c3 = 2392.0 / 4096.0 * 32; + float3 Lp = pow(L, m1); + return pow((c1 + c2 * Lp) / (1 + c3 * Lp), m2); +} + +float3 RemoveREC2084Curve(float3 N) +{ + float m1 = 2610.0 / 4096.0 / 4; + float m2 = 2523.0 / 4096.0 * 128; + float c1 = 3424.0 / 4096.0; + float c2 = 2413.0 / 4096.0 * 32; + float c3 = 2392.0 / 4096.0 * 32; + float3 Np = pow(N, 1 / m2); + return pow(max(Np - c1, 0) / (c2 - c3 * Np), 1 / m1); +} + +// +// Color space conversions +// +// These assume linear (not gamma-encoded) values. A color space conversion is a change +// of basis (like in Linear Algebra). Since a color space is defined by three vectors-- +// the basis vectors--changing space involves a matrix-vector multiplication. Note that +// changing the color space may result in colors that are "out of bounds" because some +// color spaces have larger gamuts than others. When converting some colors from a wide +// gamut to small gamut, negative values may result, which are inexpressible in that new +// color space. +// +// It would be ideal to build a color pipeline which never throws away inexpressible (but +// perceivable) colors. This means using a color space that is as wide as possible. The +// XYZ color space is the neutral, all-encompassing color space, but it has the unfortunate +// property of having negative values (specifically in X and Z). To correct this, a further +// transformation can be made to X and Z to make them always positive. They can have their +// precision needs reduced by dividing by Y, allowing X and Z to be packed into two UNORM8s. +// This color space is called YUV for lack of a better name. +// + +// Note: Rec.709 and sRGB share the same color primaries and white point. Their only difference +// is the transfer curve used. + +float3 REC709toREC2020( float3 RGB709 ) +{ + static const float3x3 ConvMat = + { + 0.627402, 0.329292, 0.043306, + 0.069095, 0.919544, 0.011360, + 0.016394, 0.088028, 0.895578 + }; + return mul(ConvMat, RGB709); +} + +float3 REC2020toREC709(float3 RGB2020) +{ + static const float3x3 ConvMat = + { + 1.660496, -0.587656, -0.072840, + -0.124547, 1.132895, -0.008348, + -0.018154, -0.100597, 1.118751 + }; + return mul(ConvMat, RGB2020); +} + +float3 REC709toDCIP3( float3 RGB709 ) +{ + static const float3x3 ConvMat = + { + 0.822458, 0.177542, 0.000000, + 0.033193, 0.966807, 0.000000, + 0.017085, 0.072410, 0.910505 + }; + return mul(ConvMat, RGB709); +} + +float3 DCIP3toREC709( float3 RGBP3 ) +{ + static const float3x3 ConvMat = + { + 1.224947, -0.224947, 0.000000, + -0.042056, 1.042056, 0.000000, + -0.019641, -0.078651, 1.098291 + }; + return mul(ConvMat, RGBP3); +} + +#endif // __COLOR_SPACE_UTILITY_HLSLI__ diff --git a/WickedEngine/shaders/PixelPacking_R11G11B10.hlsli b/WickedEngine/shaders/PixelPacking_R11G11B10.hlsli new file mode 100644 index 000000000..2493e295c --- /dev/null +++ b/WickedEngine/shaders/PixelPacking_R11G11B10.hlsli @@ -0,0 +1,127 @@ +// +// 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 +// + +#ifndef __PIXEL_PACKING_R11G11B10_HLSLI__ +#define __PIXEL_PACKING_R11G11B10_HLSLI__ + +#include "ColorSpaceUtility.hlsli" + +// The standard 32-bit HDR color format. Each float has a 5-bit exponent and no sign bit. +uint Pack_R11G11B10_FLOAT( float3 rgb ) +{ + // Clamp upper bound so that it doesn't accidentally round up to INF + // Exponent=15, Mantissa=1.11111 + rgb = min(rgb, asfloat(0x477C0000)); + uint r = ((f32tof16(rgb.x) + 8) >> 4) & 0x000007FF; + uint g = ((f32tof16(rgb.y) + 8) << 7) & 0x003FF800; + uint b = ((f32tof16(rgb.z) + 16) << 17) & 0xFFC00000; + return r | g | b; +} + +float3 Unpack_R11G11B10_FLOAT( uint rgb ) +{ + float r = f16tof32((rgb << 4 ) & 0x7FF0); + float g = f16tof32((rgb >> 7 ) & 0x7FF0); + float b = f16tof32((rgb >> 17) & 0x7FE0); + return float3(r, g, b); +} + +// An improvement to float is to store the mantissa in logarithmic form. This causes a +// smooth and continuous change in precision rather than having jumps in precision every +// time the exponent increases by whole amounts. +uint Pack_R11G11B10_FLOAT_LOG( float3 rgb ) +{ + float3 flat_mantissa = asfloat((asuint(rgb) & 0x7FFFFF) | 0x3F800000); + float3 curved_mantissa = min(log2(flat_mantissa) + 1.0, asfloat(0x3FFFFFFF)); + rgb = asfloat((asuint(rgb) & 0xFF800000) | (asuint(curved_mantissa) & 0x7FFFFF)); + + uint r = ((f32tof16(rgb.x) + 8) >> 4) & 0x000007FF; + uint g = ((f32tof16(rgb.y) + 8) << 7) & 0x003FF800; + uint b = ((f32tof16(rgb.z) + 16) << 17) & 0xFFC00000; + return r | g | b; +} + +float3 Unpack_R11G11B10_FLOAT_LOG( uint p ) +{ + float3 rgb = f16tof32(uint3(p << 4, p >> 7, p >> 17) & uint3(0x7FF0, 0x7FF0, 0x7FE0)); + float3 curved_mantissa = asfloat((asuint(rgb) & 0x7FFFFF) | 0x3F800000); + float3 flat_mantissa = exp2(curved_mantissa - 1.0); + return asfloat((asuint(rgb) & 0xFF800000) | (asuint(flat_mantissa) & 0x7FFFFF)); +} + +// As an alternative to floating point, we can store the log2 of a value in fixed point notation. +// The 11-bit fields store 5.6 fixed point notation for log2(x) with an exponent bias of 15. The +// 10-bit field uses 5.5 fixed point. The disadvantage here is we don't handle underflow. Instead +// we use the extra two exponent values to extend the range down through two more exponents. +// Range = [2^-16, 2^16) +uint Pack_R11G11B10_FIXED_LOG(float3 rgb) +{ + uint3 p = clamp((log2(rgb) + 16.0) * float3(64, 64, 32) + 0.5, 0.0, float3(2047, 2047, 1023)); + return p.b << 22 | p.g << 11 | p.r; +} + +float3 Unpack_R11G11B10_FIXED_LOG(uint p) +{ + return exp2((uint3(p, p >> 11, p >> 21) & uint3(2047, 2047, 2046)) / 64.0 - 16.0); +} + +// These next two encodings are great for LDR data. By knowing that our values are [0.0, 1.0] +// (or [0.0, 2.0), incidentally), we can reduce how many bits we need in the exponent. We can +// immediately eliminate all postive exponents. By giving more bits to the mantissa, we can +// improve precision at the expense of range. The 8E3 format goes one bit further, quadrupling +// mantissa precision but increasing smallest exponent from -14 to -6. The smallest value of 8E3 +// is 2^-14, while the smallest value of 7E4 is 2^-21. Both are smaller than the smallest 8-bit +// sRGB value, which is close to 2^-12. + +// This is like R11G11B10_FLOAT except that it moves one bit from each exponent to each mantissa. +uint Pack_R11G11B10_E4_FLOAT( float3 rgb ) +{ + // Clamp to [0.0, 2.0). The magic number is 1.FFFFF x 2^0. (We can't represent hex floats in HLSL.) + // This trick works because clamping your exponent to 0 reduces the number of bits needed by 1. + rgb = clamp( rgb, 0.0, asfloat(0x3FFFFFFF) ); + uint r = ((f32tof16(rgb.r) + 4) >> 3 ) & 0x000007FF; + uint g = ((f32tof16(rgb.g) + 4) << 8 ) & 0x003FF800; + uint b = ((f32tof16(rgb.b) + 8) << 18) & 0xFFC00000; + return r | g | b; +} + +float3 Unpack_R11G11B10_E4_FLOAT( uint rgb ) +{ + float r = f16tof32((rgb << 3 ) & 0x3FF8); + float g = f16tof32((rgb >> 8 ) & 0x3FF8); + float b = f16tof32((rgb >> 18) & 0x3FF0); + return float3(r, g, b); +} + +// This is like R11G11B10_FLOAT except that it moves two bits from each exponent to each mantissa. +uint Pack_R11G11B10_E3_FLOAT( float3 rgb ) +{ + // Clamp to [0.0, 2.0). Divide by 256 to bias the exponent by -8. This shifts it down to use one + // fewer bit while still taking advantage of the denormalization hardware. In half precision, + // the exponent of 0 is 0xF. Dividing by 256 makes the max exponent 0x7--one fewer bit. + rgb = clamp( rgb, 0.0, asfloat(0x3FFFFFFF) ) / 256.0; + uint r = ((f32tof16(rgb.r) + 2) >> 2 ) & 0x000007FF; + uint g = ((f32tof16(rgb.g) + 2) << 9 ) & 0x003FF800; + uint b = ((f32tof16(rgb.b) + 4) << 19) & 0xFFC00000; + return r | g | b; +} + +float3 Unpack_R11G11B10_E3_FLOAT( uint rgb ) +{ + float r = f16tof32((rgb << 2 ) & 0x1FFC); + float g = f16tof32((rgb >> 9 ) & 0x1FFC); + float b = f16tof32((rgb >> 19) & 0x1FF8); + return float3(r, g, b) * 256.0; +} + +#endif // __PIXEL_PACKING_R11G11B10_HLSLI__ diff --git a/WickedEngine/shaders/ShaderInterop.h b/WickedEngine/shaders/ShaderInterop.h index ce8556fb5..a01a24d9e 100644 --- a/WickedEngine/shaders/ShaderInterop.h +++ b/WickedEngine/shaders/ShaderInterop.h @@ -5,7 +5,6 @@ #include "SamplerMapping.h" #include "ResourceMapping.h" - #ifdef __cplusplus // not invoking shader compiler, but included in engine source // Application-side types: @@ -34,6 +33,8 @@ typedef XMINT4 int4; #else +#include "PixelPacking_R11G11B10.hlsli" + // Shader - side types: #define CBUFFER(name, slot) cbuffer name : register(b ## slot) diff --git a/WickedEngine/shaders/ShaderInterop_Renderer.h b/WickedEngine/shaders/ShaderInterop_Renderer.h index b59356244..c722bf8fe 100644 --- a/WickedEngine/shaders/ShaderInterop_Renderer.h +++ b/WickedEngine/shaders/ShaderInterop_Renderer.h @@ -28,8 +28,6 @@ static const uint SHADERMATERIAL_OPTION_BIT_TRANSPARENT = 1 << 8; struct ShaderMaterial { float4 baseColor; - float4 specularColor; - float4 emissiveColor; float4 subsurfaceScattering; float4 subsurfaceScattering_inv; float4 texMulAdd; @@ -46,8 +44,8 @@ struct ShaderMaterial float transmission; uint options; - int padding0; - int padding1; + uint emissive_r11g11b10; + uint specular_r11g11b10; uint layerMask; int uvset_baseColorMap; @@ -69,12 +67,10 @@ struct ShaderMaterial int padding2; int padding3; + uint sheenColor_r11g11b10; float sheenRoughness; float clearcoat; float clearcoatRoughness; - float padding4; - - float4 sheenColor; float4 baseColorAtlasMulAdd; float4 surfaceMapAtlasMulAdd; @@ -101,6 +97,12 @@ struct ShaderMaterial int padding6; int padding7; +#ifndef __cplusplus + float3 GetEmissive() { return Unpack_R11G11B10_FLOAT(emissive_r11g11b10); } + float3 GetSpecular() { return Unpack_R11G11B10_FLOAT(specular_r11g11b10); } + float3 GetSheenColor() { return Unpack_R11G11B10_FLOAT(sheenColor_r11g11b10); } +#endif // __cplusplus + inline bool IsUsingVertexColors() { return options & SHADERMATERIAL_OPTION_BIT_USE_VERTEXCOLORS; } inline bool IsUsingSpecularGlossinessWorkflow() { return options & SHADERMATERIAL_OPTION_BIT_SPECULARGLOSSINESS_WORKFLOW; } inline bool IsOcclusionEnabled_Primary() { return options & SHADERMATERIAL_OPTION_BIT_OCCLUSION_PRIMARY; } diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems b/WickedEngine/shaders/Shaders_SOURCE.vcxitems index ad6953cea..204d71d6b 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems @@ -17,6 +17,7 @@ + @@ -33,6 +34,7 @@ + diff --git a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters index 5f9edd903..6ba8de022 100644 --- a/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters +++ b/WickedEngine/shaders/Shaders_SOURCE.vcxitems.filters @@ -129,6 +129,12 @@ HF + + HF + + + HF + diff --git a/WickedEngine/shaders/brdf.hlsli b/WickedEngine/shaders/brdf.hlsli index a99b1636e..f71336c80 100644 --- a/WickedEngine/shaders/brdf.hlsli +++ b/WickedEngine/shaders/brdf.hlsli @@ -136,7 +136,7 @@ struct Surface float roughness; // roughness: [0:smooth -> 1:rough] (perceptual) float occlusion; // occlusion [0 -> 1] float opacity; // opacity for blending operation [0 -> 1] - float4 emissiveColor; // light emission [0 -> 1] + float3 emissiveColor; // light emission [0 -> 1] float4 refraction; // refraction color (rgb), refraction amount (a) float transmission; // transmission factor float2 pixel; // pixel coordinate (used for randomization effects) @@ -211,7 +211,7 @@ struct Surface opacity = 1; } roughness = material.roughness; - f0 = material.specularColor.rgb * specularMap.rgb * specularMap.a * material.specularColor.a; + f0 = material.GetSpecular() * specularMap.rgb * specularMap.a; if (g_xFrame.Options & OPTION_BIT_FORCE_DIFFUSE_LIGHTING) { @@ -391,14 +391,14 @@ struct Surface create(material, baseColor, surfaceMap, specularMap); - emissiveColor = material.emissiveColor; + emissiveColor = material.GetEmissive(); [branch] if (material.texture_emissivemap_index >= 0) { const float2 UV_emissiveMap = material.uvset_emissiveMap == 0 ? uvsets.xy : uvsets.zw; float4 emissiveMap = bindless_textures[NonUniformResourceIndex(material.texture_emissivemap_index)].SampleLevel(sampler_linear_wrap, UV_emissiveMap, 0); emissiveMap.rgb = DEGAMMA(emissiveMap.rgb); - emissiveColor *= emissiveMap; + emissiveColor *= emissiveMap.rgb * emissiveMap.a; } transmission = material.transmission; diff --git a/WickedEngine/shaders/emittedparticlePS_soft.hlsl b/WickedEngine/shaders/emittedparticlePS_soft.hlsl index 9b598762d..fbdec5a6a 100644 --- a/WickedEngine/shaders/emittedparticlePS_soft.hlsl +++ b/WickedEngine/shaders/emittedparticlePS_soft.hlsl @@ -37,7 +37,7 @@ float4 main(VertextoPixel input) : SV_TARGET float opacity = saturate(color.a * inputColor.a * fade); - color.rgb *= inputColor.rgb * (1 + material.emissiveColor.rgb * material.emissiveColor.a); + color.rgb *= inputColor.rgb * (1 + material.GetEmissive()); color.a = opacity; #ifdef EMITTEDPARTICLE_DISTORTION diff --git a/WickedEngine/shaders/objectHF.hlsli b/WickedEngine/shaders/objectHF.hlsli index b43dd911a..d1941d039 100644 --- a/WickedEngine/shaders/objectHF.hlsli +++ b/WickedEngine/shaders/objectHF.hlsli @@ -351,7 +351,7 @@ struct PixelInput inline void ApplyEmissive(in Surface surface, inout Lighting lighting) { - lighting.direct.specular += surface.emissiveColor.rgb * surface.emissiveColor.a; + lighting.direct.specular += surface.emissiveColor; } inline void LightMapping(in int lightmap, in float2 ATLAS, inout Lighting lighting) @@ -1166,16 +1166,16 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_TARGET // Emissive map: - surface.emissiveColor = GetMaterial().emissiveColor; + surface.emissiveColor = GetMaterial().GetEmissive(); #ifdef OBJECTSHADER_USE_UVSETS [branch] - if (surface.emissiveColor.a > 0 && GetMaterial().uvset_emissiveMap >= 0) + if (any(surface.emissiveColor) && GetMaterial().uvset_emissiveMap >= 0) { const float2 UV_emissiveMap = GetMaterial().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; float4 emissiveMap = texture_emissivemap.Sample(sampler_objectshader, UV_emissiveMap); emissiveMap.rgb = DEGAMMA(emissiveMap.rgb); - surface.emissiveColor *= emissiveMap; + surface.emissiveColor *= emissiveMap.rgb * emissiveMap.a; } #endif // OBJECTSHADER_USE_UVSETS @@ -1235,16 +1235,16 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_TARGET } #endif // OBJECTSHADER_USE_UVSETS - surface2.emissiveColor = GetMaterial().emissiveColor; + surface2.emissiveColor = GetMaterial().GetEmissive(); #ifdef OBJECTSHADER_USE_UVSETS [branch] - if (GetMaterial().uvset_emissiveMap >= 0 && any(GetMaterial().emissiveColor)) + if (GetMaterial().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) { float2 uv = GetMaterial().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam; + surface2.emissiveColor *= sam.rgb * sam.a; } #endif // OBJECTSHADER_USE_UVSETS @@ -1297,16 +1297,16 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_TARGET } #endif // OBJECTSHADER_USE_UVSETS - surface2.emissiveColor = GetMaterial1().emissiveColor; + surface2.emissiveColor = GetMaterial1().GetEmissive(); #ifdef OBJECTSHADER_USE_UVSETS [branch] - if (GetMaterial1().uvset_emissiveMap >= 0 && any(GetMaterial().emissiveColor)) + if (GetMaterial1().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) { float2 uv = GetMaterial1().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_blend1_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam; + surface2.emissiveColor *= sam.rgb * sam.a; } #endif // OBJECTSHADER_USE_UVSETS @@ -1359,16 +1359,16 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_TARGET } #endif // OBJECTSHADER_USE_UVSETS - surface2.emissiveColor = GetMaterial2().emissiveColor; + surface2.emissiveColor = GetMaterial2().GetEmissive(); #ifdef OBJECTSHADER_USE_UVSETS [branch] - if (GetMaterial2().uvset_emissiveMap >= 0 && any(GetMaterial2().emissiveColor)) + if (GetMaterial2().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) { float2 uv = GetMaterial2().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_blend2_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam; + surface2.emissiveColor *= sam.rgb * sam.a; } #endif // OBJECTSHADER_USE_UVSETS @@ -1421,16 +1421,16 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_TARGET } #endif // OBJECTSHADER_USE_UVSETS - surface2.emissiveColor = GetMaterial3().emissiveColor; + surface2.emissiveColor = GetMaterial3().GetEmissive(); #ifdef OBJECTSHADER_USE_UVSETS [branch] - if (GetMaterial3().uvset_emissiveMap >= 0 && any(GetMaterial3().emissiveColor)) + if (GetMaterial3().uvset_emissiveMap >= 0 && any(surface2.emissiveColor)) { float2 uv = GetMaterial3().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_blend3_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - surface2.emissiveColor *= sam; + surface2.emissiveColor *= sam.rgb * sam.a; } #endif // OBJECTSHADER_USE_UVSETS @@ -1449,7 +1449,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_TARGET #ifdef OBJECTSHADER_USE_EMISSIVE - surface.emissiveColor *= unpack_rgba(input.emissiveColor); + surface.emissiveColor *= Unpack_R11G11B10_FLOAT(input.emissiveColor); #endif // OBJECTSHADER_USE_EMISSIVE @@ -1481,7 +1481,7 @@ float4 main(PixelInput input, in bool is_frontface : SV_IsFrontFace) : SV_TARGET #ifdef BRDF_SHEEN - surface.sheen.color = GetMaterial().sheenColor.rgb; + surface.sheen.color = GetMaterial().GetSheenColor(); surface.sheen.roughness = GetMaterial().sheenRoughness; #ifdef OBJECTSHADER_USE_UVSETS diff --git a/WickedEngine/shaders/objectPS_hologram.hlsl b/WickedEngine/shaders/objectPS_hologram.hlsl index 7f560ae5d..5c235d65d 100644 --- a/WickedEngine/shaders/objectPS_hologram.hlsl +++ b/WickedEngine/shaders/objectPS_hologram.hlsl @@ -19,16 +19,16 @@ float4 main(PixelInput input) : SV_TARGET } color *= input.color; - float4 emissiveColor = GetMaterial().emissiveColor; + float3 emissiveColor = GetMaterial().GetEmissive(); [branch] - if (emissiveColor.a > 0 && GetMaterial().uvset_emissiveMap >= 0) + if (any(emissiveColor) && GetMaterial().uvset_emissiveMap >= 0) { const float2 UV_emissiveMap = GetMaterial().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; float4 emissiveMap = texture_emissivemap.Sample(sampler_objectshader, UV_emissiveMap); emissiveMap.rgb = DEGAMMA(emissiveMap.rgb); - emissiveColor *= emissiveMap; + emissiveColor *= emissiveMap.rgb * emissiveMap.a; } - color.rgb += emissiveColor.rgb * emissiveColor.a; + color.rgb += emissiveColor; float time = g_xFrame.Time; float2 uv = input.pos.xy * g_xFrame.InternalResolution_rcp; diff --git a/WickedEngine/shaders/objectPS_voxelizer.hlsl b/WickedEngine/shaders/objectPS_voxelizer.hlsl index 0f41d1ea6..3391be814 100644 --- a/WickedEngine/shaders/objectPS_voxelizer.hlsl +++ b/WickedEngine/shaders/objectPS_voxelizer.hlsl @@ -41,14 +41,14 @@ void main(PSInput input) } baseColor *= input.color; float4 color = baseColor; - float4 emissiveColor = GetMaterial().emissiveColor; + float3 emissiveColor = GetMaterial().GetEmissive(); [branch] - if (GetMaterial().emissiveColor.a > 0 && GetMaterial().uvset_emissiveMap >= 0) + if (any(emissiveColor) && GetMaterial().uvset_emissiveMap >= 0) { const float2 UV_emissiveMap = GetMaterial().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; float4 emissiveMap = texture_emissivemap.Sample(sampler_linear_wrap, UV_emissiveMap); emissiveMap.rgb = DEGAMMA(emissiveMap.rgb); - emissiveColor *= emissiveMap; + emissiveColor *= emissiveMap.rgb * emissiveMap.a; } @@ -76,12 +76,12 @@ void main(PSInput input) color += sam * GetMaterial().baseColor * blend_weights.x; [branch] - if (GetMaterial().uvset_emissiveMap >= 0 && any(GetMaterial().emissiveColor)) + if (GetMaterial().uvset_emissiveMap >= 0 && any(GetMaterial().GetEmissive())) { float2 uv = GetMaterial().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam * GetMaterial().emissiveColor * blend_weights.x; + emissiveColor += sam.rgb * sam.a * GetMaterial().GetEmissive() * blend_weights.x; } } @@ -102,12 +102,12 @@ void main(PSInput input) color += sam * GetMaterial1().baseColor * blend_weights.y; [branch] - if (GetMaterial1().uvset_emissiveMap >= 0 && any(GetMaterial1().emissiveColor)) + if (GetMaterial1().uvset_emissiveMap >= 0 && any(GetMaterial1().GetEmissive())) { float2 uv = GetMaterial1().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_blend1_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam * GetMaterial1().emissiveColor * blend_weights.y; + emissiveColor += sam.rgb * sam.a * GetMaterial1().GetEmissive() * blend_weights.y; } } @@ -128,12 +128,12 @@ void main(PSInput input) color += sam * GetMaterial2().baseColor * blend_weights.z; [branch] - if (GetMaterial2().uvset_emissiveMap >= 0 && any(GetMaterial2().emissiveColor)) + if (GetMaterial2().uvset_emissiveMap >= 0 && any(GetMaterial2().GetEmissive())) { float2 uv = GetMaterial2().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_blend2_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam * GetMaterial2().emissiveColor * blend_weights.z; + emissiveColor += sam.rgb * sam.a * GetMaterial2().GetEmissive() * blend_weights.z; } } @@ -154,12 +154,12 @@ void main(PSInput input) color += sam * GetMaterial3().baseColor * blend_weights.w; [branch] - if (GetMaterial3().uvset_emissiveMap >= 0 && any(GetMaterial3().emissiveColor)) + if (GetMaterial3().uvset_emissiveMap >= 0 && any(GetMaterial3().GetEmissive())) { float2 uv = GetMaterial3().uvset_emissiveMap == 0 ? input.uvsets.xy : input.uvsets.zw; sam = texture_blend3_emissivemap.Sample(sampler_objectshader, uv); sam.rgb = DEGAMMA(sam.rgb); - emissiveColor += sam * GetMaterial3().emissiveColor * blend_weights.w; + emissiveColor += sam.rgb * sam.a * GetMaterial3().GetEmissive() * blend_weights.w; } } @@ -314,7 +314,7 @@ void main(PSInput input) color.rgb *= lighting.direct.diffuse; - color.rgb += emissiveColor.rgb * emissiveColor.a; + color.rgb += emissiveColor; uint color_encoded = PackVoxelColor(color); uint normal_encoded = pack_unitvector(N); diff --git a/WickedEngine/shaders/raytraceCS.hlsl b/WickedEngine/shaders/raytraceCS.hlsl index 242f9773f..fab44988a 100644 --- a/WickedEngine/shaders/raytraceCS.hlsl +++ b/WickedEngine/shaders/raytraceCS.hlsl @@ -114,7 +114,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex) surface.update(); - result += max(0, energy * surface.emissiveColor.rgb * surface.emissiveColor.a); + result += max(0, energy * surface.emissiveColor); diff --git a/WickedEngine/shaders/renderlightmapPS.hlsl b/WickedEngine/shaders/renderlightmapPS.hlsl index 2a6f4071f..34995e3fa 100644 --- a/WickedEngine/shaders/renderlightmapPS.hlsl +++ b/WickedEngine/shaders/renderlightmapPS.hlsl @@ -255,7 +255,7 @@ float4 main(Input input) : SV_TARGET surface.update(); - result += max(0, energy * surface.emissiveColor.rgb * surface.emissiveColor.a); + result += max(0, energy * surface.emissiveColor); // Calculate chances of reflection types: const float refractChance = surface.transmission; diff --git a/WickedEngine/shaders/rtreflectionLIB.hlsl b/WickedEngine/shaders/rtreflectionLIB.hlsl index eaf167a44..b2259972c 100644 --- a/WickedEngine/shaders/rtreflectionLIB.hlsl +++ b/WickedEngine/shaders/rtreflectionLIB.hlsl @@ -170,7 +170,7 @@ void RTReflection_ClosestHit(inout RayPayload payload, in BuiltInTriangleInterse lighting.indirect.specular += max(0, EnvironmentReflection_Global(surface)); LightingPart combined_lighting = CombineLighting(surface, lighting); - payload.data.xyz = surface.albedo * combined_lighting.diffuse + combined_lighting.specular + surface.emissiveColor.rgb * surface.emissiveColor.a; + payload.data.xyz = surface.albedo * combined_lighting.diffuse + combined_lighting.specular + surface.emissiveColor; payload.data.w = RayTCurrent(); } diff --git a/WickedEngine/shaders/surfel_raytraceCS.hlsl b/WickedEngine/shaders/surfel_raytraceCS.hlsl index c5996dd57..8418dbc7f 100644 --- a/WickedEngine/shaders/surfel_raytraceCS.hlsl +++ b/WickedEngine/shaders/surfel_raytraceCS.hlsl @@ -315,7 +315,7 @@ void main(uint3 DTid : SV_DispatchThreadID) #endif // SURFEL_ENABLE_INFINITE_BOUNCES hit_result *= surface.albedo; - hit_result += max(0, surface.emissiveColor.rgb * surface.emissiveColor.a); + hit_result += max(0, surface.emissiveColor); result += float4(hit_result, 1); } diff --git a/WickedEngine/shaders/temporalaaCS.hlsl b/WickedEngine/shaders/temporalaaCS.hlsl index 4940effed..ead4e2c9b 100644 --- a/WickedEngine/shaders/temporalaaCS.hlsl +++ b/WickedEngine/shaders/temporalaaCS.hlsl @@ -17,8 +17,8 @@ RWTEXTURE2D(output, float3, 0); static const uint TILE_BORDER = 1; static const uint TILE_SIZE = POSTPROCESS_BLOCKSIZE + TILE_BORDER * 2; -groupshared uint tile_RG[TILE_SIZE*TILE_SIZE]; -groupshared uint tile_B_depth[TILE_SIZE*TILE_SIZE]; +groupshared uint tile_color[TILE_SIZE*TILE_SIZE]; +groupshared float tile_depth[TILE_SIZE*TILE_SIZE]; [numthreads(POSTPROCESS_BLOCKSIZE, POSTPROCESS_BLOCKSIZE, 1)] void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint3 Gid : SV_GroupID, uint groupIndex : SV_GroupIndex) @@ -36,8 +36,8 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint3 const uint2 pixel = tile_upperleft + unflatten2D(t, TILE_SIZE); const float depth = texture_lineardepth[pixel]; const float3 color = input_current[pixel].rgb; - tile_RG[t] = f32tof16(color.r) | (f32tof16(color.g) << 16); - tile_B_depth[t] = f32tof16(color.b) | (f32tof16(depth) << 16); + tile_color[t] = Pack_R11G11B10_FLOAT(color); + tile_depth[t] = depth; } GroupMemoryBarrierWithGroupSync(); @@ -49,10 +49,8 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint3 { const int2 offset = int2(x, y); const uint idx = flatten2D(GTid.xy + TILE_BORDER + offset, TILE_SIZE); - const uint RG = tile_RG[idx]; - const uint B_depth = tile_B_depth[idx]; - const float3 neighbor = float3(f16tof32(RG), f16tof32(RG >> 16), f16tof32(B_depth)); + const float3 neighbor = Unpack_R11G11B10_FLOAT(tile_color[idx]); neighborhoodMin = min(neighborhoodMin, neighbor); neighborhoodMax = max(neighborhoodMax, neighbor); if (x == 0 && y == 0) @@ -60,7 +58,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint3 current = neighbor; } - const float depth = f16tof32(B_depth >> 16); + const float depth = tile_depth[idx]; if (depth < bestDepth) { bestDepth = depth; diff --git a/WickedEngine/wiMath.cpp b/WickedEngine/wiMath.cpp index 79c175bf3..1c83a2a9b 100644 --- a/WickedEngine/wiMath.cpp +++ b/WickedEngine/wiMath.cpp @@ -2,9 +2,6 @@ namespace wiMath { - -#define saturate(x) std::min(std::max(x,0.0f),1.0f) - float TriangleArea(const XMVECTOR& A, const XMVECTOR& B, const XMVECTOR& C) { // Heron's formula: @@ -419,35 +416,4 @@ namespace wiMath return HALTON[idx % arraysize(HALTON)]; } - uint32_t CompressNormal(const XMFLOAT3& normal) - { - uint32_t retval = 0; - - retval |= (uint32_t)((uint8_t)(normal.x * 127.5f + 127.5f) << 0); - retval |= (uint32_t)((uint8_t)(normal.y * 127.5f + 127.5f) << 8); - retval |= (uint32_t)((uint8_t)(normal.z * 127.5f + 127.5f) << 16); - - return retval; - } - uint32_t CompressColor(const XMFLOAT3& color) - { - uint32_t retval = 0; - - retval |= (uint32_t)((uint8_t)(saturate(color.x) * 255.0f) << 0); - retval |= (uint32_t)((uint8_t)(saturate(color.y) * 255.0f) << 8); - retval |= (uint32_t)((uint8_t)(saturate(color.z) * 255.0f) << 16); - - return retval; - } - uint32_t CompressColor(const XMFLOAT4& color) - { - uint32_t retval = 0; - - retval |= (uint32_t)((uint8_t)(saturate(color.x) * 255.0f) << 0); - retval |= (uint32_t)((uint8_t)(saturate(color.y) * 255.0f) << 8); - retval |= (uint32_t)((uint8_t)(saturate(color.z) * 255.0f) << 16); - retval |= (uint32_t)((uint8_t)(saturate(color.w) * 255.0f) << 24); - - return retval; - } } diff --git a/WickedEngine/wiMath.h b/WickedEngine/wiMath.h index 32e38deff..4220d070c 100644 --- a/WickedEngine/wiMath.h +++ b/WickedEngine/wiMath.h @@ -5,6 +5,8 @@ namespace wiMath { + inline float saturate(float x) { return std::min(std::max(x, 0.0f), 1.0f); } + inline float Length(const XMFLOAT2& v) { return sqrtf(v.x*v.x + v.y*v.y); @@ -173,9 +175,52 @@ namespace wiMath // Returns an element of a precomputed halton sequence. Specify which iteration to get with idx >= 0 const XMFLOAT4& GetHaltonSequence(int idx); - uint32_t CompressNormal(const XMFLOAT3& normal); - uint32_t CompressColor(const XMFLOAT3& color); - uint32_t CompressColor(const XMFLOAT4& color); + inline uint32_t CompressNormal(const XMFLOAT3& normal) + { + uint32_t retval = 0; + + retval |= (uint32_t)((uint8_t)(normal.x * 127.5f + 127.5f) << 0); + retval |= (uint32_t)((uint8_t)(normal.y * 127.5f + 127.5f) << 8); + retval |= (uint32_t)((uint8_t)(normal.z * 127.5f + 127.5f) << 16); + + return retval; + } + inline uint32_t CompressColor(const XMFLOAT3& color) + { + uint32_t retval = 0; + + retval |= (uint32_t)((uint8_t)(saturate(color.x) * 255.0f) << 0); + retval |= (uint32_t)((uint8_t)(saturate(color.y) * 255.0f) << 8); + retval |= (uint32_t)((uint8_t)(saturate(color.z) * 255.0f) << 16); + + return retval; + } + inline uint32_t CompressColor(const XMFLOAT4& color) + { + uint32_t retval = 0; + + retval |= (uint32_t)((uint8_t)(saturate(color.x) * 255.0f) << 0); + retval |= (uint32_t)((uint8_t)(saturate(color.y) * 255.0f) << 8); + retval |= (uint32_t)((uint8_t)(saturate(color.z) * 255.0f) << 16); + retval |= (uint32_t)((uint8_t)(saturate(color.w) * 255.0f) << 24); + + return retval; + } + inline XMFLOAT3 Unpack_R11G11B10_FLOAT(uint32_t value) + { + XMFLOAT3PK pk; + pk.v = value; + XMVECTOR V = XMLoadFloat3PK(&pk); + XMFLOAT3 result; + XMStoreFloat3(&result, V); + return result; + } + inline uint32_t Pack_R11G11B10_FLOAT(const XMFLOAT3& color) + { + XMFLOAT3PK pk; + XMStoreFloat3PK(&pk, XMLoadFloat3(&color)); + return pk.v; + } diff --git a/WickedEngine/wiScene.cpp b/WickedEngine/wiScene.cpp index 3f8fe1f87..733a894c5 100644 --- a/WickedEngine/wiScene.cpp +++ b/WickedEngine/wiScene.cpp @@ -231,8 +231,8 @@ namespace wiScene void MaterialComponent::WriteShaderMaterial(ShaderMaterial* dest) const { dest->baseColor = baseColor; - dest->specularColor = specularColor; - dest->emissiveColor = emissiveColor; + dest->emissive_r11g11b10 = wiMath::Pack_R11G11B10_FLOAT(XMFLOAT3(emissiveColor.x * emissiveColor.w, emissiveColor.y * emissiveColor.w, emissiveColor.z * emissiveColor.w)); + dest->specular_r11g11b10 = wiMath::Pack_R11G11B10_FLOAT(XMFLOAT3(specularColor.x * specularColor.w, specularColor.y * specularColor.w, specularColor.z * specularColor.w)); dest->texMulAdd = texMulAdd; dest->roughness = roughness; dest->reflectance = reflectance; @@ -262,7 +262,7 @@ namespace wiScene dest->uvset_clearcoatRoughnessMap = textures[CLEARCOATROUGHNESSMAP].GetUVSet(); dest->uvset_clearcoatNormalMap = textures[CLEARCOATNORMALMAP].GetUVSet(); dest->uvset_specularMap = textures[SPECULARMAP].GetUVSet(); - dest->sheenColor = sheenColor; + dest->sheenColor_r11g11b10 = wiMath::Pack_R11G11B10_FLOAT(XMFLOAT3(sheenColor.x, sheenColor.y, sheenColor.z)); dest->sheenRoughness = sheenRoughness; dest->clearcoat = clearcoat; dest->clearcoatRoughness = clearcoatRoughness; @@ -3185,7 +3185,7 @@ namespace wiScene } inst.uid = entity; inst.color = wiMath::CompressColor(object.color); - inst.emissive = wiMath::CompressColor(object.emissiveColor); + inst.emissive = wiMath::Pack_R11G11B10_FLOAT(XMFLOAT3(object.emissiveColor.x * object.emissiveColor.w, object.emissiveColor.y * object.emissiveColor.w, object.emissiveColor.z * object.emissiveColor.w)); inst.meshIndex = (uint)meshes.GetIndex(object.meshID); if (TLAS_instancesMapped != nullptr) diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 0cee85ce4..831c96dd4 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wiVersion // minor features, major updates, breaking compatibility changes const int minor = 57; // minor bug fixes, alterations, refactors, updates - const int revision = 39; + const int revision = 40; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);