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);